【问题标题】:RaiseCanExecuteChanged() on a RelayCommand<enum> doesn't cause CanExecute() to be calledRelayCommand<enum> 上的 RaiseCanExecuteChanged() 不会导致调用 CanExecute()
【发布时间】:2018-06-21 07:14:44
【问题描述】:

我的第一个问题来了。

在带有 MVVM Light 的 UWP 应用程序中,我尝试使用枚举参数定义 仅一个 命令,以响应视图中的所有按钮交互。但是按钮仍处于禁用状态且无响应。

我已经为命令定义了参数

public enum ButtonKey
{
    Connect = 0,
    Disconnect = 1
}

然后由 MainViewModel 类使用

public class MainViewModel : ViewModelBase
{
    RelayCommand<ButtonKey> buttonPressed;
    public RelayCommand<ButtonKey> ButtonPressed
    {
        get => buttonPressed;
        set => buttonPressed = value;
    }

    public MainViewModel()
    {
        buttonPressed = new RelayCommand<ButtonKey> (ButtonPressed_Execute, ButtonPressed_CanExecute);
    }

    bool ButtonPressed_CanExecute(ButtonKey arg)
    {
        bool retValue = false;
        switch (arg)
        {
            // The following conditions are just for testing
            case ButtonKey.Connect:
                retValue = true;
                break;
            case ButtonKey.Disconnect:
                retValue = false;
                break;
        }
        return retValue;
    }

    void ButtonPressed_Execute(ButtonKey obj)
    {
        // another switch() case:
    }
}

那么xaml代码如下:

<CommandBar>
    <AppBarButton Label="Connect" Command="{Binding ButtonPressed}">
        <AppBarButton.CommandParameter>
            <viewModel:ButtonKey>Connect</viewModel:ButtonKey>
        </AppBarButton.CommandParameter>
    </AppBarButton>
    <AppBarButton Label="Disconnect" Command="{Binding ButtonPressed}">
        <AppBarButton.CommandParameter>
            <viewModel:ButtonKey>Disconnect</viewModel:ButtonKey>
    </AppBarButton.CommandParameter>
</AppBarButton>

即使在MainViewModel 构造函数中调用buttonPressed.RaiseCanExecuteChanged(),也不会调用ButtonPressed_CanExecute(ButtonKey arg) 方法。

我认为这一切都是由用作命令参数的枚举类型引起的,但我不知道为什么。任何帮助将不胜感激。

【问题讨论】:

    标签: mvvm enums uwp mvvm-light uwp-xaml


    【解决方案1】:

    我检查了 MvvmLight 的源代码,发现了问题。在RelayCommand&lt;T&gt;'s source 中,您会在CanExecute 方法中找到以下检查:

    if (parameter == null || parameter is T)
    {
        return (_canExecute.Execute((T)parameter));
    }
    

    由于某种原因,该方法的枚举parameterint,而不是执行检查时枚举的实例。因此,第二次检查将失败。

    如果您更新代码以使用int,它将按预期工作:

    public RelayCommand<int> ButtonPressed { get; set; }
    
    public MainViewModel()
    {
        ButtonPressed = new RelayCommand<int>(ButtonPressed_Execute, ButtonPressed_CanExecute);            
    }
    
    bool ButtonPressed_CanExecute(int arg)
    {
        bool retValue = false;
        switch (arg)
        {
            // The following conditions are just for testing
            case (int) ButtonKey.Connect:
                retValue = true;
                break;
            case (int) ButtonKey.Disconnect:
                retValue = false;
                break;
        }
        return retValue;
    }
    
    void ButtonPressed_Execute(int  obj)
    {
        // another switch() case:
    }
    

    我觉得这很令人惊讶,我想这应该作为 MvvmLight 中的一个错误来解决。

    【讨论】:

    • 我同意 Martin Zikmund 的建议。 @Oreste Riccardo Natale 您可以在Github 上报告此问题,您可以使用 Martin Zikmund 的代码作为解决方法。
    • 我将尝试在 MvvmLight 存储库上执行 Pull 请求并进行修复 :-)
    • 谢谢@MartinZikmund,它确实有效!鉴于您的洞察力,现在我只是想知道这种行为是否确实如愿。正确的方法应该是使用 ValueConverter from/to int 和 enum 类型吗?
    • 实际上我发现枚举值显示为 int 的事实非常令人惊讶,但我认为最好的办法是在 MvvmLight 中解决这个问题,以便框架可以处理 int -> enum转换,您可以使用enum 作为RelayCommand 的泛型类型参数,并保持XAML 与现在相同。 int 应该是一个临时解决方案......
    【解决方案2】:

    尝试使用 x:static 标记扩展设置命令参数

    <AppBarButton Label="Connect" 
                  Command="{Binding ButtonPressed}"
                  CommandParameter="{x:Static viewModel:ButtonKey.Connect}" />
    

    【讨论】:

    • x:静态在 UWP 中不可用
    猜你喜欢
    • 2011-10-19
    • 2011-01-19
    • 1970-01-01
    • 2023-04-03
    • 2013-02-10
    • 1970-01-01
    • 2014-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多