C# MVVM混合行为和RelayCommand未按预期工作

C# MVVM混合行为和RelayCommand未按预期工作,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我正在尝试设置一些行为来控制MVVM应用程序中的窗口 我的想法是,行为可以在XAML中装饰性地设置,并存在于它们自己的类中,允许在某些情况下在许多不同的视图中重用它们 我还有一个绑定到RelayCommand的菜单项。这两种方法各自都能很好地发挥作用,但当我尝试将这两种方法结合在一起时,却没有达到预期效果: MainView.xaml <Window x:Class="CaseManager.Views.MainView" xmlns="http://schemas.mic

我正在尝试设置一些行为来控制MVVM应用程序中的窗口

我的想法是,行为可以在XAML中装饰性地设置,并存在于它们自己的类中,允许在某些情况下在许多不同的视图中重用它们

我还有一个绑定到RelayCommand的菜单项。这两种方法各自都能很好地发挥作用,但当我尝试将这两种方法结合在一起时,却没有达到预期效果:

MainView.xaml

<Window x:Class="CaseManager.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:VM="clr-namespace:CaseManager.ViewModels;assembly=CaseManager.ViewModels"
        xmlns:local="clr-namespace:CaseManager.Views"
        local:ExitBehavior.ExitWhen="{Binding ExitFlag}"
        Title="Main Window" Height="350" Width="525">

    <Window.DataContext>
        <VM:MainViewModel />
    </Window.DataContext>

    <Grid>

        <Menu Height="20" VerticalAlignment="Top">
            <MenuItem Header="_File">
                <MenuItem Header="_Exit" Command="{Binding ExitCommand}" />
            </MenuItem>
        </Menu>

    </Grid>
</Window>
ExitCommand.cs

namespace CaseManager.ViewModels
{
    using System;
    using System.Collections.Generic;

    using Commands;

    public class MainViewModel : ViewModelBase
    {
        # region RelayCommands
        private RelayCommand _exitCommand;
        public RelayCommand ExitCommand
        {
            get { return _exitCommand; }
            private set { _exitCommand = value; }
        }
        #endregion

        private bool _exitFlag;
        public bool ExitFlag { 
            get { return _exitFlag; } 
            private set { _exitFlag = value; } 
        }

        public MainViewModel()
        {
            ExitCommand = new RelayCommand(ExitCommand_Execute);
            ExitFlag = false;
        }

        private void ExitCommand_Execute(object obj)
        {
            System.Console.WriteLine("Command executed");
            ExitFlag = true;
        }
    }
}
namespace CaseManager.Views
{
    using System;
    using System.Windows;

    public static class ExitBehavior
    {
        public static bool GetExitWhen(DependencyObject obj)
        {
            return (bool)obj.GetValue(ExitWhenProperty);
        }

        public static void SetExitWhen(DependencyObject obj, bool value)
        {
            obj.SetValue(ExitWhenProperty, value);
        }

        public static readonly DependencyProperty ExitWhenProperty =
            DependencyProperty.RegisterAttached(
                "ExitWhen", typeof(bool), typeof(ExitBehavior),
                new UIPropertyMetadata(OnExitWhenChanged));

        static void OnExitWhenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            System.Console.WriteLine("Behavior executed");
            Environment.Exit(0);
        }
    }
}
当我在菜单中选择exit时,按原样运行上述代码将在控制台中输出“Command executed”。所以我知道中继命令工作正常。然而,这种行为并非如此

如果我将我的
MainViewModel
的构造函数更改为将
ExitFlag
设置为true,程序将启动,将“执行的行为”打印到控制台,然后退出

ExitBehavior和RelayCommand都独立工作,但是当我试图通过在relay命令中设置ExitFlag来触发ExitBehavior时,它们不能一起使用。我是不是遗漏了什么

为了简洁起见,这里有
RelayCommand.cs

namespace CaseManager.Commands
{
    using System;
    using System.Windows.Input;

    public class RelayCommand : ICommand
    {
        #region Fields

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

        #endregion

        #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

