C# RelayCommand赢得';单击按钮时不执行

C# RelayCommand赢得';单击按钮时不执行,c#,wpf,xaml,mvvm,relaycommand,C#,Wpf,Xaml,Mvvm,Relaycommand,我在这个问题上纠缠了几个小时。我正在尝试在WPF中实现MVVM样式的Word加载项。我没有使用MVVM工具包。我有一个WPF用户控件,它停靠在WinForm中。虽然我能够在win表单中看到WPF用户控件并与之交互,但当我单击按钮时,绑定到WPF按钮的通用RelayCommand将不会执行。RelayCommand位于ViewModel.cs中,视图的DataContext通过代码隐藏进行设置。我肯定我在做一些愚蠢的事情,但是我不知道它是什么,因此也不知道为什么RelayCommand属性的get

我在这个问题上纠缠了几个小时。我正在尝试在WPF中实现MVVM样式的Word加载项。我没有使用MVVM工具包。我有一个WPF用户控件,它停靠在WinForm中。虽然我能够在win表单中看到WPF用户控件并与之交互,但当我单击按钮时,绑定到WPF按钮的通用
RelayCommand
将不会执行。
RelayCommand
位于ViewModel.cs中,视图的
DataContext
通过代码隐藏进行设置。我肯定我在做一些愚蠢的事情,但是我不知道它是什么,因此也不知道为什么
RelayCommand
属性的
get{}
不会被执行。请参阅下面的代码。提前感谢您的帮助

RelayCommand.cs(代码片段不包括名称空间,包括语句)

ViewModel.cs(不包括某些代码。仅显示相关的RelayCommand)

//
///SubmitCommentCommand负责与UI交互以提交注释。
/// 
///返回一个RelayCommand,该命令执行一个方法来保存注释框中的注释
公共ICommand SubmitCommentCommand
{
得到
{
返回_submitcommonCommand??(_submitcommonCommand=newrelaycommand(param=>this.SaveComment());
}
}

我通过在XAML而不是.cs文件中告诉模型数据上下文解决了这个问题

首先:告诉模型您放置视图模型的
名称空间,我的如下所示:

xmlns:Local="clr-namespace:MKPL.Views.A01.S020"
Second:在XAML
资源中添加ViewModel,如:

<UserControl.Resources>  
        <Local:ViewModel x:Key="dvm"/>   
</UserControl.Resources>
Fourth:在按钮代码中添加如下数据上下文:

<Button Grid.Column="2" x:Name="SubmitButton" Command="{Binding Path=SubmitCommentCommand, Source={StaticResource dvm}}"
                        Content="Submit" HorizontalAlignment="Right" Margin="5"/>


希望它能帮助您

我通过在XAML而不是.cs文件中告诉模型数据上下文解决了这个问题

首先:告诉模型您放置视图模型的
名称空间,我的如下所示:

xmlns:Local="clr-namespace:MKPL.Views.A01.S020"
Second:在XAML
资源中添加ViewModel,如:

<UserControl.Resources>  
        <Local:ViewModel x:Key="dvm"/>   
</UserControl.Resources>
Fourth:在按钮代码中添加如下数据上下文:

<Button Grid.Column="2" x:Name="SubmitButton" Command="{Binding Path=SubmitCommentCommand, Source={StaticResource dvm}}"
                        Content="Submit" HorizontalAlignment="Right" Margin="5"/>


希望它能帮助您更详细地了解MVVM和RelayCommand:

您不必在Xaml中声明ViewModel,这主要是在应用程序根级别以编程方式完成的,可能需要一些DI

当坚持这一点时,您的RelayCommand应如下所示:

public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members
}
public class GenericRelayCommand<T> : ICommand
{
    private readonly Action<T> _execute;
    public Predicate<T> CanExecuteFunc { get; private set; }

    public GenericRelayCommand(Action<T> execute) : this(execute, p => true)
    {}

    public GenericRelayCommand(Action<T> execute, Predicate<T> canExecuteFunc)
    {
        _execute = execute;
        CanExecuteFunc = canExecuteFunc;
    }

    public bool CanExecute(object parameter)
    {
        var canExecute = CanExecuteFunc((T)parameter);
        return canExecute;
    }

    public void Execute(object parameter)
    {
        _execute((T)parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
        }
        remove
        {
            CommandManager.RequerySuggested -= value;
        }
    }
}
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Column="0"
                    Orientation="Horizontal">
            <TextBox Name="textBox"
                     Width="200"
                     Text="{Binding Comment,
                                    Mode=TwoWay,
                                    UpdateSourceTrigger=PropertyChanged}" />
            <Button x:Name="SubmitButton1"
                    Grid.Column="0"
                    Margin="5"
                    HorizontalAlignment="Right"
                    Command="{Binding Path=SubmitComment1Command}"
                    CommandParameter="{Binding ElementName=textBox,
                                               Path=Text}"
                    Content="Submit1" />
        </StackPanel>


        <Button x:Name="SubmitButton2"
                Grid.Column="1"
                Margin="5"
                HorizontalAlignment="Right"
                Command="{Binding Path=SubmitComment2Command}"
                Content="Submit2" />
    </Grid>
