2012-07-23 174 views
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>())); 

在我的收藏,每个元素包含一个字符串(州)和布尔(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,但它似乎不支持绑定...

有人能帮助我吗?

回答

4

你有一些问题存在。首先,您正在使用RelativeSourceTemplatedParent但这不是绑定应用于模板中的元素,因此您应该使用。这样可以固定相对容易:

<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虽然你将无法将其设置在一个二传手,将其绑定到虚拟机上的一些属性等等,所以这可能不是最好的选择。

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

我个人不喜欢这个选项。或者更具体地说,我认为它的糟糕做法是在吸气人员中懒散地分配你自己的财产。如果某人实际设置了较低的优先级(例如,在模板中定义了一个实例并且在该模板中定义了属性集/绑定),则会在该对象上设置一个本地值,该值可能会覆盖实际值。如果你计划在设计时支持这可能会弄乱设计师。如果你确实走这条路线,那么你真的应该在你的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中定义集合类的实例,但如果您希望这种绑定仅限于此,可能不是问题。从另一个回复的评论,尽管它听起来像它可能被设置在XAML。

4

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

你可以尝试实施的ObservableCollection专业化支持ChangeNotification这里看到例如Extending ObservableCollection

但是,它可能是更容易的ObservableCollection的第一个值存储在您的视图模型/代码后面,将其设置为触发器的目标。

+0

谢谢,但我只是写了一个例子,我们的图形设计师将使用这个集合来添加他所需要的项目,然后他需要将它们绑定到图形上。因此,他可以通过更改集合中的值并保持始终相同的样式来重复使用相同样式的多个项目。 – mlemay 2012-07-23 14:41:25

1

发现:

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