【问题标题】:ListBox selected items not updated when the context menu opens上下文菜单打开时列表框所选项目未更新
【发布时间】:2014-02-21 19:20:41
【问题描述】:

我的 WPF 应用程序有一个 ListBox,里面有很多项目。当用户用鼠标右键单击一个项目以打开上下文菜单时,我需要评估当前选定的项目以构建菜单项标题,告诉用户该命令会发生什么。

此命令将在项目上设置过滤器,并应提前指示生成的过滤器,该过滤器基于来自所选项目的数据。

由于我不知道有什么方法可以通过 MVVM 将 ListBox 的选定项放入视图模型中,因此我使用了后面的代码。 SelectionChanged 事件处理程序将所选项目发送到视图模型。

不幸的是,当用户点击的速度足够快时,这个选定项目列表就会过时。我经常看到以前的选择,而不是当前的。只有当我按住鼠标右键的时间足够长时,选择才是最新的。

这是我的测试应用程序的屏幕截图(如下):

问:如何可靠地获取上下文菜单标题的当前选择?

我制作了一个非常简单的测试用例,以便您重现该问题。转换器有一个短暂的延迟来模拟活动。我真正的转换器没有这个延迟,但是由于视图比较复杂,所以加载UI也需要很短的时间,效果是一样的。

这是代码:https://drive.google.com/file/d/0B8CN0ghdY1SdTW9Ka1lHc1dIUFk/edit

【问题讨论】:

    标签: c# wpf mvvm listbox contextmenu


    【解决方案1】:

    将您的 ViewModel 更新为此

    internal class MainViewModel : INotifyPropertyChanged
    {
        private List<string> _selectedItems;
    
        public MainViewModel()
        {
            MenuCommand = new MenuCommand();
    
            StringItems = new List<string>();
            StringItems.Add("Hello");
            StringItems.Add("world");
            StringItems.Add("of");
            StringItems.Add("mysterious");
            StringItems.Add("WPF");
        }
    
        public List<string> StringItems { get; set; }
    
        public MenuCommand MenuCommand { get; private set; }
    
        public string MenuCommandTitle
        {
            get { return "Selected items: " + SelectedItems.Aggregate((a, b) => a + ", " + b); }
        }
    
        public List<string> SelectedItems
        {
            get { return _selectedItems; }
            set
            {
                _selectedItems = value;
                OnPropertyChanged("MenuCommandTitle");
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    您想更新 ContextMenu 的绑定以通知 UI 新值。

    OnPropertyChanged("MenuCommandTitle");
    

    【讨论】:

    • 我已经考虑过了,但我担心上下文菜单标题在打开后立即更新时会闪烁。不过要测试一下。
    • 好的,确实工作得非常好。即使长度发生变化,也看不到任何值发生变化。
    【解决方案2】:

    您的 MainViewModel 似乎没有实现 INotifyPropertyChanged,因此您的 MenuCommandTitle 属性并不总是更新。当您在代码隐藏中更新 SelectedItems 时,您需要触发属性更改。

    【讨论】:

    • 据我了解,每次打开上下文菜单时都会获取一个属性,因此总是对其进行评估。在这种情况下还为时过早。另见 lll 的回答。 (没有 -1。)
    • 投反对票的是什么?我给出了答案,并向 OP 指出了我看到的错误以及如何解决它。
    • @LonelyPixel 我调试了你的代码,发现不是每次都评估 MenuCommandTitle。这就是 INotifyPropertyChanged 的​​用途,除非您告诉 UI 它已更改,否则它将使用以前的值。
    • 该死,你是对的!当我快速点击时,它甚至没有被提取。很高兴知道。
    猜你喜欢
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    相关资源
    最近更新 更多