从XAML中的显式可枚举绑定到父级的属性

时间:2015-10-21 19:56:00

标签: wpf xaml

不确定这是否可行。我有一个可观察的集合" OptionsList"对于具有"名称"的简单对象;和#34; IsEnabled"属性。

这是一个看起来像

的菜单
Configuration
  |--Option1
  |--Option2
  |--Option3
       |--Enabled

第一个子菜单" Option1,Option2,Option3"正确绑定但后来我尝试从第一个子菜单访问这些项并绑定到他们的数据上下文但我似乎无法通过RelativeSource访问它们出于某种原因。

<MenuItem Header="Configuration">
  <MenuItem Header="Service" ItemsSource="{Binding OptionsList}">
    <MenuItem.ItemContainerStyle>
      <Style TargetType="MenuItem">
        <Setter Property="Header" Value="{Binding Name}"/>
        <Setter Property="ItemsSource">
          <Setter.Value>
            <x:Array Type="MenuItem">
              <MenuItem Header="Enabled" IsCheckable="True" 
                        DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}, Path=DataContext}"
                        IsChecked="{Binding Path=IsEnabled}"/>
             </x:Array>
           </Setter.Value>
         </Setter>
       </Style>
     </MenuItem.ItemContainerStyle>
   </MenuItem>
 </MenuItem>

2 个答案:

答案 0 :(得分:1)

IsChecked与错误的路径绑定。这里Binding的隐式源已经是DataContext,它绑定到父MenuItem的DataContext。因此,使用路径DataContext.IsEnabled - 它实际上会查找DataContext.DataContext.IsEnabled - 当然无法解决。

您只需删除DataContext.

即可
IsChecked="{Binding IsEnabled}"

另一个问题是DataContext将自动向下流动子MenuItem,因此您不需要为内部MenuItem设置DataContext,这实际上不起作用(I&#39 ;我试过它,不知何故RelativeSource绑定不起作用 - 它不是某种断开连接的可视化树 - 因为DataContext是空的OK - 所以在这种情况下很奇怪):

<MenuItem Header="Enabled" IsCheckable="True" IsChecked="{Binding IsEnabled}"/>

这是一种更安全的方法,我们使用HierarchicalDataTemplate。请注意,ItemsSource设置为包含1个元素的虚拟数组。在ItemTemplate内,我们将使用Binding前往IsChecked属性的父元素

<MenuItem Header="Service" ItemsSource="{Binding OptionsList}">
   <MenuItem.ItemContainerStyle>
       <Style TargetType="MenuItem">
           <Setter Property="ItemTemplate">
               <Setter.Value>
                  <HierarchicalDataTemplate>
                     <HierarchicalDataTemplate.ItemsSource>
                         <x:Array Type="{x:Type sys:Int32}">
                             <sys:Int32>0</sys:Int32>
                         </x:Array>
                     </HierarchicalDataTemplate.ItemsSource>
                     <HierarchicalDataTemplate.ItemTemplate>
                          <DataTemplate>
                              <TextBlock Text="Enabled"/>
                          </DataTemplate>
                     </HierarchicalDataTemplate.ItemTemplate>
                     <HierarchicalDataTemplate.ItemContainerStyle>
                         <Style TargetType="MenuItem">
                            <Setter Property="IsCheckable" Value="True"/>
                            <Setter Property="IsChecked" 
                                    Value="{Binding DataContext.IsEnabled, RelativeSource={RelativeSource AncestorType=MenuItem}}"/>
                         </Style>
                     </HierarchicalDataTemplate.ItemContainerStyle>
                     <TextBlock Text="{Binding Name}"/>                       
                  </HierarchicalDataTemplate>
               </Setter.Value>
           </Setter>
       </Style>
   </MenuItem.ItemContainerStyle>

答案 1 :(得分:1)

我认为项目显示无法正常工作,因为在WPF中重复使用了MenuItem(不确定这是否是MenuItem中的错误)。玩x:Shared="False"并没有解决它。

有一种不同的方法可以实现您的目标:

  1. 创建一个辅助类,它是您的选项类的子级,并提供此帮助程序的一个实例作为该选项的子级。
  2. 将XAML绑定到此帮助程序类
  3. 以下是一些代码,详细说明了如何操作:

    <强> XAML:

    <MenuItem Header="Service" ItemsSource="{Binding OptionsList}">
      <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
          <Setter Property="Header" Value="{Binding Name}" />
          <Setter Property="ItemsSource" Value="{Binding ToggleItem}" />
          <Setter Property="ItemContainerStyle">
            <Setter.Value>
              <Style TargetType="MenuItem">
                <Setter Property="Header" Value="{Binding Name}" />
                <Setter Property="IsCheckable" Value="True" />
                <Setter Property="IsChecked" Value="{Binding IsEnabled}" />
              </Style>
            </Setter.Value>
          </Setter>
        </Style>
      </MenuItem.ItemContainerStyle>
    </MenuItem>
    

    <强> C#

    public class OptionHelper
    {
      private readonly Option owner;
    
      public OptionHelper(Option owner)
      {
        this.owner = owner;
      }
    
      public bool IsEnabled
      {
        get { return this.owner.IsEnabled; }
        set { this.owner.IsEnabled = value; }
      }
    }
    
    public class Option : INotifyPropertyChanged
    {
      public ObservableCollection<OptionHelper> ToggleItem { get; private set;  }
    
      public Option(string name, bool isEnabled)
      {
        this.ToggleItem = new ObservableCollection<OptionHelper>() { new OptionHelper(this) };
        this.name = name;
        this.isEnabled = isEnabled;
      }
    
      // your code here...
    }
    

    我知道这不是一个完美的解决方案,但它确实有效......如果有人找到没有帮助者的解决方案,那就太棒了。