从上下文菜单的菜单项中检索所选项目。我正在使用WPF,MVVM

时间:2014-11-17 21:24:53

标签: wpf mvvm

我的ListView上有一个上下文菜单,其中FilterBy是其中的一个菜单项。此菜单项绑定到可观察的Menuitems集合(来自对象ContextMenuclass的_childFilterMenuitems)。我想从FilterBy MenuItem的子菜单中检索所选项目,并在我的MainView模型中绑定到名为SelectedItem的属性。

使用relay命令并填充项目,一切正常。但是,我无法访问主视图模型中的选定项目。我尝试将SelectedItem属性(从MainViewModel)绑定到Menuitem上的Tag属性。我不能让这个工作。我阅读了几篇关于可视树及其datacontext和Placement target.Tag的博客,我无法弄清楚包含tag属性的位置。请指导我,以便我可以建立适当的绑定。我很新,这个网站有很大的帮助。

在我的MainWindow.xaml

 <ListView.ContextMenu >
   <ContextMenu Name="menuListContext" >
 <MenuItem Header="Reset" Name="menuReset" Command="{Binding ResetCmd}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext}" >
<MenuItem Header="Filter By"   ItemsSource="{Binding ChildFilterMenuItems}">  
<MenuItem.ItemContainerStyle>                                   
   <Style TargetType="{x:Type MenuItem}" <Setter Property="Header" Value="{Binding  Header, Mode=TwoWay}" />  
   <Setter Property="ItemsSource" Value="{Binding Path=  ChildFilterMenuItems}"/>
   <Setter Property= "Command" Value= "{Binding DataContext.FilterByCmd, RelativeSource   ={RelativeSource AncestorType={x:Type MenuItem}}}"/>
   <Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=DataContext}" />
   <Setter Property="Tag" Value= "{Binding DataContext.SelectedItem, RelativeSource ={RelativeSource AncestorType=MenuItem}}"/> 
  </Style>
 </MenuItem.ItemContainerStyle>

  </ContextMenu >
</ListView.ContextMenu>

MainViewModel.xaml

  public class MainViewModel : ViewModelBase, INotifyPropertyChanged
   {
       /// <summary>
       /// The menu item selected from FilterBy Menu.
       /// </summary>
       public string SelectedItem {get;set;}

     public ObservableCollection<ContextMenuClass> ChildFilterMenuItems
     {
        get
        {
            return _childFilterMenuItems;

        }

        set
        {
            _childFilterMenuItems = value;
            // Call OnPropertyChanged whenever the property is updated
            OnPropertyChanged("ChildFilterMenuItems");
        }
    }

    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>      
    public MainViewModel()
    {  _childFilterMenuItems = new ObservableCollection<ContextMenuClass>(); 
       //populates the menuitems for FilterBy
       PopulateFilterBy  
       FilterByCmd = new RelayCommand(() => FilterByMenu(), () => true);
    }
    private void FilterByMenu()
    {
        try
        {
          string MenuName = GetExactName(SelectedItem);
         }

ContextMenuClass.cs

public class ContextMenuClass : INotifyPropertyChanged
{
    #region Fields

    private ObservableCollection<ContextMenuClass> _filterItems;

    private string _header;

    private bool _isEnabled;

    #endregion

    #region Properties

    /// <summary>
    /// Gets or sets the header.
    /// </summary>
    /// <value>The header.</value>
    public string Header
    {
        get
        {
            return _header;
        }
        set
        {
            _header = value; OnPropertyChanged("Header");
        }
    }



    public bool IsEnabled
    {
        get
        {
            return _isEnabled;
        }
        set
        {
             _isEnabled = value; OnPropertyChanged("IsEnabled");
        }
    }

    public ObservableCollection<ContextMenuClass> ChildFilterMenuItems
    {
        get
        {
            return (_filterItems = _filterItems ??
             new ObservableCollection<ContextMenuClass>());
        }
    }
    /// <summary>
    /// Gets or sets the SelectedItem.
    /// </summary>
    /// <value>The header.</value>
    public object SelectedMenuItem
    {
        get
        {
            return _currentItem = Header;
        }
        set
        {
            _currentItem = value; OnPropertyChanged("SelectedMenuItem");

        }

    }       
    #endregion

    #region INotifyPropertyChanged
    /// <summary>
    /// Occurs when a property value changes.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;
    private object _currentItem;

    /// <summary>
    /// Safely raises the PropertyChanged event.
    /// </summary>
    /// <param name="property">The property name.</param>

    protected void OnPropertyChanged(string Property)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(Property));
        }
    }
    #endregion

2 个答案:

答案 0 :(得分:1)

如果您想知道哪个ContextMenuClass对应于所点击的菜单项,则应修改CommandParameter setter,如下所示:

<Setter Property="CommandParameter"
        Value="{Binding}" />

然后将FilterByCmdRelayCommand更改为RelayCommand<ContextMenuClass>

FilterByCmd = new RelayCommand<ContextMenuClass>(FilterByMenu, _ => true);

并在ContextMenuClass方法中添加FilterByMenu参数:

private void FilterByMenu(ContextMenuClass selectedItem)
{
    // ...
}

答案 1 :(得分:0)

我希望这可以帮助:

<MenuItem ItemsSource="{Binding MyList}">
    <MenuItem.ItemContainerStyle>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Command" Value="{Binding RelativeSource={ RelativeSource FindAncestor, AncestorType={ x:Type Window}}, Path= DataContext.MyListItemCommand}"/>
            <Setter Property="CommandParameter" Value="{Binding}" />
            <Setter Property="IsCheckable" Value="True"/>
            <Setter Property="IsChecked" Value="{Binding IsChecked, Mode=OneWay}"/>
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

因此列表为 MyList,命令为 MyListItemCommand,命令参数为 MyList 中的实际项目(因为 Value="{Binding}" 返回实际列表项目)。< /p>

这也意味着您需要编写 MyListItemCommand(实现 ICommand 接口)类来管理当前检查哪个列表项(请注意,也可以同时检查多个项目在这种情况下)。