【问题标题】:Specify collection in WPF Property setter在 WPF 属性设置器中指定集合
【发布时间】:2014-05-12 20:12:28
【问题描述】:

我有一个图例上的项目的依赖属性。它看起来像:

    public List<LegendItem> LegendItems
    {
        get { return (List<LegendItem>)GetValue(LegendItemsProperty); }
        set { SetValue(LegendItemsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty LegendItemsProperty =
        DependencyProperty.Register("LegendItems", typeof(List<LegendItem>), typeof(TipScoreboard), new PropertyMetadata());

其中LegendItemUserControl

我可以像这样在 XAML 中毫无问题地设置它。

<local:TipScoreboard.LegendItems>
    <local:LegendItem ItemFillBrush="{DynamicResource GreenStatusBrush}"
                      Label="{x:Static res:TipLabels.GoodScan}"/>
    <local:LegendItem ItemFillBrush="{DynamicResource RedStatusBrush}"
                      Label="{x:Static res:TipLabels.BadScan}"/>
</local:TipScoreboard.LegendItems>

但是,当我像这样在 setter 中设置此属性时:

<Setter Property="LegendItems">
     <Setter.Value>
         <local:LegendItem ItemFillBrush="{DynamicResource GreenStatusBrush}"
                           Label="{x:Static res:TipLabels.GoodScan}"/>
         <local:LegendItem ItemFillBrush="{DynamicResource YellowStatusBrush}"
                           Label="{x:Static res:TipLabels.LowConfidence}"/>
      </Setter.Value>
 </Setter>

我得到了二传手的The property "Value" is set more than once.。我不知道如何包装这个或做什么。我试过只用一个 List 包裹它,但这似乎不起作用。

编辑:我尝试创建一个自定义包装的集合,一切都符合并运行,但内容为空白。

public class LegendItemCollection : Collection<LegendItem>
{
}

public LegendItemCollection LegendItems
{
    get { return (LegendItemCollection)GetValue(LegendItemsProperty); }
    set { SetValue(LegendItemsProperty, value); }
}

 public static readonly DependencyProperty LegendItemsProperty =
        DependencyProperty.Register("LegendItems", typeof(LegendItemCollection), typeof(TipScoreboard), new PropertyMetadata());

和 XAML:

<Setter Property="LegendItems">
    <Setter.Value>
       <local:LegendItemCollection>
           <local:LegendItem ItemFillBrush="{DynamicResource GreenStatusBrush}"
                             Label="{x:Static res:TipLabels.GoodScan}"/>
           <local:LegendItem ItemFillBrush="{DynamicResource YellowStatusBrush}"
                             Label="{x:Static res:TipLabels.LowConfidence}"/>
       </local:LegendItemCollection>
    </Setter.Value>
</Setter>

【问题讨论】:

    标签: wpf wpf-controls


    【解决方案1】:

    解决此问题的一种方法是将依赖属性的类型更改为包装 List&lt;LegendItem&gt; 的类:

    public class LegendItemCollection : List<LegendItem>
    {
    }
    
    public LegendItemCollection LegendItems
    {
        get { return (LegendItemCollection)GetValue(LegendItemsProperty); }
        set { SetValue(LegendItemsProperty, value); }
    }
    public static readonly DependencyProperty LegendItemsProperty =
        DependencyProperty.Register("LegendItems", typeof(LegendItemCollection), typeof(TipScoreboard), 
            new PropertyMetadata((sender, args) => {
                System.Diagnostics.Debug.WriteLine("LegendItems property set");
            }));
    

    然后你可以直接在 XAML 中设置属性:

    <Setter Property="LegendItems">
         <Setter.Value>
             <local:LegendItemCollection>
                 <local:LegendItem ItemFillBrush="{DynamicResource GreenStatusBrush}"
                                   Label="{x:Static res:TipLabels.GoodScan}"/>
                 <local:LegendItem ItemFillBrush="{DynamicResource YellowStatusBrush}"
                                   Label="{x:Static res:TipLabels.LowConfidence}"/>
             </local:LegendItemCollection>
          </Setter.Value>
     </Setter>
    

    我相信,理论上,您可以在不需要包装器集合类的情况下实现相同的目标,只需使用 x:TypeArguments 在 XAML 中声明 List&lt;T&gt;。不过,我似乎无法让它工作 (related question)。根据文档,声明看起来像这样:

    <Setter Property="LegendItems">
         <Setter.Value>
             <scg:List xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib"
                       x:TypeArguments="local:LegendItem">
                 <local:LegendItem ItemFillBrush="{DynamicResource GreenStatusBrush}"
                                   Label="{x:Static res:TipLabels.GoodScan}"/>
                 <local:LegendItem ItemFillBrush="{DynamicResource YellowStatusBrush}"
                                   Label="{x:Static res:TipLabels.LowConfidence}"/>
             </scg:List>
          </Setter.Value>
     </Setter>
    

    但是,上面的代码给了我一个编译器错误:

    命名空间“clr-namespace:System.Collections.Generic;assembly=mscorlib”中不存在名称“List”


    编辑

    根据 cmets,在 OP 中编辑的解决方案是使用 SetCurrentValue 而不是直接分配属性(后者由于 dependency property value precedence 而消除了属性上的任何样式):

    this.SetCurrentValue(LegendItemsProperty, new LegendItemCollection());
    

    【讨论】:

    • 我尝试了自定义包装器,它运行但似乎不起作用。只是显示为空白。在尝试 List 方法时,我遇到了与您相同的错误。
    • @BrianTriplett 你确定你在所有 3 个位置都将 DP 类型更新为“LegendItemCollection”吗?这是我现在唯一能想到的。您还可以在输出窗口中检查绑定错误...
    • 我确实检查过,它们都设置正确。初始化呢?在视图的构造函数中,我有 this.LegendItems = new LegendItemCollection(); InitializeComponent();
    • @BrianTriplett 为什么要在视图中实例化 LegendItems?对于您的代码 sn-p &lt;Setter Property="LegendItems"&gt;,我的印象是您想使用样式设置 LegendItems(或者它是触发器?)
    • 就是这样!如果我直接在 XAML 中设置它就可以了,但是一旦我把它放在一个样式中它就不起作用了。这是因为价值优先。有关SetCurrentValue 的解决方案,请参阅stackoverflow.com/questions/4231478/…。如果您想添加您的答案,我会接受,因为您非常乐于助人。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    相关资源
    最近更新 更多