【问题标题】:how to pass data when using MenuItem.ItemContainerStyle使用 MenuItem.ItemContainerStyle 时如何传递数据
【发布时间】:2011-02-20 09:54:19
【问题描述】:

我一直在尝试使用动态ContextMenu 来在其collection of objects 中显示每个对象的名称属性。
这是一个具体的例子,我正在连接到webservice 以提取特定帐户的contactsgroups。所以我将它们作为global variables.i display the contacts in a listboxi want to show on right click of a contact in the listbox the list of groups that it can be added to
为了能够将联系人添加到组中,我需要联系人的 id(我拥有),而我在这里寻找的组的 id 是我的代码。

xmlns:serviceAdmin="clr-namespace:MyWpfApp.serviceAdmin"
......
<ListBox.ContextMenu>
                        <ContextMenu>
                            <MenuItem Header="Refresh" Click="RefreshContact_Click"></MenuItem> 
                            <MenuItem Header="Add New Contact" Click="ContactNew_Click"></MenuItem>
                            <MenuItem Header="Add to Group" Name="groupMenus">
                                //<!--<MenuItem.Resources>
                                  //  <DataTemplate DataType="{x:Type serviceAdmin:groupInfo}" x:Key="groupMenuKey" > 
                                     //   <MenuItem>
                                     //       <TextBlock Text="{Binding name}" />
                                     //   </MenuItem>
                                   // </DataTemplate>

                               // </MenuItem.Resources>-->
                                <MenuItem.ItemContainerStyle>
                                    <Style>
                                        <Setter Property="MenuItem.Header" Value="{Binding name}"/>
                                        <Setter Property="MenuItem.Tag" Value="{Binding id}" />

                                    </Style>
                                </MenuItem.ItemContainerStyle>
                            </MenuItem>
                            <MenuItem Header="Delete Selected" Click="ContactDelete_Click"></MenuItem>
                        </ContextMenu>
                    </ListBox.ContextMenu>
                    ......

在 xaml.cs 上

//this code is in the method that loads the groups
loadedgroup = service.getGroups(session.key, null);
 groupListBox.ItemsSource = loadedgroup;
 groupMenus.ItemsSource = loadedgroup.ToList();

此代码正常显示组的名称,但我需要单击的组的 ID。
如果您注意到我评论了 xaml 代码的一部分。有了它,我可以(轻松)将 id 绑定到标签。但它不起作用,MenuItem.ItemContainerStyle 是一个工作,但后来我迷路了:

问题 1:如何为具有组名称的子菜单的单击事件创建处理程序方法?
问题 2:如何我得到点击的组 id 可以使用吗?

感谢您阅读并在此方面帮助我

【问题讨论】:

标签: c# wpf contextmenu binding


【解决方案1】:

以下是使用数据绑定的示例。子菜单项的数据上下文是 Group 的一个实例。

XAML:

<Window x:Class="MenuTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid Background="Red">
        <Grid.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Menu Item 1"></MenuItem>
                <MenuItem Header="Menu Item 2"></MenuItem>
                <MenuItem Header="SubMenu" ItemsSource="{Binding Path=Groups}"
                          Click="OnGroupMenuItemClick">
                    <MenuItem.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=Name}" />
                        </DataTemplate>
                    </MenuItem.ItemTemplate>
                </MenuItem>
            </ContextMenu>
        </Grid.ContextMenu>
    </Grid>
</Window>

后面的代码:

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace MenuTest
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            Groups = new List<Group>();
            Groups.Add(new Group() { Name = "Group1", Id = 1 });
            Groups.Add(new Group() { Name = "Group2", Id = 2 });
            Groups.Add(new Group() { Name = "Group3", Id = 3 });

            DataContext = this;
        }

        public List<Group> Groups { get; set; }

        private void OnGroupMenuItemClick(object sender, RoutedEventArgs e)
        {
            MenuItem menuItem = e.OriginalSource as MenuItem;
            Group group = menuItem.DataContext as Group;
        }
    }

    public class Group
    {
        public string Name { get; set;}
        public int Id { get; set;}
    }
}

