XamlWriter.Save() 未序列化 DependencyProperties

bug*_*d87 5 c# wpf xaml uielementcollection xamlwriter

考虑来自我的 UserControl 的以下 XAML:

<TextBlock Text="HelloWorld" Loaded="TextBlock_OnLoaded" />
Run Code Online (Sandbox Code Playgroud)

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

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

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

<TextBlock Text="HelloWorld" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
Run Code Online (Sandbox Code Playgroud)

现在考虑这个替代 XAML:

<ListBox ItemsSource="{Binding SomeCollection}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="HelloWorld" Loaded="TextBlock_OnLoaded" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

现在,当加载 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" />
......
Run Code Online (Sandbox Code Playgroud)

请注意 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);
}
Run Code Online (Sandbox Code Playgroud)

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

<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" />
......
Run Code Online (Sandbox Code Playgroud)

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

这篇博客文章解释了“......如果该属性由 DependencyProperty 支持......该属性仅在实际设置时才会写入。”

看来 TextProperty 确实是在第一个使用示例中设置的,但在第二个使用 ListBox 和 DataTemplate 的示例中没有设置。

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

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

Nex*_*ine 2

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

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

textBlock.Text = textBlock.Text;
Run Code Online (Sandbox Code Playgroud)

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

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

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