【问题标题】:ICommand implemtation fails silently [duplicate]ICommand 实现默默地失败[重复]
【发布时间】:2018-06-18 12:22:23
【问题描述】:

更新

我尝试使用的按钮位于 <DataTemplate> 内,这显然是导致问题的原因。一旦我在<ItemsControl> 区域外的按钮上尝试了代码,它就可以工作了。谁能告诉我,为什么它在 <ItemsControl><DataTemplate> 这样的重复按钮中不起作用?

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

在我的实现中(参见下面的代码),当我单击按钮时没有任何反应。我还尝试在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();
    }
}

【问题讨论】:

  • 你将 ViewModel 绑定到 View 吗?通过设置视图的DataContext ?
  • @Noceo 您希望在哪里看到您的消息?如果将这一行写入文件,它会起作用吗?
  • 改用Debug.WriteLine,或者只是设置一个断点。我还建议编写 CanExecuteChanged?.Invoke(this, EventArgs.Empty); 并摆脱 delegate {} 初始化。
  • 听起来更像是ItemsControl引起的,它会为每个项目引入一个新的DataContext
  • 这个stackoverflow.com/questions/3404707/… 是对神奇的谷歌搜索“WPF ItemsControl Binding Parent”的回答;)请注意链接的问题可能令人困惑,但接受的答案很清楚

标签: c# wpf mvvm icommand


【解决方案1】:

如果您有ItemsControl(正如您在更新版本中提到的),那么DataContext 的每个实例化DataTemplate 将在ItemsSource 中使用源集合的每个项目。要绑定到父视图模型中的命令,您可以使用 ElementName 来访问 ItemsControl

    <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>

如果您不想使用名称,另一种方法是使用 RelativeSource 来访问项目控件:

Command="{Binding DataContext.FakeCommand,  RelativeSource={RelativeSource AncestorType=ItemsControl}}"

注意在这两种情况下数据上下文都是ItemsControl,所以你需要做DataContext.FakeCommandDataContext这里指的是ItemsControl的数据上下文

您可能还需要调用命令的项目,因为它可以被源集合中的任何项目调用。为此,您可以添加一个CommandParameter={Binding},传递命令的参数将是项目(您的实现不会将参数传递给委托,但可以)

【讨论】:

    【解决方案2】:

    CanExecuteExecute 方法中删除 ICommand.

    【讨论】:

    猜你喜欢
    • 2011-01-03
    • 2019-08-02
    • 1970-01-01
    • 2021-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多