Почему эта привязка триггера Image не может быть найдена в MenuItem.Icon, чтобы найти MenuItem в качестве источника данных? - PullRequest
1 голос
/ 04 марта 2012

Я застрял на этом некоторое время и не могу понять, почему.По сути, у меня есть ContextMenu с некоторыми MenuItem объектами.Я объявил Image объекты для MenuItem.Icon свойств.У меня есть Command объекты, связанные с MenuItem s, и все это работает нормально ... в частности, когда метод Command.CanExecute возвращает false, MenuItem правильно отключен, а текст MenuItem.Header окрашен в серый цвет.out.

Я пытался установить Image.Opacity из MenuItem Image s на 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 s.Я знаю, что могу по отдельности назвать каждый MenuItem и использовать ElementName, чтобы найти их, но должен быть лучший способ.

Любая помощь будет принята с благодарностью.

ОБНОВЛЕНИЕ >>>

Благодаря ответу punker76 я понял, что все, что мне нужно было сделать, это изменить Image Trigger на следующее:

<Trigger Property="IsEnabled" Value="False">
    <Setter Property="Opacity" Value="0.5" />
</Trigger>

Вместо того, чтобы пытаться связать свойство MenuItem.IsEnabled с помощью DataTrigger, мы можем напрямую связать свойство Image.IsEnabled ... это потому, что когда MenuItem становится отключенным, он также отключает своих дочерних элементов.Гораздо проще!

1 Ответ

2 голосов
/ 04 марта 2012

попробуйте это

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

EDIT

вот еще одно решение, которое работает (кнопка получает DataContext) с этим советом, который я нашел:

* * 1010

Как решить проблемы с выполнением RoutedCommands в WPF ContextMenu

Проблема была в том, что команды не могли быть выполняется, даже если 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;
                                                                      }));
  }
}

надеюсь, что это работает

...