5

私の 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 が読み込まれると、次の出力がコンソールに書き込まれます。

<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 が再びシリアル化されていることに注意してください。

このブログ投稿では、「...プロパティが DependencyProperty によってサポートされている場合...プロパティは、実際に設定されている場合にのみ書き込まれます」と説明しています。

最初の使用例では TextProperty が実際に設定されているように見えますが、ListBox と DataTemplate を使用した 2 番目の使用例では設定されていません。

これが事実である理由と、この障害を克服する方法を誰かが説明できますか?

XAML パーサーは、依存関係プロパティで SetValue を呼び出すのではなく、TextBlock の状態を何らかの方法で内部的に設定していると推測されますが、DataTemplate 内の要素に対してのみこれを行う理由がわかりません。

4

2 に答える 2

1

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));
}

これにより、XAML で更新されたすべてのプロパティが強制的XamlWriter.Save(dependencyObject)にシリアル化されます。dependencyObject

于 2015-02-17T23:51:16.033 に答える