ICommand实现无声地失败

时间:2018-01-09 12:53:50

标签: c# wpf mvvm icommand

更新

我试图使用的按钮位于<DataTemplate>内,这显然导致了问题。一旦我在<ItemsControl>区域外的按钮上尝试了代码,它就能正常工作。任何人都可以告诉我,为什么它不能用于<ItemsControl><DataTemplate>这样的重复按钮?

我正在尝试基于TutorialsPoints.com的文章实现MVVM通信模式。我稍微修改了代码,但总的来说它仍然非常类似于文章中的代码。我想要做的是,一旦点击一个按钮就在控制台中写一行。

通过我的实现(参见下面的代码),单击按钮时没有任何反应。我还尝试在OnClick()函数中添加一个断点来查看是否运行了,但事实并非如此。但是MyICommand()的构造函数中的断点表明该类实际上已初始化。那我做错了什么?

按钮

<Button Content="Do stuff!"
        Command="{Binding FakeCommand}"
        Cursor="Hand"
        Background="Red" 
        Foreground="White" 
        BorderThickness="0" 
        Padding="10 0 10 0"  />

视图模型

public class AgreementViewModel : INotifyPropertyChanged
{
    public MyICommand FakeCommand { get; set; }

    public AgreementViewModel ()
    {
        LoadAgreements();
        FakeCommand = new MyICommand(OnClick, CanClick);
        FakeCommand.RaiseCanExecuteChanged();
    }

    private void OnClick()
    {
        Console.WriteLine("Something was clicked...");
    }

    private bool CanClick()
    {
        return true;
    }
}

ICommand的实施

public class MyICommand : ICommand
{
    Action _TargetExecuteMethod;
    Func<bool> _TargetCanExecuteMethod;

    public event EventHandler CanExecuteChanged = delegate {};

    public MyICommand(Action executeMethod)
    {
        _TargetExecuteMethod = executeMethod;
    }

    public MyICommand(Action executeMethod, Func<bool> canExecuteMethod)
    {
        _TargetExecuteMethod = executeMethod;
        _TargetCanExecuteMethod = canExecuteMethod;
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged(this, EventArgs.Empty);
    }

    bool ICommand.CanExecute(object parameter)
    {
        if (_TargetCanExecuteMethod != null)
        {
            return _TargetCanExecuteMethod();
        }

        if (_TargetExecuteMethod != null)
        {
            return true;
        }

        return false;
    }

    void ICommand.Execute(object parameter)
    {
        _TargetExecuteMethod?.Invoke();
    }
}

2 个答案:

答案 0 :(得分:2)

如果您有ItemsControl(正如您在更新版本中提到的那样),那么DataContext的每个实例化的DataTemplateItemsSource中的每个项目使用ElementName 1}}。要绑定到父视图模型中的命令,可以使用 <ItemsControl ItemsSource="{Binding Data}" x:Name="root"> <ItemsControl.ItemTemplate> <DataTemplate> <Button Content="Do stuff!" Command="{Binding DataContext.FakeCommand, ElementName=root}" Cursor="Hand" Background="Red" Foreground="White" BorderThickness="0" Padding="10 0 10 0" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 来获取ItemsControl

RelativeSource

如果您不想使用名称,另一种方法是使用Command="{Binding DataContext.FakeCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" 来获取项目控件:

ItemsControl

请注意,在这两种情况下,数据上下文都是DataContext.FakeCommand,因此您需要执行DataContextItemsControl这里指的是CommandParameter={Binding}的数据上下文

您可能还需要调用该命令的项,因为可以为源集合中的任何项调用它。要做到这一点,你可以添加一个o < develop | o < staging | o < v0.2 | o < v0.1 ,传递命令的参数将是项目(你的实现不会将参数传递给委托,但它可以)

答案 1 :(得分:-2)

CanExecute 执行方法移除ICommand.