【问题标题】:WPF command in code behind not firing代码中的 WPF 命令未触发
【发布时间】:2017-10-21 21:19:57
【问题描述】:

我正在开发一个使用 MVVM 模式的 WPF 应用程序,而且我对 .NET 开发还很陌生。我的理解是 View 应该将其数据上下文设置为 ViewModel,然后任何与数据相关的处理都应该在 ViewModel 中完成,而 UI 部分应在视图中处理(XAMLcode behind)。

所以我有一个菜单,每个菜单项都绑定到 DelegateCommand(使用 Prism)在 ViewModel 中声明并使用键盘快捷键进行处理它完美无瑕。但是,我想将菜单项绑定View's code behind 文件中的 command,因为它不会处理任何数据(它只是显示或隐藏面板)。

查看 (XAML)

<Window x:Class="Editor.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Editor.Views"
        xmlns:vm="clr-namespace:Editor.ViewModels"
        mc:Ignorable="d"
        x:Name="RootWindow"
        WindowStartupLocation="CenterScreen"
        Width="1200" Height="650">

    <!-- Data Context -->
    <Window.DataContext>
        <vm:MainViewModel />
    </Window.DataContext>

    <!-- Keyboard Shortcuts -->
    <Window.InputBindings>
        <KeyBinding Modifiers="Control" Key="L" Command="{Binding ElementName=RootWindow, Path=ToggleLayersCommand}" />
    </Window.InputBindings>

    <!-- Main Menu -->
    <Menu>
        <MenuItem Header="View" Padding="5, 2">
            <MenuItem Header="Toggle Layers Panel" InputGestureText="CTRL + L" Command="{Binding ElementName=RootWindow, Path=ToggleLayersCommand}" />
        </MenuItem>
    </Menu>

</Window>

查看(代码隐藏)

public partial class MainWindow : Window
{
    public DelegateCommand ToggleLayersCommand { get; private set; }

    public MainWindow()
    {
        InitializeComponent();
        ToggleLayersCommand = new DelegateCommand(ToggleLayersCommand_OnExecuted, () => true);
    }

    private void ToggleLayersCommand_OnExecuted()
    {
        LayerListPanel.Visibility = (LayerListPanel.Visibility == Visibility.Collapsed) ? Visibility.Visible : Visibility.Collapsed;
    }
}

我在 XAML 中命名窗口以在绑定 Command 属性View 中找到 command 而不是 ViewModel /强>。它似乎找到了它,因为我得到了 intellisense,但它永远不会触发。

我可以使用 click 事件 代替,即使我宁愿使用 command 但是如何绑定 键盘事件的快捷方式

【问题讨论】:

    标签: c# wpf xaml mvvm command


    【解决方案1】:

    我将在 ViewModel 中定义命令并让它更改属性public Visibility LayerListPanelVisibility(也应该在 ViewModel 中定义)。然后我会将LayerListPanel.Visibility 绑定到这个属性。

    尽可能让您的代码隐藏为空。


    你的 Binding 找不到命令的原因是 ToggleLayersCommandnull 当 Binding 被解析时。只有在绑定解析后不久,您才将正确的命令分配给ToggleLayersCommand。但是,绑定不会更新,因为您的 Viewmodel 不会引发 PropertyChanged 事件。

    如果您想将命令保留在视图中,您可以在分配命令时引发 PropertyChanged 事件,或者在调用 InitializeComponent 之前分配命令:

    public MainWindow()
    {
        ToggleLayersCommand = new DelegateCommand(ToggleLayersCommand_OnExecuted, () => true);
        InitializeComponent();
    }
    

    【讨论】:

    • 所以即使和数据没有关系,放到ViewModel里也行?
    • 是控制视图的逻辑。这正是 ViewModel 应有的样子。
    • 好吧,我想我现在有了更好的理解,是的,在 InitializeComponent 工作之前绑定命令,但我想我要把它移到 ViewModel 上。
    • 在 ViewModel 中依赖 WPF 特定的 Visiblity 枚举是没有意义的,您不妨将它放在代码隐藏中。拥有视图模型的目的是将业务逻辑连接到 GUI,并尽可能少地依赖,以最大限度地提高可用性和可测试性。如果你真的想让它成为 MVVM,你可以让属性与业务逻辑相关,比如UserHasPermission,并使用转换器将其转换为视图可以理解的东西。使用视图模型只是因为是不好的建议。视图模型应该对视图一无所知。
    【解决方案2】:

    您必须使用ViewModel 命令而不是View

    视图模型:

    public partial class MainViewModel
    {
        public DelegateCommand ToggleLayersCommand { get; private set; }
    
        public MainViewModel()
        {
            ToggleLayersCommand = new DelegateCommand(ToggleLayersCommand_OnExecuted, () => true);
        }
    
        private void ToggleLayersCommand_OnExecuted()
        {
            LayerListPanel.Visibility = (LayerListPanel.Visibility == Visibility.Collapsed) ? Visibility.Visible : Visibility.Collapsed; 
    //THIS WILL PROBABLY NOT WORK...
    //You can use another public property to change your visibility.
    // Create a public visibility and bind it to the correct item
        }
     }
    

    XAML:

    <Menu>
        <MenuItem Header="View" Padding="5, 2">
           <MenuItem Header="Toggle Layers Panel" InputGestureText="CTRL + L" Command="{Binding Path=ToggleLayersCommand}" />
            </MenuItem>
     </Menu>
    

    【讨论】:

      【解决方案3】:

      我在将命令绑定到键绑定时遇到了同样的问题。我所做的只是给一个按钮自己的名字,并从 set 命令后面的查看代码到你的。

      我的例子是这样的:

      <KeyBinding x:Name="ShowDetailsKeyBinding"
                      Key="D"
                      Modifiers="Control" />
      

      后面的代码:

      ShowDetailsKeyBinding.Command = new DelegateCommand(ShowDetailsOperation);
      

      我使用这个解决方案来运行我的动画,其他方式你应该在你的 ViewModel 中创建命令。

      【讨论】:

        猜你喜欢
        • 2019-04-05
        • 2016-10-22
        • 1970-01-01
        • 2021-01-04
        • 2014-05-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-27
        相关资源
        最近更新 更多