【讨论】:

    【解决方案2】:

    您可以在不使用 Click 事件或任何复杂的操作的情况下执行此操作。

    问题在于您的 Command 有一个 DataContext(ViewModel),而 item 有另一个。因此,有两个选择:要么将命令放在 ItemsSource 中的项目上(更灵活,因为它们可以有不同的命令),要么将 RelativeSource 绑定回视图,通过 view.DataContext 获取 ViewModel,然后从那。这为您节省了将命令传递给所有这些数据项的一些琐碎麻烦。

    请注意,由于我们是通过样式执行此操作的,因此如果我们从所有类似样式的菜单项共有的某个 DataContext 获取命令,我们将绑定相同的命令到每个菜单项。但由于我们是从类似数据项列表中生成项目本身,这可能就是您想要的。如果不是,则在数据项上放置命令。

    如果您的 ItemsSource 中的项目有命令,那是数据项的公共属性,可以很容易地绑定到您的 ItemContainerStyle 中的 MenuItem.Command。更多 C#,更少 XAML。

    这具有额外的好处,即在较大的菜单系统中仅在一个本地化子菜单上同样工作,其他菜单项以传统方式定义。这是部分 MRU 列表实现。你可以很容易地对其他类似的子菜单做同样的事情——或者只需很少的进一步工作,你的整个主菜单树。

    为简单起见,我假设该项目有一个命名空间,该命名空间在 XAML 中定义为 local,并且此 XAML 位于名为 MainWindow 的视图中。

    这两个都已在完整的实现中进行了测试,但以下内容并不完整:为了便于管理 SO 答案,已将其缩减到几乎最低限度,以使 XAML 有意义。我最终使用了RelativeSource AncestorType 版本,因为它更简单一些,我不需要为某些列表项提供不同的命令,但我保留了另一个版本的注释。

    <Window.Resources>
        <!-- ... -->
        <DataTemplate DataType="{x:Type local:MRUListItem}" >
            <Label Content="{Binding HeaderText}" />
        </DataTemplate>
        <!-- ... -->
    </Window.Resources>
    
    <!-- ... -->
    
    <Menu>
        <MenuItem Header="_File">
            <MenuItem Header="_Save File" 
                      Command="{Binding SaveFileCommand}" />
    
            <!-- ... -->
            <!-- etc. -->
            <!-- ... -->
    
            <MenuItem Header="_Recent Files"
                      ItemsSource="{Binding MRUList}">
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="Command" 
                                Value="{Binding FileOpenCommand}" />
                        <Setter Property="CommandParameter" 
                                Value="{Binding FileName}" />
                    </Style>
                </MenuItem.ItemContainerStyle>
            </MenuItem>
    
            <!-- etc. -->
        </MenuItem>
    
        <!-- ... -->
    </Menu>
    

    替代的 RelativeSource 版本,直接从 XAML 中的 ViewModel 获取命令:

    <!--
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="Command" 
                            Value="{Binding RelativeSource={RelativeSource 
                            AncestorType={x:Type local:MainWindow}}, 
                            Path=DataContext.MRUFileOpenCommand}" />
                         <Setter Property="CommandParameter" 
                            Value="{Binding FileName}" />
                    </Style>
                </MenuItem.ItemContainerStyle>
    -->
    

    C#

    public class MRUList : ObservableCollection<MRUListItem>
    {
        //  The owning ViewModel provides us with his FileOpenCommand
        //  initially. 
        public MRUList(ICommand fileOpenCommand)
        {
            FileOpenCommand = fileOpenCommand;
            CollectionChanged += CollectionChangedHandler;
        }
    
        public ICommand FileOpenCommand { get; protected set; }
    
        //  Methods to renumber and prune when items are added, 
        //  remove duplicates when existing item is re-added, 
        //  and to assign FileOpenCommand to each new MRUListItem. 
    
        //  etc. etc. etc. 
    }
    
    public class MRUListItem : INotifyPropertyChanged
    {
        public ICommand FileOpenCommand { get; set; }
    
        private int _number;
        public int Number {
            get { return _number; }
            set
            {
                _number = value;
                OnPropertyChanged("Number");
                OnPropertyChanged("HeaderText");
            }
        }
        public String HeaderText { 
            get {
                return String.Format("_{0} {1}", Number, FileName);
            }
        }
    
        //  etc. etc. etc. 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-03
      • 1970-01-01
      • 2015-08-30
      • 2015-02-23
      • 2019-12-05
      • 1970-01-01
      • 2020-01-10
      • 1970-01-01
      相关资源
      最近更新 更多