        #region ICommand Members

        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
    }
}
namespace CaseManager.Commands
{
使用制度;
使用System.Windows.Input;
公共类中继命令:ICommand
{
#区域字段
只读操作_执行;
只读谓词_canExecute;
#端区
#区域构造函数
公共中继命令(操作执行)
:此(执行,空)
{
}
公共RelayCommand(操作执行,谓词canExecute)
{
if(execute==null)
抛出新的ArgumentNullException(“执行”);
_执行=执行;
_canExecute=canExecute;
}
#端区
#区域ICommand成员
公共布尔CanExecute(对象参数)
{
返回_canExecute==null?true:_canExecute(参数);
}
公共事件事件处理程序CanExecuteChanged
{
添加{CommandManager.RequerySuggested+=value;}
删除{CommandManager.RequerySuggested-=value;}
}
public void Execute(对象参数)
{
_执行(参数);
}
#端区
}
}

您必须通知绑定引擎,您的属性
ExitFlag
已更改。假设
ViewModelBase
以某种方式实现:


其中,
OnPropertyChanged
是一个方法,它会引发
INPC.PropertyChanged
事件。

您必须通知绑定引擎,您的属性
ExitFlag
已更改。假设
ViewModelBase
以某种方式实现:


其中,
OnPropertyChanged
是一个方法,它会引发
INPC.PropertyChanged
事件。

您必须通知绑定引擎,您的属性
ExitFlag
已更改。假设
ViewModelBase
以某种方式实现:


其中,
OnPropertyChanged
是一个方法,它会引发
INPC.PropertyChanged
事件。

您必须通知绑定引擎,您的属性
ExitFlag
已更改。假设
ViewModelBase
以某种方式实现:


其中,
OnPropertyChanged
是一个方法,它引发
INPC.PropertyChanged
事件。

首先,正如我从您的代码中理解的,这里:

local:CloseBehavior.CloseWhen="{Binding CloseFlag}"
必须有一个属性
ExitFlag

其次,这个属性应该从接口调用
OnPropertyChanged
方法来更新属性,在XAML中应该是:

local:CloseBehavior.CloseWhen="{Binding Path=ExitFlag, Mode=TwoWay}"

首先,正如我从您的代码中理解的,这里:

local:CloseBehavior.CloseWhen="{Binding CloseFlag}"
必须有一个属性
ExitFlag

其次,这个属性应该从接口调用
OnPropertyChanged
方法来更新属性,在XAML中应该是:

local:CloseBehavior.CloseWhen="{Binding Path=ExitFlag, Mode=TwoWay}"

首先,正如我从您的代码中理解的,这里:

local:CloseBehavior.CloseWhen="{Binding CloseFlag}"
必须有一个属性
ExitFlag

其次,这个属性应该从接口调用
OnPropertyChanged
方法来更新属性,在XAML中应该是:

local:CloseBehavior.CloseWhen="{Binding Path=ExitFlag, Mode=TwoWay}"

首先,正如我从您的代码中理解的,这里:

local:CloseBehavior.CloseWhen="{Binding CloseFlag}"
必须有一个属性
ExitFlag

其次,这个属性应该从接口调用
OnPropertyChanged
方法来更新属性,在XAML中应该是:

local:CloseBehavior.CloseWhen="{Binding Path=ExitFlag, Mode=TwoWay}"

很抱歉,在尝试精简此示例的代码时,这是一个输入错误!将更新您误解的问题
UpdateSourceTrigger=PropertyChanged
。当绑定目标的属性更改时,此选项告知绑定更新视图模型(即绑定源)。在OP的情况下,绑定目标永远不会更改属性。因此,
UpdateSourceTrigger
在这里是无用的,并且它与视图模型中的
INPC
实现无关。很抱歉,在尝试精简此示例的代码时,这是一个输入错误!将更新您误解的问题
UpdateSourceTrigger=PropertyChanged
。当绑定目标的属性更改时,此选项告知绑定更新视图模型(即绑定源)。在OP的情况下,绑定目标永远不会更改属性。因此,
UpdateSourceTrigger
在这里是无用的,并且它与视图模型中的
INPC
实现无关。很抱歉,在尝试精简此示例的代码时,这是一个输入错误!将更新您误解的问题
UpdateSourceTrigger=PropertyChanged
。当绑定目标的属性更改时,此选项告知绑定更新视图模型(即绑定源)。在OP的情况下,绑定目标永远不会更改属性。因此,
UpdateSourceTrigger
在这里是无用的,并且它与视图模型中的
INPC
实现无关。很抱歉,在尝试精简此示例的代码时,这是一个输入错误!将更新问题