WPF ViewModel命令CanExecute问题 [英] WPF ViewModel Commands CanExecute issue

查看:751
本文介绍了WPF ViewModel命令CanExecute问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的视图模型上的上下文菜单命令有些困难。



我正在为View模型中的每个命令实现ICommand接口,在View(MainWindow)的资源中使用ContextMenu,并使用MVVMToolkit的CommandReference访问当前的DataContext(ViewModel)命令。



当我调试应用程序时,看起来该命令上的CanExecute方法没有被调用,除非在创建窗口,因此我的上下文MenuItems没有被启用或禁用,如我所料。



我已经准备了一个简单的示例(在这里),这表示我的实际应用,并在下面总结。




这是ViewModel

 命名空间WpfCommandTest 
{
public class MainWindowViewModel
{
private List< string> data = new List< string> {One,Two,Three};

//这是为了简化这个例子 - 通常我们将链接到
//域模型属性
public List< string> TestData
{
get {return data; }
set {data = value; }
}

// listview的绑定属性
public string SelectedItem {get;组; }

//执行命令
public ICommand DisplayValue {get;私人集}

public MainWindowViewModel()
{
DisplayValue = new DisplayValueCommand(this);
}

}
}

DisplayValueCommand是如此:

  public class DisplayValueCommand:ICommand 
{
private MainWindowViewModel viewModel;

public DisplayValueCommand(MainWindowViewModel viewModel)
{
this.viewModel = viewModel;
}

#region ICommand成员

public bool CanExecute(对象参数)
{
if(viewModel.SelectedItem!= null)
{
return viewModel.SelectedItem.Length == 3;
}
else return false;
}

public event EventHandler CanExecuteChanged;

public void Execute(object parameter)
{
MessageBox.Show(viewModel.SelectedItem);
}

#endregion
}

最后,视图在Xaml中定义:

 < Window x:Class =WpfCommandTest.Window1
xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml¥b $ b xmlns :local =clr-namespace:WpfCommandTest
xmlns:mvvmtk =clr-namespace:MVVMToolkit
Title =Window1Height =300Width =300>

< Window.Resources>

< mvvmtk:CommandReference x:Key =showMessageCommandReferenceCommand ={Binding DisplayValue}/>

< ContextMenu x:Key =listContextMenu>
< MenuItem Header =Show MessageBoxCommand ={StaticResource showMessageCommandReference}/>
< / ContextMenu>

< /Window.Resources>

< Window.DataContext>
< local:MainWindowViewModel />
< /Window.DataContext>

< grid>
< ListBox ItemsSource ={Binding TestData}ContextMenu ={StaticResource listContextMenu}
SelectedItem ={Binding SelectedItem}/>
< / Grid>
< / Window>


解决方案

CanExecuteChanged 事件:

  public事件EventHandler CanExecuteChanged 
{
add {CommandManager.RequerySuggested + = value; }
remove {CommandManager.RequerySuggested - = value; }
}

(来自Josh Smith的 RelayCommand RelayCommand DelegateCommand :你会很快厌倦了为你的每个命令创建新的命令类ViewModels ...


I'm having some difficulty with Context Menu commands on my View Model.

I'm implementing the ICommand interface for each command within the View Model, then creating a ContextMenu within the resources of the View (MainWindow), and using a CommandReference from the MVVMToolkit to access the current DataContext (ViewModel) Commands.

When I debug the application, it appears that the CanExecute method on the command is not being called except at the creation of the window, therefore my Context MenuItems are not being enabled or disabled as I would have expected.

I've cooked up a simple sample (attached here) which is indicative of my actual application and summarised below. Any help would be greatly appreciated!

This is the ViewModel

namespace WpfCommandTest
{
    public class MainWindowViewModel
    {
        private List<string> data = new List<string>{ "One", "Two", "Three" };

        // This is to simplify this example - normally we would link to
        // Domain Model properties
        public List<string> TestData
        {
            get { return data; }
            set { data = value; }
        }

        // Bound Property for listview
        public string SelectedItem { get; set; }

        // Command to execute
        public ICommand DisplayValue { get; private set; }

        public MainWindowViewModel()
        {
            DisplayValue = new DisplayValueCommand(this);
        }

    }
}

The DisplayValueCommand is such:

public class DisplayValueCommand : ICommand
{
    private MainWindowViewModel viewModel;

    public DisplayValueCommand(MainWindowViewModel viewModel)
    {
        this.viewModel = viewModel;
    }

    #region ICommand Members

    public bool CanExecute(object parameter)
    {
        if (viewModel.SelectedItem != null)
        {
            return viewModel.SelectedItem.Length == 3;
        }
        else return false;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        MessageBox.Show(viewModel.SelectedItem);
    }

    #endregion
}

And finally, the view is defined in Xaml:

<Window x:Class="WpfCommandTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfCommandTest"
    xmlns:mvvmtk="clr-namespace:MVVMToolkit"
    Title="Window1" Height="300" Width="300">

    <Window.Resources>

        <mvvmtk:CommandReference x:Key="showMessageCommandReference" Command="{Binding DisplayValue}" />

        <ContextMenu x:Key="listContextMenu">
            <MenuItem Header="Show MessageBox" Command="{StaticResource showMessageCommandReference}"/>
        </ContextMenu>

    </Window.Resources>

    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>

    <Grid>
        <ListBox ItemsSource="{Binding TestData}" ContextMenu="{StaticResource listContextMenu}" 
                 SelectedItem="{Binding SelectedItem}" />
    </Grid>
</Window>

解决方案

To complete Will's answer, here's a "standard" implementation of the CanExecuteChanged event :

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}

(from Josh Smith's RelayCommand class)

By the way, you should probably consider using RelayCommand or DelegateCommand : you'll quickly get tired of creating new command classes for each and every command of you ViewModels...

这篇关于WPF ViewModel命令CanExecute问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