【问题标题】:fire RaiseCanExecuteChanged when items of a Listview are changed当 Listview 的项目更改时触发 RaiseCanExecuteChanged
【发布时间】:2012-10-25 15:27:05
【问题描述】:

我在 Prism 中使用 MVVM 模式

我的模型中有一个 ObservableCollection 中的元素列表。在我的视图中,我将 ObservableCollection 绑定到 Listview,然后尝试显示 1 个绑定到名为 DoSomethingCommand 的 DelegateCommand 的按钮。这意味着我的 Listview 的每一行都有一个用于调用 DoSomethingCommand 的按钮,其中一个 CommandParameter 绑定到元素的 ID。

约束:DoSomethingCommand 会将我的元素的状态字段更改为“完成”。当一个元素“完成”时,我希望禁用调用 DoSomethingCommand 的按钮。

所以从逻辑上讲,我所要做的就是在执行命令时拥有一个 canExecuteDoSomethingCommand 委托。但是,问题是我何时以及如何提高 DoSomethingCommand.RaiseCanExecuteChanged? BTW Element 是我无法修改的第三方 dll 的一部分,但它已经实现了 INotifyPropertyChanged。

<ListView BorderThickness="0" Width="Auto"
              ItemsSource="{Binding ElementList}"
              >
   <ListView.View>
     <GridView>
       <GridViewColumn Header="Actions">
         <GridViewColumn.CellTemplate>
             <DataTemplate>
                <StackPanel Orientation="Horizontal">
                     <Button Command="{Binding DataContext.DoSomethingCommand, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" CommandParameter="{Binding ID}" >Accept</Button>
                </StackPanel>
             </DataTemplate>
           </GridViewColumn.CellTemplate>
        </GridViewColumn>

执行命令

DoSomethingCommand = new DelegateCommand<string>(executeDoSomethingCommand, canExecuteDoSomethingCommand);

【问题讨论】:

    标签: wpf listview mvvm command


    【解决方案1】:

    如果您使用的是 Prism 的 EventAggregator,并且我假设您使用的是 Prism,那么您可以订阅一个事件并在您的 DelegateCommand 上调用 RaiseCanExecuteChanged()。

    类似这样的:

    _eventAggregator.GetEvent<YourCompositePresentationEvent>().Subscribe((i) => { YourDelegateCommand.RaiseCanExecuteChanged(); });
    

    【讨论】:

    • 这很有趣。实际上我没有使用 EventAggregator,因为我现在只有一个模块。所以你说的是当我更新模型中的元素时,我应该引发一个事件,并且这个事件应该被 ViewModel 捕获以引发 RaisePropertyChanged?使用 EventAggregator 链接一切?我要试试这个
    • @kstarbucks51...没错。我认为 EventAggregator 是 Prism 的最佳功能。它促进了松散耦合部分之间的通信。
    • 使用EventAggregator确实很好,解决了我的问题
    【解决方案2】:

    我有两个解决你的问题:

    第一个解决方案:

    如果您在 Element 类上实现 INotifyPropertyChanged,那就太好了。也许您可以创建另一个类并在它们之间进行转换?您的代码将如下所示:

     public ICommand DoSomethingCommand { get; private set; }
        private void OnDoSomethingCommand(object param)
        {
            Element tmp = param as Element;
    
            if (tmp != null)
            {
                tmp.Status = "done";
            }                
    
            (DoSomethingCommand as DelegateCommand<object>).RaiseCanExecuteChanged();
        }
    
        private bool CanDoSomethingCommand(object param)
        {
            Element tmp = param as Element;
    
            if (tmp != null)
            {
                if (tmp.Status != null && tmp.Status.Equals("done"))
                    return false;
                else
                    return true; 
            }
            return true;
        }
    

    第二种解决方案:

    您可以在不调用 RaiseCanExecuteChanged 方法的情况下执行此操作。

     public ICommand DoSomethingCommand { get; private set; }
        private void OnDoSomethingCommand(object param)
        {
            Element tmp = param as Element;
    
            if (tmp != null)
            {
                tmp.Status = "done";
            }
    
            List<Element> refresh = new List<Element>(ElementList);
            ElementList.Clear();
            foreach (var item in refresh)
            {
                ElementList.Add(item);
            }          
        }
    
        private bool CanDoSomethingCommand(object param)
        {
            Element tmp = param as Element;
    
            if (tmp != null)
            {
                if (tmp.Status != null && tmp.Status.Equals("done"))
                    return false;
                else
                    return true; 
            }
            return true;
        }
    

    Here你有所有示例代码(ListViewDelegateCommand.zip)。

    【讨论】:

    • Element 已经实现了 INotifyPropertyChanged,抱歉不是很清楚(我在凌晨 2:30 写了这个问题)。第一个解决方案确实有效!这并不理想,因为命令要求另一个服务更改状态,然后我收到了来自服务的确认,其中包含修改后的元素。所以它起作用了,但我认为这是因为我很幸运延迟非常短。如果我必须等待 1 分钟才能获得更新,它可能无法正常工作。第二个解决方案是不可行的,它会刷新整个列表,这可能会很长。这会大大降低 GUI 的速度。
    猜你喜欢
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多