WPF オブジェクトのクローンを作成するにはどうすればよいですか?
質問
データバインディングを保持しながら WPF オブジェクトをディープ クローン作成する方法の良い例を持っている人はいますか?
マークされた答えは最初の部分です。
2 番目の部分では、ExpressionConverter を作成し、それをシリアル化プロセスに挿入する必要があります。詳細は次のとおりです。
http://www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx?fid=1428301&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2801571
解決
私が行った最も簡単な方法は、XamlWriter を使用して WPF オブジェクトを文字列として保存することです。Save メソッドは、論理ツリー内のオブジェクトとそのすべての子をシリアル化します。これで、新しいオブジェクトを作成し、XamlReader でそれを読み込むことができます。
元:オブジェクトを xaml に書き込みます (オブジェクトが Grid コントロールだったとしましょう)。
string gridXaml = XamlWriter.Save(myGrid);
それを新しいオブジェクトにロードします。
StringReader stringReader = new StringReader(gridXaml);
XmlReader xmlReader = XmlReader.Create(stringReader);
Grid newGrid = (Grid)XamlReader.Load(xmlReader);
他のヒント
.NET 4.0 では、新しい xaml シリアル化スタックにより、これがはるかに簡単になります。
var sb = new StringBuilder();
var writer = XmlWriter.Create(sb, new XmlWriterSettings
{
Indent = true,
ConformanceLevel = ConformanceLevel.Fragment,
OmitXmlDeclaration = true,
NamespaceHandling = NamespaceHandling.OmitDuplicates,
});
var mgr = new XamlDesignerSerializationManager(writer);
// HERE BE MAGIC!!!
mgr.XamlWriterMode = XamlWriterMode.Expression;
// THERE WERE MAGIC!!!
System.Windows.Markup.XamlWriter.Save(this, mgr);
return sb.ToString();
ここには素晴らしい答えがいくつかあります。非常に役立ちます。バインディング情報をコピーするためにさまざまなアプローチを試しました。 http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programmatically/ しかし、ここの情報はインターネット上で最も優れています。
InvalidoperationExceptionを扱うための再利用可能な拡張方法を作成しました。「使用後、バインディングは変更できません。」私のシナリオでは、誰かが書いたコードを維持していました。DXGRIDフレームワークの主要なアップグレードの後、それは機能しなくなりました。以下は私の問題を完全に解決しました。オブジェクトを返すコードの部分はもっと良くなる可能性があるので、後で再ファクタリングします。
/// <summary>
/// Extension methods for the WPF Binding class.
/// </summary>
public static class BindingExtensions
{
public static BindingBase CloneViaXamlSerialization(this BindingBase binding)
{
var sb = new StringBuilder();
var writer = XmlWriter.Create(sb, new XmlWriterSettings
{
Indent = true,
ConformanceLevel = ConformanceLevel.Fragment,
OmitXmlDeclaration = true,
NamespaceHandling = NamespaceHandling.OmitDuplicates,
});
var mgr = new XamlDesignerSerializationManager(writer);
// HERE BE MAGIC!!!
mgr.XamlWriterMode = XamlWriterMode.Expression;
// THERE WERE MAGIC!!!
System.Windows.Markup.XamlWriter.Save(binding, mgr);
StringReader stringReader = new StringReader(sb.ToString());
XmlReader xmlReader = XmlReader.Create(stringReader);
object newBinding = (object)XamlReader.Load(xmlReader);
if (newBinding == null)
{
throw new ArgumentNullException("Binding could not be cloned via Xaml Serialization Stack.");
}
if (newBinding is Binding)
{
return (Binding)newBinding;
}
else if (newBinding is MultiBinding)
{
return (MultiBinding)newBinding;
}
else if (newBinding is PriorityBinding)
{
return (PriorityBinding)newBinding;
}
else
{
throw new InvalidOperationException("Binding could not be cast.");
}
}
}
どうでしょうか:
public static T DeepClone<T>(T from)
{
using (MemoryStream s = new MemoryStream())
{
BinaryFormatter f = new BinaryFormatter();
f.Serialize(s, from);
s.Position = 0;
object clone = f.Deserialize(s);
return (T)clone;
}
}
もちろん、これはあらゆるオブジェクトのディープ クローンを作成するため、街中で最も速いソリューションではないかもしれませんが、メンテナンスは最小限で済みます...:)