Bind trigger to item in parent collection

I have a control with the dependency property "IsLightOnVal" a witch is defined as follows:

// 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>())); 

In my collection, each element contains a string (state) and bool (value)

My management style is defined in ControlTemplate.

I want to add a trigger, for example, when the first item in my collection is right, and then do something.

I tried this:

 <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> 

I also tried using a simple trigger instead of a DataTrigger, but it does not support binding ...

Can someone help me?

+4
source share
3 answers

You have a number of problems. Firstly, you are using RelativeSource TemplatedParent , but this is not binding to the element inside the template, so you should use Self . This can be done relatively easily:

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

Secondly, you have defined this property as a CLR property (with its own repository) and as DependencyProperty. If the property is defined as DP, then the system expects you to use DP to store the value. In code, you never use the SetValue method to actually store the collection instance in the DependencyObject backup storage. Therefore, there are several ways to fix this:

1) Remove 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>() ) ); 

Since this is not DP, although you cannot install it in the setter, bind it to some property on your virtual machine, etc., so this is probably not the best option.

2) Store the value in DP as well as the local variable:

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

I personally donโ€™t like it. Or, more specifically, I believe that his bad practice lazily distributes your own property in a getter. This will set a local value for the object, which can overwrite the actual value if someone really set it with a lower priority (for example, an instance of this parameter was defined in the template and the property set / associated with it). And if you plan to support development time, this can ruin the designer. If you go along this route, then really you should add PropertyChangedHandler to your DP definition and do not forget to set the m_IsLightOnVal member variable in it, otherwise you will exit synchronization if the value is set via DP (for example, someone including the WPF structure - uses SetValue to set the property value).

3) Use only GetValue / SetValue

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

I would recommend this approach. Yes, this means that anyone who wants to set a property must define an instance of the collection, but I think that it is preferable to the problems that you could hit if you set your own DP value. Note that if you go through this route, you may need to define a non-generic generic class that will be derived from the ObservableCollection so that someone can define an instance of the collection class in xaml, although if you expect this to be just related may not be a problem. From a comment on another answer, although it seems that it can be installed in haml.

+4
source

At the moment, your trigger never starts, since the ObservableCollection does not support the modified notifiaction property of the contained elements.

You can try to implement the ObservableCollection specialization, which supports ChangeNotification, as shown here, for example, the ObservableCollection Extension

However, it may be easier to keep the first value of your ObservableCollection in your ViewModel / Code behind and set it as the trigger target.

+4
source

Found:

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

All Articles