</Window>

然后一切都会正常工作。

要让您更详细地了解MVVM和RelayCommand:

您不必在Xaml中声明ViewModel,这主要是在应用程序根级别以编程方式完成的,可能需要一些DI

当坚持这一点时,您的RelayCommand应如下所示:

public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members
}
public class GenericRelayCommand<T> : ICommand
{
    private readonly Action<T> _execute;
    public Predicate<T> CanExecuteFunc { get; private set; }

    public GenericRelayCommand(Action<T> execute) : this(execute, p => true)
    {}

    public GenericRelayCommand(Action<T> execute, Predicate<T> canExecuteFunc)
    {
        _execute = execute;
        CanExecuteFunc = canExecuteFunc;
    }

    public bool CanExecute(object parameter)
    {
        var canExecute = CanExecuteFunc((T)parameter);
        return canExecute;
    }

    public void Execute(object parameter)
    {
        _execute((T)parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
        }
        remove
        {
            CommandManager.RequerySuggested -= value;
        }
    }
}
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Column="0"
                    Orientation="Horizontal">
            <TextBox Name="textBox"
                     Width="200"
                     Text="{Binding Comment,
                                    Mode=TwoWay,
                                    UpdateSourceTrigger=PropertyChanged}" />
            <Button x:Name="SubmitButton1"
                    Grid.Column="0"
                    Margin="5"
                    HorizontalAlignment="Right"
                    Command="{Binding Path=SubmitComment1Command}"
                    CommandParameter="{Binding ElementName=textBox,
                                               Path=Text}"
                    Content="Submit1" />
        </StackPanel>


        <Button x:Name="SubmitButton2"
                Grid.Column="1"
                Margin="5"
                HorizontalAlignment="Right"
                Command="{Binding Path=SubmitComment2Command}"
                Content="Submit2" />
    </Grid>
</Window>

然后一切都会正常工作。

代码中没有任何错误。。检查是否正确应用了Datacontext。。添加另一个文本属性并将其绑定到textblock并检查是否显示?使用Snoop()在运行时检查datacontext在我看来,您没有发送命令参数,在RelayCommand实现中,由于某种原因,只有在参数不为null时才调用execute。为什么在ViewModel.cs中使用ICommand而不是RelayCommand?代码中没有任何错误。。检查是否正确应用了Datacontext。。添加另一个文本属性并将其绑定到textblock并检查是否显示?使用Snoop()在运行时检查datacontext在我看来,您没有发送命令参数,在您的RelayCommand实现中,由于某些原因,只有在参数不为null时才调用execute。为什么在ViewModel.cs中使用ICommand而不是RelayCommand?感谢所有响应者。这个特殊的解决方案对我有效。@user3317801如果这个解决方案对你有效,那么请将它标记为一个答案,以帮助其他人注意到它。我想我说得太早了。我在下午早些时候尝试了这个解决方案,并认为它是成功的,因为在启动外接程序时,调用了SubmitCommentCommand,但今晚当我尝试重新启动应用程序时,我注意到该命令除了在启动时外,没有其他时间执行。我猜它总是这样,我从来没有注意到。不管怎样,我不知道这里发生了什么。我将按照另一位对此问题发表评论的人的建议尝试下载snoop,看看会发生什么。@user3317801您应该给GalaSoft一次尝试,它是针对MVVM模式的,我用它测试了我的解决方案。只是想让您知道,我认为您的解决方案可以工作,但我注意到Visual Studio中的XAML编辑器给了我一个警告。这可能是我的问题的根源:基本上,当我在UserControl.Resources标记中命名视图模型时,即警告说“ViewModel不存在于名称空间clr-…”中。你认为有什么办法可以避免这种情况吗?我知道ViewModel存在并编译。不知道为什么XAML不能识别它。我声明通过说出up-top-xmlns:local=“clr namespace:AppName”来进行本地声明,因为它位于目录的顶层。感谢所有响应者。这个特殊的解决方案对我有效。@user3317801如果这个解决方案对你有效,那么请将它标记为一个答案,以帮助其他人注意到它。我想我说得太早了。我在下午早些时候尝试了这个解决方案,并认为它是成功的,因为在启动外接程序时,调用了SubmitCommentCommand,但今晚当我尝试重新启动应用程序时,我注意到该命令除了在启动时外,没有其他时间执行。我猜它总是这样,我从来没有注意到。不管怎样,我不知道这里发生了什么。我将按照另一位对此问题发表评论的人的建议尝试下载snoop,看看会发生什么。@user3317801您应该给GalaSoft一次尝试,它是针对MVVM模式的,我用它测试了我的解决方案。只是想让您知道,我认为您的解决方案可以工作,但我注意到Visual Studio中的XAML编辑器给了我一个警告。这可能是
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}