【问题标题】:XamlWriter.Save() is not serializing DependencyPropertiesXamlWriter.Save() 未序列化 DependencyProperties
【发布时间】:2015-01-21 23:48:45
【问题描述】:

考虑我的 UserControl 中的以下 XAML:

<TextBlock Text="HelloWorld" Loaded="TextBlock_OnLoaded" />

以及相关的事件处理程序:

private void TextBlock_OnLoaded(object sender, RoutedEventArgs e)
{
    var xaml = XamlWriter.Save(sender);
    Console.WriteLine(xaml);
}

加载 TextBlock 时,将以下输出写入控制台:

<TextBlock Text="HelloWorld" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />

现在考虑这个替代 XAML:

<ListBox ItemsSource="{Binding SomeCollection}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="HelloWorld" Loaded="TextBlock_OnLoaded" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

现在加载 TextBlock 时,以下输出将写入控制台:

<TextBlock xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
<TextBlock xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
<TextBlock xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
......

请注意,TextProperty 不再被序列化。

如果在调用 XamlWriter.Save() 之前添加了以下 TextProperty 赋值:

private void TextBlock_OnLoaded(object sender, RoutedEventArgs e)
{
    var textBlock = sender as TextBlock;
    if (textBlock != null)
    {
        textBlock.Text = textBlock.Text;
    }

    var xaml = XamlWriter.Save(sender);
    Console.WriteLine(xaml);
}

然后在加载TextBlock时,将以下输出写入Console:

<TextBlock Text="HelloWorld" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
<TextBlock Text="HelloWorld" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
<TextBlock Text="HelloWorld" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
......

请注意,TextProperty 再次被序列化。

这个blog post 解释说“...如果该属性由 DependencyProperty 支持...该属性仅在实际设置时才被写入。”

似乎在第一个用法示例中确实设置了 TextProperty,但在 ListBox 和 DataTemplate 的第二个用法示例中没有设置。

谁能解释为什么会这样,以及如何克服这个障碍?

我的最佳猜测是 XAML 解析器以某种方式在内部设置 TextBlock 状态,而不是在依赖属性上调用 SetValue,但我不确定为什么它只会对 DataTemplate 中的元素执行此操作。

【问题讨论】:

    标签: c# wpf xaml xamlwriter uielementcollection


    【解决方案1】:

    XamlWriter.Save 似乎只序列化本地-set 值。在 XAML 中,值可以来自 multiple levels of sources

    当您直接设置 TextBlock.Text 时,您正在查看“本地值”集(优先级 3)。但是,当您在数据模板中设置它时,您正在设置模板属性(优先级 4)。通过写作

    textBlock.Text = textBlock.Text;
    

    您实际上是将其转换为本地属性集(优先级 3)!

    如果您查看some of the source code involved in XamlWriter.Save,您可以看到 (line 819) 它显式读取属性的本地值。

    不幸的是,我不确定有什么好的解决方法。 XamlWriter 有known limitations。您尝试从XamlDesignerSerializationManager 继承并调用XamlWriter.Save(Object, XamlDesignerSerializationManager) 重载,但它看起来不太有希望。更有可能的是,您必须执行上述操作,或者编写自己的序列化例程(至少 Microsoft 已将其源代码作为指南提供)。

    【讨论】:

    【解决方案2】:

    根据NextInLine 的回答,我想出了以下解决方法:

    public static IEnumerable<DependencyProperty> GetDependencyProperties(this DependencyObject obj)
    {
        var propertyDescriptors = TypeDescriptor.GetProperties(obj, new Attribute[]
        {
            new PropertyFilterAttribute(PropertyFilterOptions.All)
        });
    
        return (from PropertyDescriptor pd in propertyDescriptors
                let dpd = DependencyPropertyDescriptor.FromProperty(pd)
                where dpd != null
                select dpd.DependencyProperty).ToList();
    }
    
    public static IEnumerable<DependencyProperty> GetUpdatedDependencyProperties(this DependencyObject obj)
    {
        return (from property in obj.GetDependencyProperties().Where(x => !x.ReadOnly)
                let metaData = property.GetMetadata(obj.GetType())
                let defaultValue = metaData.DefaultValue
                let currentValue = obj.GetValue(property)
                where currentValue != defaultValue
                select property).ToList();
    }
    

    可以这样使用:

    foreach (var updatedProperty in dependencyObject.GetUpdatedDependencyProperties())
    {
        dependencyObject.SetValue(updatedProperty, dependencyObject.GetValue(updatedProperty));
    }
    

    这将强制 XamlWriter.Save(dependencyObject) 序列化在 XAML 中更新的所有 dependencyObject 属性。

    【讨论】:

    • 很高兴你添加了这个 - 希望它会帮助同一条船上的其他人。
    • GetDependencyProperties 方法究竟从何而来?
    猜你喜欢
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多