2010-07-12 67 views
1

我知道标准XamlWriter不会保留绑定。但真正太臭的是绑定当前的值并没有被序列化。XamlWriter失去约束力 - 好的!但如何保持价值? (ItemsControl)

我当前 - 真的很蠢 - 解决方法是创建一个DependencyProperty fooProperty和属性foo。还有一个属性foo2。 foo的Change-eventhandler然后将其值写入foo2。

你看:愚蠢。

没有人有更好的解决方案吗?

欢呼

- 编辑回应托马斯 -

基本上你是对的。但使用的ItemsControl时,它看起来有点不同:

<Window x:Class="TestApp.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:TestApp" 
    Title="MainWindow" Height="350" Width="525" 
    x:Name="window" 
    > 
<StackPanel> 
    <StackPanel.Resources> 
     <x:Array x:Key="arr1" Type="{x:Type local:TestData}"> 
      <local:TestData Message="itemcontrol binding 1"/> 
      <local:TestData Message="itemcontrol binding 2"/> 
     </x:Array> 
    </StackPanel.Resources> 

    <local:Test Foo="hard coded"/> 
    <local:Test Foo="{Binding Message, ElementName=window}"/> 
    <ItemsControl ItemsSource="{StaticResource arr1}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <local:Test Foo="{Binding Path=Message }"/> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</StackPanel> 

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     Message = "direct binding"; 
    } 

    public static DependencyProperty MessageProperty = DependencyProperty.Register("Message", typeof(string), typeof(MainWindow)); 
    public string Message 
    { 
     get { return (string)GetValue(MessageProperty); } 
     set { SetValue(MessageProperty, value); } 
    } 
} 

public class Test : TextBox 
{ 
    public static DependencyProperty FooProperty = DependencyProperty.Register("Foo", typeof(string), typeof(Test), new PropertyMetadata(OnFooChanged)); 
    private static void OnFooChanged(DependencyObject d, DependencyPropertyChangedEventArgs a) 
    { 
     (d as Test).Text = a.NewValue as String; 
    } 
    public string Foo 
    { 
     get { return (string)GetValue(FooProperty); } 
     set { SetValue(FooProperty, value); } 
    } 

    protected override void OnMouseEnter(MouseEventArgs e) 
    { 
     Debug.Print("foo is really: " + Foo); 
     Debug.Print(XamlWriter.Save(this)); 
    } 
} 

public class TestData : DependencyObject 
{ 
    public static DependencyProperty MessageProperty = DependencyProperty.Register("Message", typeof(string), typeof(TestData)); 
    public string Message 
    { 
     get { return (string)GetValue(MessageProperty); } 
     set { SetValue(MessageProperty, value); } 
    } 
} 

如果运行这个测试应用程序,将光标移动到不同的文本框,你会看到世界上没有问题的串行化硬编码和直接绑定的值。 相反,数据模板绑定不会被序列化。

的方式存在在使用通过代码来代替一个StaticReference产生的ItemsSource没有区别,只是测试的..

回答

0

保持由XamlWriter值。看到这个页面:

Serialization Limitations of XamlWriter.Save

通过各种标记扩展格式,如静态资源或绑定人造物体常见的引用,将被序列化进程解除引用。在应用程序运行时创建内存中的对象时,这些已经被解除引用,并且保存逻辑不会重新访问原始XAML以恢复对序列化输出的此类引用。 这可能会冻结任何数据绑定或资源获取值,使其成为运行时表示上次使用的值,只有有限或间接的能力将此值与本地设置的任何其他值区分开来。当图像存在于项目中时,图像也被序列化为图像的对象引用,而不是原始的源引用,失去了最初引用的任何文件名或URI。即使是在同一页面中声明的资源,也可以被序列化为它们被引用的位置,而不是被保存为资源集合的关键字。

我只是做了一个简单的测试,它为我工作得很好:

public class Test : DependencyObject 
{ 
    public static DependencyProperty FooProperty = DependencyProperty.Register("Foo", typeof(string), typeof(Test)); 

    public string Foo 
    { 
     get { return (string)GetValue(FooProperty); } 
     set { SetValue(FooProperty, value); } 
    } 

    public static DependencyProperty BarProperty = DependencyProperty.Register("Bar", typeof(int), typeof(Test)); 

    public int Bar 
    { 
     get { return (int)GetValue(BarProperty); } 
     set { SetValue(BarProperty, value); } 
    } 
} 

public partial class App : Application 
{ 
    protected override void OnStartup(StartupEventArgs e) 
    { 
     base.OnStartup(e); 

     Message = "Hello"; 
     Answer = 42; 

     var t = new Test(); 

     Binding fooBinding = new Binding("Message") { Source = App.Current }; 
     BindingOperations.SetBinding(t, Test.FooProperty, fooBinding); 

     Binding barBinding = new Binding("Answer") { Source = App.Current }; 
     BindingOperations.SetBinding(t, Test.BarProperty, barBinding); 

     var s = XamlWriter.Save(t); 
     Debug.Print(s); 

    } 

    public string Message { get; set; } 
    public int Answer { get; set; } 
} 

该程序打印以下XAML在调试输出:

<Test Foo="Hello" Bar="42" xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" /> 

所以必须有另之所以不适合你的情况......你确定你没有任何绑定错误吗?在序列化对象之前对象是否具有预期值?

+0

感谢您的回应。看来你是对的..在我的测试床上,我还没有能够重现这个错误。 在我的真实应用程序中有一堆ContentControls。 TabControl,ItemControl,ItemControl。那里的绑定工作通过RelativeSource FindAncestor .. 我会尝试一些更多。看看 – kris 2010-07-13 11:09:25

+0

。 :) – kris 2010-07-13 12:20:37

0

我已经看到了同样的事情,在一个ItemTemplate内结合相同的情况:

<ListBox.ItemTemplate> 
    <DataTemplate> 
     <TextBlock Text="{Binding}"/> 
    </DataTemplate> 
</ListBox.ItemTemplate> 

我能做到的最好的是以下解决方法:

private static UIElement ClonedElement(UIElement original) 
{ 
    var clone = (UIElement)XamlReader.Parse(XamlWriter.Save(original)); 

    if (original is TextBlock) 
     //Handles situation where databinding doesn't clone correctly. 
     ((TextBlock)clone).Text = ((TextBlock)original).Text; 
    return clone; 
} 

它艾因不漂亮,但它的作品。 (它可以很容易地修改为你失去的任何财产。)