4

我有一个控件,它的依赖属性“IsLightOnVal”是这样定义的:

// List of available states for this control
private ObservableCollection<CtlStateBool> m_IsLightOnVal;

[Category("Properties")]
public System.Collections.ObjectModel.ObservableCollection<CtlStateBool> IsLightOnVal
{
    get
    {
        if (m_IsLightOnVal == null)
            m_IsLightOnVal = new System.Collections.ObjectModel.ObservableCollection<CtlStateBool>();
        return m_IsLightOnVal;
    }
    set
    {
        if (m_IsLightOnVal != value)
        {
            m_IsLightOnVal = value;
            OnPropertyChanged("IsLightOnVal");
        }
    }
}

// IsLightOnVal dependency property.
public static readonly DependencyProperty IsLightOnValProperty =
        DependencyProperty.Register("IsLightOnVal", typeof(System.Collections.ObjectModel.ObservableCollection<CtlStateBool>), typeof(ButtonSimple), new UIPropertyMetadata(new System.Collections.ObjectModel.ObservableCollection<CtlStateBool>()));

在我的集合中,每个元素都包含一个字符串(状态)和一个布尔值(值)

我的控件样式在 ControlTemplate 中定义。

我想添加一个触发器,例如,当我的集合中的第一个元素为真时,然后做一些事情。

我试过这个:

<Style x:Key="Btn_RADIO_VHF" TargetType="{x:Type ButtonSimple}">
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type ButtonSimple}">
            <Canvas .../>
            <ControlTemplate.Triggers>
               <DataTrigger Value="True" Binding="{Binding IsLightOnVal[0].Value, RelativeSource={RelativeSource TemplatedParent}}">
                  <Setter Property="Fill" TargetName="pShowTouch" Value="{DynamicResource ShowTouch}"/>
               </DataTrigger>
            </ControlTemplate.Triggers>

我也尝试使用简单的触发器而不是 DataTrigger,但它似乎不支持绑定......

有人能帮我吗?

4

3 回答 3

4

现在你的触发器永远不会被触发,因为ObservableCollection不支持包含元素的属性更改通知。

您可以尝试实现ObservableCollection支持 ChangeNotification 的专业化,如此处所示,例如Extending ObservableCollection

ObservableCollection但是,将您的第一个值存储在 ViewModel/Code 后面并将其设置为触发器的目标可能更容易。

于 2012-07-23T14:38:29.700 回答
4

你那里有很多问题。首先,您使用的是TemplatedParent的RelativeSource ,但这不是应用于模板中元素的绑定,因此您应该使用Self。因此可以相对容易地修复:

<DataTrigger Value="True" Binding="{Binding Path=IsLightOnVal[0].Value, RelativeSource={RelativeSource Self}}">

其次,您已将此属性定义为 CLR 属性(具有自己的后备存储)和 DependencyProperty。如果属性被定义为 DP,那么框架将期望您使用 DP 来存储值。在您的代码中,您永远不会使用 SetValue 方法将集合实例实际存储在 DependencyObject 的后备存储中。所以有很多方法可以解决这个问题:

1) 卸下 DP:

//public static readonly DependencyProperty IsLightOnValProperty =
//        DependencyProperty.Register( "IsLightOnVal", typeof( System.Collections.ObjectModel.ObservableCollection<CtlStateBool> ), typeof( ButtonSimple ), new UIPropertyMetadata( new System.Collections.ObjectModel.ObservableCollection<CtlStateBool>() ) );

由于它不是 DP,尽管您无法在 setter 中设置它,将其绑定到 VM 上的某些属性等,因此这可能不是最佳选择。

2)将值存储在 DP 以及您的局部变量中:

public System.Collections.ObjectModel.ObservableCollection<CtlStateBool> IsLightOnVal
{
    get
    {
        if ( m_IsLightOnVal == null )
            this.SetValue(IsLightOnValProperty, m_IsLightOnVal = new System.Collections.ObjectModel.ObservableCollection<CtlStateBool>());
        return m_IsLightOnVal;
    }
    set
    {
        if ( m_IsLightOnVal != value )
        {
            this.SetValue( IsLightOnValProperty, m_IsLightOnVal = value );
            OnPropertyChanged( "IsLightOnVal" );
        }
    }
}

我个人不喜欢这个选项。或者更具体地说,我认为在吸气剂中懒惰地分配自己的财产是不好的做法。这将在对象上设置一个本地值,如果有人实际上将其设置为较低的优先级,则该值可能会覆盖实际值(例如,在模板中定义了 this 的实例并且在那里设置/绑定了属性)。如果您计划设计时支持,这可能会搞砸设计师。如果你确实走这条路,那么你真的应该在你的 DP 定义中添加一个 PropertyChangedHandler 并确保在那里设置你的 m_IsLightOnVal 成员变量,否则如果通过 DP 设置值(例如某人 - 包括WPF 框架 - 使用 SetValue 设置属性的值)。

3) 只使用 GetValue/SetValue

public System.Collections.ObjectModel.ObservableCollection<CtlStateBool> IsLightOnVal
{
    get { return (System.Collections.ObjectModel.ObservableCollection<CtlStateBool>)this.GetValue(IsLightOnValProperty); }
    set { this.SetValue( IsLightOnValProperty, value ); }
}

我会推荐这种方法。是的,这意味着任何希望设置属性的人都必须定义集合的实例,但我认为这比设置自己的 DP 值可能遇到的问题更可取。请注意,如果您采用这条路线,那么您可能想要定义一个派生自 ObservableCollection 的非泛型集合类,以便有人可以在 xaml 中定义集合类的实例,尽管如果您希望它只是绑定到那么 this可能不是问题。从对其他回复的评论中,虽然听起来它可能是在 xaml 中设置的。

于 2012-10-23T17:12:34.327 回答
1

找到了:

<DataTrigger Binding="{Binding MyCollection[index].Value, RelativeSource={RelativeSource Self}}" Value="True">
    <Setter .../>
</DataTrigger>
于 2012-10-23T17:01:23.543 回答