2

我知道标准的 XamlWriter 不会持久绑定。但真正令人讨厌的是绑定持有的当前值也没有被序列化。

我目前 - 真的很愚蠢 - 解决方法是创建一个 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); }
    }
}

如果您运行此测试应用程序并将光标移到不同的文本框上,您会发现序列化硬编码和直接绑定的值没有问题。相反,数据模板化绑定不会被序列化。

顺便说一句,使用代码生成的 ItemsSource 而不是 StaticReference 没有区别,只是测试了一下..

4

2 回答 2

0

该值保存XamlWriter。请参阅此页面:

XamlWriter.Save 的序列化限制

对由各种标记扩展格式(例如 StaticResource 或 Binding)产生的对象的公共引用将被序列化过程取消引用。在应用程序运行时创建内存对象时,这些已被取消引用,并且保存逻辑不会重新访问原始 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" />

所以一定有另一个原因为什么它在你的情况下不起作用......你确定你没有任何绑定错误吗?该对象在序列化之前是否具有预期值?

于 2010-07-13T07:48:06.053 回答
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;
}

它不漂亮,但它有效。(并且可以很容易地针对您丢失的任何属性进行修改。)

于 2012-02-15T21:50:30.350 回答