1

I understand that interesting things happen to attached properties in datatemplates but this one is very strange.

I have a behavior with a dependency property on it, the property is type List<DataStatePair>

[System.Windows.Markup.ContentProperty("StateDefinitions")]
public class MultiDataStateBehavior: StateBehaviourBase
{
    public List<DataStatePair> StateDefinitions
    {
        get { return (List<DataStatePair>)GetValue(StateDefinitionsProperty); }
        set { SetValue(StateDefinitionsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for StateDefinitions.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty StateDefinitionsProperty =
        DependencyProperty.Register("StateDefinitions", typeof(List<DataStatePair>), typeof(MultiDataStateBehavior), new PropertyMetadata(new List<DataStatePair>()));
}

As you can see, I've marked it as the content property. The XAML looks like this:

<DataTemplate>
<!-- VISUAL STATES  OMITTED FOR BREVITY-->
<Grid x:Name="grid" Background="Transparent" ContextMenu="{StaticResource ContextMenu_ToolMenu}">
                    <i:Interaction.Behaviors>
                        <ext:MultiDataStateBehavior Binding="{Binding Type}">
                                <ext:DataStatePair State="None" Value="{x:Null}"/>
                                <ext:DataStatePair State="Gauge" Value="{x:Static jcm:ToolType.Gauge}"/>
                                <ext:DataStatePair State="Repeater" Value="{x:Static jcm:ToolType.Gauge}"/>
                        </ext:MultiDataStateBehavior>
                    </i:Interaction.Behaviors>
</Grid>
</DataTemplate>

The problem? 3 DataStatePair instances are added for each use of the datatemplate. I use the template 32 times in my app and get 96 DataStatePair instances in total. Grizzly! I understand how this is possible. The Behavior is static for the datatemplate but the DataStatePair instances are not and a List can be added to.

If change the dependency property to an IEnumerable everything breaks - it will not compile. If I set the property explicitly with an x:Array in XAML, everything works as expected - I only ever get 3 states. XAML below;

<i:Interaction.Behaviors>
                        <ext:MultiDataStateBehavior Binding="{Binding Type}" UseTransitionsOnLoad="True">
                            <ext:MultiDataStateBehavior.StateDefinitions>
                                <x:Array Type="{x:Type ext:DataStatePair}">
                                    <ext:DataStatePair State="None" Value="{x:Null}"/>
                                    <ext:DataStatePair State="Gauge" Value="{x:Static jcm:ToolType.Gauge}"/>
                                    <ext:DataStatePair State="Repeater" Value="{x:Static jcm:ToolType.Gauge}"/>
                                </x:Array>
                            </ext:MultiDataStateBehavior.StateDefinitions>
                        </ext:MultiDataStateBehavior>
</i:Interaction.Behaviors>

Does anyone know why this is and what the most elegant solution is. I can imagine a Microsoft implementation would not make you use x:Array.

EDIT : The x:Array solution breaks the blend designer.

XamlParseException: Add value to collection of type 'System.Collections.Generic.IEnumerable(SSW.WPFExtensions.DataStatePair)' threw an exception.

EDIT : Removing the [System.Windows.Markup.ContentProperty("StateDefinitions")] attribute definition works great. I dont understand what is going on!

WPF, what are you doing. WPF, STAHP

4

1 回答 1

1

潜在的解决方案......这是一个doozy。

Microsoft在此处提供有关创建作为集合的依赖项属性的指南 。

本文档指定您永远不应将属性的默认值声明为实例,而是在所属类的构造函数中初始化集合并设置依赖属性。例如。

public Aquarium() : base()
{
    SetValue(AquariumContentsPropertyKey, new List<FrameworkElement>()); 
}

...[the] 单个列表默认值对 Aquarium 的所有实例共享。如果您运行以下测试代码,该代码旨在展示如何实例化两个单独的 Aquarium 实例并为每个实例添加一个不同的 Fish,您会看到一个令人惊讶的结果:

至于我的设计时例外。同样的问题期望 newDataStatePair[0]是不可变的,可怕的错误报告。

结论 - 微软的某个人正在以我为代价轻笑。

于 2013-08-19T10:21:56.360 回答