【问题标题】:Can't bind ICommand in VM to button Command in xaml无法将 VM 中的 ICommand 绑定到 xaml 中的按钮命令
【发布时间】:2011-03-18 12:18:16
【问题描述】:

我创建了一个基于 MVVM 轻量级工具包的 VM。 在VM中,有一个简单的ICommand(RelayCommand)

  private RelayCommand _myCommand = null;
    public RelayCommand MyCommand
    {
        get
        {
            if (_myCommand == null)  //set break point here for debug
            {
                _myCommand = new RelayCommand(() =>
                {
                    try
                    {
                       //....
                    }
                    catch (Exception ex)
                    {
                        // notify user if there is any error
                        //....
                    }
                }
                , () => true);
            }
            return _myCommand;
        }
    }

然后在 xaml 中,只需将此 Command 属性绑定到一个按钮,例如:

 <Button Grid.Column="1"  x:Name="Test" Content="Test" Margin="2,0,2,0" Command="{Binding Path=MyCommand}" />

然后运行app,点击按钮,完全没有反应。没有错误。 虚拟机工作正常。在我单击“测试”按钮之前,数据已加载到数据网格中。

如果调试应用程序并放置断点,则永远不会到达该点。

如何解决这个问题?

【问题讨论】:

    标签: silverlight mvvm silverlight-4.0 mvvm-light mvvm-toolkit


    【解决方案1】:

    为您的 MyCommand 属性添加一个 setter。

    与往常一样,在呈现 XAML 时检查输出窗口是否存在任何数据绑定错误。

    另外,尝试添加一个测试值转换器并在 convert 方法中放置一个断点,以查看该命令是否正在执行数据绑定。如果未命中断点,则说明 XAML 中存在问题。如果断点被命中,看一下值,看看数据上下文是否正确。

    <UserControl.Resources>
        <ResourceDictionary>
            <TestConverter x:Key="TestConverter" />
        </ResourceDictionary>
        <Button Grid.Column="1" x:Name="Test" Content="Test" Margin="2,0,2,0" Command="{Binding Path=MyCommand, Converter={StaticResource TestConverter}}" />
    </UserControl>
    

    测试值转换器 - 对于调试数据绑定问题非常有用。

    public class TestConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Debug.WriteLine("TestConverter.Convert(value := {0}, targetType := {1}, parameter := {2}, culture := {3})",
                value, targetType, parameter, culture);
            return value; // put break point here to test data binding
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Debug.WriteLine("TestConverter.ConvertBack(value := {0}, targetType := {1}, parameter := {2}, culture := {3})",
                value, targetType, parameter, culture);
            return value;
        }
    }
    

    【讨论】:

    • 澄清一下,命令绑定的工作不需要setter。但是,setter 会很有用,因此您不必像这样将所有杂乱的代码放在一个 getter 中。糟糕!
    • 喜欢 testconverter 的想法。还有更多相关(或完全不相关)的提示吗?
    【解决方案2】:

    在我的机器上工作:)

    说真的,我做了一个简单的项目,创建了一个 ViewModel,粘贴到您的代码中,然后它就可以工作了。我猜你正在处理其他问题。

    Here is my C# code.

    Here is my XAML code.

    是时候传福音了

    这个 ViewModel 代码很臭。您可能会考虑使用某种 MVVM 框架或助手。例如,如果您查看ViewModelSupport,您可以这样编写您的 ViewModel:

    public class MyViewModel : ViewModelBase
    {
        public void Execute_MyCommand()
        {
            // Your execution code here
        }
    }
    

    然后,您就可以避免所有凌乱的管道。想想看:)

    【讨论】:

    • 我没有想到您在基本 ViewModel 类中所做的一些事情。我特别喜欢 DependentUpon 属性。非常好!
    【解决方案3】:

    代码看起来不错。所以你只需要检查输出窗口是否有数据绑定错误。也许您没有正确设置视图的数据上下文。顺便说一句,您应该在命令的 try-catch 中添加断点。

    【讨论】:

      【解决方案4】:

      1) 确保您从中继命令的 CanExecute 委托返回 true。 (我看到你正在这样做,但最好仔细检查一下)。

      2) 按钮是否位于ListBoxDataGridDataForm 内?

      对于 ListBox 或 DataGrid:

      如果是这样,您需要修改绑定表达式以引用 VM DataContext 而不是数据绑定项。 See this answer.

      对于数据表单:

      比较棘手,but look at this question.

      【讨论】:

        猜你喜欢
        • 2011-09-28
        • 1970-01-01
        • 2016-11-20
        • 1970-01-01
        • 2013-06-29
        • 1970-01-01
        • 2011-02-17
        • 1970-01-01
        • 2020-05-28
        相关资源
        最近更新 更多