ComboBox 選択のイベント ハンドラーでディープ コピーを実行する必要があります 選択が変更されまし
た DeepCopy は失敗します
しかし、まったく同じ DeepCopy が ctor とボタン クリックのイベント ハンドラーで成功します
2 台のマシンでこれを再現しまし
た ハンドラーまたはディープ コピーを変更したいと思っていますが、私はComboBox SelectionChanged のイベント ハンドラーでかなり必要です。
コードでこれが失敗するのを探します
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.ComponentModel;
namespace DeepCopy
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private List<TestClass> testClassList = new List<TestClass>();
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
try
{
TestClass tca = new TestClass();
tca.Prop1 = "Tcaa";
TestClass tcb = DeepClone<TestClass>(tca);
tca.Prop1 = "TcaNew1";
System.Diagnostics.Debug.WriteLine(tca.Prop1);
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
tcb.Prop1 = "sdf1";
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
}
catch (Exception Ex)
{
System.Diagnostics.Debug.WriteLine(Ex.Message);
}
TestClass tc = new TestClass();
tc.Prop1 = "tc1";
testClassList.Add(tc);
tc = new TestClass();
tc.Prop1 = "tc2";
testClassList.Add(tc);
foreach (TestClass tcx in TestClassList)
{
try
{
// this does not fail
TestClass tcb = DeepClone<TestClass>(tcx);
System.Diagnostics.Debug.WriteLine(tc.Prop1);
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
tc.Prop1 += "ctorA";
System.Diagnostics.Debug.WriteLine(tc.Prop1);
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
tcb.Prop1 += "ctorB";
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
public List<TestClass> TestClassList { get { return testClassList; } }
[Serializable()]
public abstract class TestAstract : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public abstract string Prop1 { get; set; }
}
[Serializable()]
public class TestClass : TestAstract
{
private string prop1;
public override string Prop1
{
get { return prop1; }
set
{
if (prop1 == value) return;
prop1 = value;
NotifyPropertyChanged("Prop1");
}
}
public TestClass() { }
}
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
private void clickDeepCopy(object sender, RoutedEventArgs e)
{
foreach (TestClass tc in TestClassList)
{
try
{
// this does not fail
TestClass tcb = DeepClone<TestClass>(tc);
System.Diagnostics.Debug.WriteLine(tc.Prop1);
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
tc.Prop1 += "clickA";
System.Diagnostics.Debug.WriteLine(tc.Prop1);
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
tcb.Prop1 += "clickB";
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
private void cbSelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (TestClass tc in TestClassList)
{
try
{
// this fails
TestClass tcb = DeepClone<TestClass>(tc);
// A first chance exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
// Type 'System.ComponentModel.PropertyChangedEventManager' in Assembly 'WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable.
// A first chance exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
System.Diagnostics.Debug.WriteLine(tc.Prop1);
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
tc.Prop1 += "cbceA";
System.Diagnostics.Debug.WriteLine(tc.Prop1);
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
tcb.Prop1 = "cbceB";
System.Diagnostics.Debug.WriteLine(tcb.Prop1);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
}
}
<Window x:Class="DeepCopy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="DeepCopy" Click="clickDeepCopy" />
<ComboBox Grid.Row="1" ItemsSource="{Binding Path=TestClassList}" DisplayMemberPath="Prop1" SelectionChanged="cbSelectionChanged" />
</Grid>
</Window>
もっと興味深い
空の ComboBox SelectionChanged イベント ハンドラーを試してみました 空
の ComboBox SelectionChanged が呼び出された後、ボタン クリックは失敗します
XAML で ComboBox SelectionChanged イベント ハンドラーを削除しました
ボタン クリックは ComboBox SelectionChanged の後で失敗します - イベント ハンドラーがなくても
、ボタン クリックは ComboBox SelectionChanged の前に成功します
XAML で ComboBox SelectionChanged イベント ハンドラーを削除しました XAML
で SelectedIndex = 0 を設定し
ます ボタン クリック イベント ハンドラーは、最初は失敗します
SelectionChanged イベント ハンドラーがなく、ComboBox に SelectedIndex がない場合でも、Get は TestClassList で呼び出されます
。 raw バインディングだけではディープ コピーは壊れません。ComboBox で
アイテムが選択されると、ディープ コピーが壊れます。
私はあなたが疑わしいことを知っていますが、私はこれに数時間を費やしました