2010-05-17 72 views
0

我一直试图让一个动态的ContextMenu显示其collection of objects中的每个对象的名称属性。
这里是一个具体的例子,我连接到webservicecontactsgroups一个特定的帐户。所以我有那些作为global variablesi 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是我的代码。如何使用MenuItem.ItemContainerStyle时传递数据

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给tag.But它不会工作和MenuItem.ItemContainerStyle是一个工作,但随后我迷路了:

问题1:如何创建对于具有组的名称的子菜单的点击事件的处理方法?
问题2:我如何获得点击的组ID以使用?

感谢您的阅读并善意帮助我在此

回答

2

下面是一个使用数据绑定的示例。子菜单项的数据上下文是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;} 
    } 
} 
+0

感谢的作品 – 2010-05-17 15:31:22

0

你可以做到这一点不使用Click事件,或任何令人费解的。

麻烦的是,你的命令有一个DataContext的(视图模型)和项目有另一个。因此,有两种选择:要么把命令上的项目中的ItemsSource(更灵活,因为他们可以有不同的命令),或做的RelativeSource绑定备份到视图,通过view.DataContext抢视图模型,并从得到的命令那。这为您节省了一些简单的麻烦,将命令传递给所有这些数据项。

注意,因为我们通过一个样式这样做,我们会在同一个命令绑定到每个菜单项,如果我们从一些的DataContext这是通用于所有的样式相似的菜单项获得命令。但是由于我们是从类似数据项目列表中自己生成项目的,这可能就是您想要的。如果不是,则将命令放在数据项上。

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

这样做还有一个好处,就是在一个更大的菜单系统中只有一个本地化的子菜单上工作得很好,其他菜单项以常规方式定义。这是部分MRU清单实施。您可以非常轻松地为其他类似的子菜单执行相同的操作,或者只需很少的工作就可以完成整个主菜单树。

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

这两个都已经在一个完整的实现中进行了测试,但是下面的内容并不完整:为了便于管理,所以将它简化为使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:

<!-- 
      <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. 
}