【问题标题】:Retrieve the selected item from the menuitems of a context menu. I am using WPF, MVVM从上下文菜单的菜单项中检索所选项目。我正在使用 WPF、MVVM
【发布时间】:2014-11-17 21:24:53
【问题描述】:

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

中继命令和填充项目一切正常。但是我无法访问我的主视图模型中的选定项目。我尝试将 SelectedItem 属性(来自 MainViewModel)绑定到 Menuitem 上的 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

【问题讨论】:

  • “已选择”菜单项是什么意思? WPF 中的菜单没有“选定”项目的概念。您是指已单击/调用的菜单项,还是“已检查”的可检查菜单项?
  • 是的。 FilterBy 菜单上已被用户点击的菜单项。
  • 是的,你说的很有道理。 FilterByCmd 命令由菜单项列表调用。我需要在我的 mainviewmodel 的 FilterBy() 方法中调用此命令的菜单项的名称,以便进一步实现。

标签: wpf mvvm


【解决方案1】:

如果你想知道哪个ContextMenuClass对应于被点击的菜单项,你应该修改你的CommandParameter设置器如下:

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

然后将您的 FilterByCmdRelayCommand 更改为 RelayCommand&lt;ContextMenuClass&gt;

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

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

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

【讨论】:

  • 抱歉在我之前的评论中按了 Enter ...FilterByCmd = new RelayCommand(FilterByMenu);它不起作用。我没有想到我应该使用我创建的对象而不是 Windows 控件。非常感谢。
【解决方案2】:

我希望这可以帮助:

<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}" 返回实际的列表项)。

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

【讨论】:

  • 另外请注意 MyListItemCommand 不是列表项的属性。它是整个代码 sn-p 所在的 ViewModel 的一个属性。
猜你喜欢
  • 2015-06-15
  • 1970-01-01
  • 2011-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多