将命令绑定到视图模型与 ItemsSource from a StaticResource

本文关键字:ItemsSource from StaticResource 模型 命令 绑定 视图 | 更新日期: 2023-09-27 18:36:57

我正在尝试向MenuItem添加ItemsSource,同时将命令绑定到我的视图模型(我的窗口的数据上下文)。到目前为止,我还没有找到让它工作的方法。在添加项源之前,绑定是正常的。我尝试绑定的集合来自StaticResource。有人可以帮助我解决这个问题吗?

<MenuItem Command="{Binding OpenTeamPage}"
          DisplayMemberPath="Name"
          Header="Teams"
          ItemsSource="{Binding Teams,
                                Source={StaticResource Container}}" />

我尝试使用它及其变体,但没有运气:

Command="{Binding OpenTeamPage,
                  RelativeSource={RelativeSource AncestorType=Window},
                  Mode=Default}"

如果有人能告诉我如何使用这个ItemsSource,同时仍然将我的命令绑定到我的ViewModel,我将不胜感激。我想我可以将命令放在我的团队模型中,但如果可能的话,我想避免这种情况。

编辑:为了澄清我的问题,在 ItemsSource 就位的情况下,ViewModel 中的命令根本不会触发。如果没有 ItemsSource,该命令将触发。我希望能够拥有项目源并且仍然能够触发命令。

编辑:

public class GameContainer
{
    static GameContainer()
    {
        Teams = new ObservableCollection<Team>();
    }
    public static ObservableCollection<Team> Teams { get; set; } 
}

在 App.xaml 中:

<data:GameContainer x:Key="Container" />

集合在程序启动时填充。

一旦我完成这项工作,我的目标是将所选团队传递给视图模型,希望通过 CommandParameter,并显示有关所选团队的信息。

编辑:我在原始帖子中弄错了。来自视图模型的绑定集合也不起作用。

将命令绑定到视图模型与 ItemsSource from a StaticResource

这是

MenuItem的行为,具有子MenuItem的项目不会触发Command,也不应该,因为它没有意义。但是,如果您仍然想在父项单击时触发命令,则有两个选项

  1. 您可以使用菜单项上的交互性触发器来调用鼠标按下事件上的命令,例如

    <MenuItem 
          DisplayMemberPath="Name"
          Header="Teams"
          ItemsSource="{Binding Teams,
                                Source={StaticResource Container}}">
      <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseDown">
            <cmd:EventToCommand Command="{Binding OpenTeamPage}" />
        </i:EventTrigger>
      </i:Interaction.Triggers>
    </MenuItem>
    
  2. 您可以为命令定义附加属性并定义菜单项鼠标向下行为,例如

     public static class MouseCommandBehavior
     {
          public static readonly DependencyProperty MouseDownCommandProperty =
                        DependencyProperty.RegisterAttached("MouseDownCommand",
                        typeof(ICommand),
                        typeof(MouseCommandBehavior),
                        new FrameworkPropertyMetadata(null, (obj, e) => OnMouseCommandChanged(obj, (ICommand)e.NewValue, false)));
     public static ICommand GetMouseDownCommand(DependencyObject d)
     {
             return (ICommand)d.GetValue(MouseDownCommandProperty);
     }
      public static void SetMouseDownCommand(DependencyObject d, ICommand value)
     {
         d.SetValue(MouseDownCommandProperty, value);
     }
     private static void OnMouseCommandChanged(DependencyObject d, ICommand command)
     {
           if (command == null) return;
            var element = (FrameworkElement)d;
            element.PreviewMouseDown += (obj, e) => command.Execute(null);
      }
     }
    }
    

您可以在菜单项上设置此属性值

<MenuItem local:MouseCommandBehavior.MouseDownCommand="{Binding OpenTeamPage}"
      DisplayMemberPath="Name"
      Header="Teams"
      ItemsSource="{Binding Teams,
      Source={StaticResource Container}}">

如果MenuItem不是叶节点,则不会执行其命令。只有作为叶子的菜单项(没有子项)才会执行命令。

这可能是由于约定 - 当您单击具有子项的项目时,您会立即显示子项,否则从鼠标悬停到显示子项会有延迟。

尽管(从UX的角度来看)对父级使用命令可能是一个坏主意,但有可能:

<MenuItem DisplayMemberPath="Name"
          Header="{Binding OpenTeamPage}"
          ItemsSource="{Binding Teams, Source={StaticResource Container}}" >
    <MenuItem.HeaderTemplate>
        <DataTemplate>
            <!--Probably need to make this button transparent-->
            <Button Content="Teams"
                    Command="{Binding }"/>
        </DataTemplate>
    </MenuItem.HeaderTemplate>
    <!--This style is for the children to fire the same command as the parent-->
    <MenuItem.ItemContainerStyle>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Command"
                    Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}, Path=Header}"/>
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

根据您的设计,您可能需要将按钮样式设置为透明。