XamlWriter.Save() 没有序列化 DependencyProperties



请考虑我的用户控件中的以下 XAML:

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

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

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

加载文本块时,以下输出将写入控制台:

<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 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 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。

这篇博文解释说"...如果该属性由依赖项属性支持...该属性仅在实际设置时才写入。

看起来确实在

第一个用法示例中设置了 TextProperty,但在第二个用法示例中未使用 ListBox 和数据模板设置。

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

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

XamlWriter.Save似乎只序列化本地设置的值。在 XAML 中,值可以来自多个级别的源。

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

textBlock.Text = textBlock.Text;

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

如果查看 XamlWriter.Save 中涉及的一些源代码,可以看到(第 819 行)它显式读取属性的本地值。

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

根据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属性。

相关内容

  • 没有找到相关文章

最新更新