为什么在MenuItem.Icon中这个Image触发绑定不能将MenuItem作为DataSource找到?

时间:2012-03-04 17:57:29

标签: wpf binding menuitem

我已经被困在这一段时间了,我无法理解为什么。基本上,我有一个ContextMenu,其中包含一些MenuItem个对象。我已为Image属性声明了MenuItem.Icon个对象。我将Command个对象绑定到MenuItem并且一切正常...特别是当Command.CanExecute方法返回false时,MenuItem为正确禁用,MenuItem.Header文字显示为灰色。

Image.Opacity被禁用时,我一直在尝试将MenuItem Image的{​​{1}}设置为0.5,这就是问题所在是。出于某种原因,MenuItem中的DataTrigger中的绑定无法找到我尝试绑定的Image.Style。我在下面添加了一个简化的问题示例。

MenuItem

请注意,此示例已简化...我的应用程序中有许多<UserControl.Resources> <Style x:Key="MenuItemIconStyle" TargetType="{x:Type Image}"> <Setter Property="Width" Value="16" /> <Setter Property="Height" Value="16" /> <Style.Triggers> <!--This Binding is not working--> <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}}" Value="False"> <Setter Property="Image.Opacity" Value="0.5" /> </DataTrigger> </Style.Triggers> </Style> <!--This is all working just fine--> <ContextMenu x:Key="ContextMenu" DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"> <MenuItem Header="Open" Command="{Binding Open}" CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu}}"> <MenuItem.Icon> <Image Source="/Application;component/Images/Actions/FolderOpen_16.png" Style="{StaticResource MenuItemIconStyle}" /> </MenuItem.Icon> </MenuItem> </ContextMenu> ... </UserControl.Resources> 个。我知道我可以单独为每个MenuItem命名并使用MenuItem来查找它们,但必须有更好的方法。

非常感谢任何帮助。

更新&gt;&gt;&gt;

感谢punker76的回答,我意识到我需要做的就是将ElementName Image更改为以下内容:

Trigger

我们可以直接绑定到<Trigger Property="IsEnabled" Value="False"> <Setter Property="Opacity" Value="0.5" /> </Trigger> 属性,而不是尝试使用MenuItem.IsEnabled绑定到DataTrigger属性...这是因为Image.IsEnabled的时候变为禁用,它也会禁用其子项。更简单!

1 个答案:

答案 0 :(得分:2)

尝试这个

<Style x:Key="MenuItemIconStyle" TargetType="{x:Type Image}">
  <Setter Property="Width" Value="16" />
  <Setter Property="Height" Value="16" />
  <Style.Triggers>
    <Trigger Property="IsEnabled" Value="False">
      <Setter Property="Opacity" Value="0.5" />
    </Trigger>
  </Style.Triggers>
</Style>

<ContextMenu x:Key="ContextMenu" DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
  <!-- IsEnabled="False" is only for testing (tested with kaxaml) -->    
  <MenuItem IsEnabled="False" Header="Open" Command="{Binding Open}" CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
    <MenuItem.Icon>
      <Image Source="http://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Disambig-dark.svg/25px-Disambig-dark.svg.png"
             Style="{StaticResource MenuItemIconStyle}" />
    </MenuItem.Icon>
  </MenuItem>
</ContextMenu>

修改

这是另一个有效的解决方案(按钮获取DataContext),我找到了这个提示:

  

如何解决WPF ContextMenu中RoutedCommands的执行问题

     

问题是,命令不可能   执行,即使父窗口上的CommandBinding允许它。   原因是,ContextMenus是各自独立的窗口   VisualTree和LogicalTree。原因是CommandManager   在当前焦点范围内搜索CommandBindings。如果   当前焦点范围没有命令绑定,它传输焦点   范围到父焦点范围。最简单的解决方案是最初的   设置父窗口的非空的逻辑焦点。当。。。的时候   CommandManager搜索它找到窗口的父焦点范围   并正确处理CommandBinding。另一种解决方案是   手动将CommandTarget绑定到父ContextMenu。

<Window.Resources>
  <Style x:Key="MenuItemIconStyle"
          TargetType="{x:Type Image}">
    <Setter Property="Width"
            Value="16" />
    <Setter Property="Height"
            Value="16" />
    <Style.Triggers>
      <Trigger Property="IsEnabled"
                Value="False">
        <Setter Property="Opacity"
                Value="0.5" />
      </Trigger>
    </Style.Triggers>
  </Style>
</Window.Resources>

<Grid>

  <Button Content="With ContextMenu"
          DataContext="{Binding ElementName=window, Path=DataContext}">
    <Button.ContextMenu>
      <ContextMenu>
        <MenuItem Header="Enabled"
                  CommandTarget="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget}"
                  Command="{Binding Open}"
                  CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
          <MenuItem.Icon>
            <Image Source="http://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Disambig-dark.svg/25px-Disambig-dark.svg.png"
                    Style="{StaticResource MenuItemIconStyle}" />
          </MenuItem.Icon>
        </MenuItem>
        <MenuItem Header="Disabled"
                  CommandTarget="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget}"
                  Command="{Binding NotOpen}"
                  CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
          <MenuItem.Icon>
            <Image Source="http://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Disambig-dark.svg/25px-Disambig-dark.svg.png"
                    Style="{StaticResource MenuItemIconStyle}" />
          </MenuItem.Icon>
        </MenuItem>
      </ContextMenu>
    </Button.ContextMenu>
  </Button>

</Grid>

背后的代码

public partial class Window11 : Window
{
  public static readonly DependencyProperty OpenProperty =
    DependencyProperty.Register("Open", typeof(ICommand), typeof(Window11), new PropertyMetadata(default(ICommand)));
  public static readonly DependencyProperty NotOpenProperty =
    DependencyProperty.Register("NotOpen", typeof(ICommand), typeof(Window11), new PropertyMetadata(default(ICommand)));

  public ICommand NotOpen {
    get { return (ICommand)this.GetValue(NotOpenProperty); }
    set { this.SetValue(NotOpenProperty, value); }
  }

  public ICommand Open {
    get { return (ICommand)this.GetValue(OpenProperty); }
    set { this.SetValue(OpenProperty, value); }
  }

  public Window11() {
    this.DataContext = this;

    this.InitializeComponent();

    this.Open = new RoutedCommand("Open", typeof(Window11));
    this.CommandBindings.Add(new CommandBinding(this.Open, null, (sender, args) =>
                                                                    {
                                                                      args.CanExecute = true;
                                                                    }));
    this.NotOpen = new RoutedCommand("NotOpen", typeof(Window11));
    this.CommandBindings.Add(new CommandBinding(this.NotOpen, null, (sender, args) =>
                                                                      {
                                                                        args.CanExecute = false;
                                                                      }));
  }
}

希望这有效