C# 将触发器绑定到父集合中的元素

C# 将触发器绑定到父集合中的元素,c#,.net,wpf,collections,triggers,C#,.net,Wpf,Collections,Triggers,我有一个控件,其依赖属性“IsLightOnVal”定义如下: // List of available states for this control private ObservableCollection<CtlStateBool> m_IsLightOnVal; [Category("Properties")] public System.Collections.ObjectModel.ObservableCollection<CtlStateBool> IsL

我有一个控件,其依赖属性“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>()));
//此控件的可用状态列表
私人可观测采集m_IsLightOnVal;
[类别(“财产”)]
public System.Collections.ObjectModel.ObservableCollection IsLightOnVal
{
得到
{
if(m_IsLightOnVal==null)
m_IsLightOnVal=new System.Collections.ObjectModel.ObservableCollection();
返回m_IsLightOnVal;
}
设置
{
如果(m_IsLightOnVal!=值)
{
m_IsLightOnVal=值;
OnPropertyChanged(“IsLightOnVal”);
}
}
}
//IsLightOnVal依赖项属性。
公共静态只读从属属性IsLightOnValProperty=
DependencyProperty.Register(“IsLightOnVal”、typeof(System.Collections.ObjectModel.ObservableCollection)、typeof(ButtonSimple)、new UIPropertyMetadata(new System.Collections.ObjectModel.ObservableCollection());
在我的集合中,每个元素都包含一个字符串(State)和一个bool(Value)

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

我想添加一个触发器,例如,当集合中的第一个元素为true时,然后执行一些操作

我试过这个:

<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,但它似乎不支持绑定


有人能帮我吗?

现在您的触发器从未被触发,因为
ObservableCollection
不支持所包含元素的属性更改通知

您可以尝试实现
ObservableCollection
的专门化,该专门化支持ChangeNotification,如这里所示

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

找到它:

<DataTrigger Binding="{Binding MyCollection[index].Value, RelativeSource={RelativeSource Self}}" Value="True">
    <Setter .../>
</DataTrigger>

您遇到了许多问题。首先,您使用的是TemplatedParent的相对资源,但这不是一个绑定,无法应用于模板中的元素,因此您应该使用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>() ) );
//公共静态只读依赖属性IsLightOnValProperty=
//DependencyProperty.Register(“IsLightOnVal”、typeof(System.Collections.ObjectModel.ObservableCollection)、typeof(ButtonSimple)、new UIPropertyMetadata(new System.Collections.ObjectModel.ObservableCollection());
由于它不是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" );
        }
    }
}
public System.Collections.ObjectModel.ObservableCollection IsLightOnVal
{
得到
{
if(m_IsLightOnVal==null)
this.SetValue(IsLightOnValProperty,m_IsLightOnVal=new System.Collections.ObjectModel.ObservableCollection());
返回m_IsLightOnVal;
}
设置
{
如果(m_IsLightOnVal!=值)
{
此.SetValue(IsLightOnValProperty,m_IsLightOnVal=value);
OnPropertyChanged(“IsLightOnVal”);
}
}
}
我个人不喜欢这个选择。或者更具体地说,我认为在getter中懒洋洋地分配自己的属性是一种不好的做法。这将在对象上设置一个本地值,如果有人实际以较低的优先级设置了该值,则该值可能会覆盖实际值(例如,在模板中定义了该值的一个实例,并在其中设置/绑定了属性)。如果您计划在设计时提供支持,这可能会使设计师陷入困境。如果您确实这样做了,那么您确实应该在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 ); }
}
public System.Collections.ObjectModel.ObservableCollection IsLightOnVal
{
获取{return(System.Collections.ObjectModel.observeCollection)this.GetValue(IsLightOnValProperty);}
set{this.SetValue(IsLightOnValProperty,value);}
}

我建议采用这种方法。是的,这意味着任何想要设置属性的人都必须定义集合的实例,但我认为这比设置自己的DP值时可能遇到的问题要好。注意,如果您采用这种方法,那么您可能希望定义一个从ObservaleCollection派生的非泛型集合类,以便有人可以在xaml中定义集合类的一个实例,尽管如果您希望仅将其绑定到该实例,那么这可能不是问题。从另一个回复的评论来看,虽然听起来可能是用xaml设置的。

谢谢,但我刚刚写了一个例子,我们的图形设计师将使用此集合添加他需要的任意多个项目,然后他需要将它们绑定到图形。因此,他可以对许多项目重复使用相同的样式,只需更改集合中的值并始终保持相同的样式即可。