C# 具有否决权选项的松散耦合视图内模型通知

C# 具有否决权选项的松散耦合视图内模型通知,c#,wpf,events,architecture,mvvm,C#,Wpf,Events,Architecture,Mvvm,在我正在构建的应用程序中,用户可能会在一个视图(由视图模型支持)中执行某些操作,这些操作应该会触发一个或多个其他视图模型中的操作。这些其他vm中的每一个都需要否决(也称为取消)在第一个v/vm对中执行的操作的能力 例如: 用户单击accounts列表视图显示的DataGrid控件中的帐户。DataGrid事件处理程序捕获单击并通知vm。Vm将建议的更改通知其他Vm 由于用户对另一个视图中的记录进行了未保存的编辑,所以另一个vm会告诉第一个vm建议的所选帐户更改被拒绝 当accounts list

在我正在构建的应用程序中,用户可能会在一个视图(由视图模型支持)中执行某些操作,这些操作应该会触发一个或多个其他视图模型中的操作。这些其他vm中的每一个都需要否决(也称为取消)在第一个v/vm对中执行的操作的能力

例如:

  • 用户单击accounts列表视图显示的DataGrid控件中的帐户。DataGrid事件处理程序捕获单击并通知vm。Vm将建议的更改通知其他Vm
  • 由于用户对另一个视图中的记录进行了未保存的编辑,所以另一个vm会告诉第一个vm建议的所选帐户更改被拒绝
  • 当accounts list vm收到此拒绝时,它会告诉DataGrid保持所选帐户集不变。若并没有收到拒绝,accounts list vm将允许DataGrid所选项目发生更改
  • 类似的场景是当用户启动应用程序关闭时。感兴趣的虚拟机需要一种方法来知道提议关闭,并可以选择取消关闭

    视图模型应该是松散耦合的,因此它们之间的直接事件订阅是不可取的

    您建议如何实现这种视图内模型通信

    使用事件聚合器“广播”帐户更改事件是明智的做法吗?事件参数对象将包括bool
    cancelled
    属性。想要取消更改的订阅vm将设置
    cancelled=true

    谢谢你,

    我认为你的最后一段提出了一个很好的解决办法

    使用,我将使用带有回调的消息传递来发送消息,并允许任意数量的订阅者取消回调

    public class AccountSelectedMessage : NotificationMessageAction<bool>
    {
        public AccountSelectedMessage(Account selectedAccount, Action<bool> callback) : base("AccountSelectedWithCancelCallback", callback)
        {
            SelectedAccount = selectedAccount;
        }
        public AccountSelectedMessage(object sender, Account selectedAccount, Action<bool> callback) : base(sender, "AccountSelectedWithCancelCallback", callback)
        {
            SelectedAccount = selectedAccount;
        }
        public AccountSelectedMessage(object sender, object target, Account selectedAccount, Action<bool> callback) : base(sender, target, "AccountSelectedWithCancelCallback", callback)
        {
            SelectedAccount = selectedAccount;
        }
    
        public Account SelectedAccount { get; private set; }
    }
    
    public class AccountListViewModel : ViewModelBase
    {
        public RelayCommand<Account> AccountSelectedCommand = new RelayCommand<Account>(AccountSelectedCommandExecute);
    
        private void AccountSelectedCommandExecute(Account selectedAccount)
        {
            MessengerInstance.Send(new AccountSelectedMessage(this, AccountSelectionCanceled));
        }
    
        private void AccountSelectionCanceled(bool canceled)
        {
            if (canceled)
            {
                // cancel logic here
            }
        }
    }
    
    public class SomeOtherViewModel : ViewModelBase
    {
        public SomeOtherViewModel()
        {
            MessengerInstance.Register<AccountSelectedMessage>(this, AccountSelectedMessageReceived);
        }
    
        private void AccountSelectedMessageReceived(AccountSelectedMessage msg)
        {
            bool someReasonToCancel = true;
            msg.Execute(someReasonToCancel);
        }
    }
    
    公共类AccountSelectedMessage:NotificationMessageAction
    {
    public AccountSelectedMessage(Account selectedAccount,Action callback):base(“AccountSelectedWithCancelCallback”,callback)
    {
    SelectedAccount=SelectedAccount;
    }
    公共帐户SelectedMessage(对象发送者、帐户selectedAccount、操作回调):基本(发送者,“AccountSelectedWithCancelCallback”,回调)
    {
    SelectedAccount=SelectedAccount;
    }
    公共帐户SelectedMessage(对象发送者、对象目标、帐户selectedAccount、操作回调):基本(发送者、目标,“AccountSelectedWithCancelCallback”,回调)
    {
    SelectedAccount=SelectedAccount;
    }
    公共帐户所选帐户{get;private set;}
    }
    公共类AccountListViewModel:ViewModelBase
    {
    public RelayCommand AccountSelectedCommand=new RelayCommand(AccountSelectedCommandExecute);
    私有无效帐户SelectedCommandExecute(帐户selectedAccount)
    {
    Send(新AccountSelectedMessage(此,AccountSelectionCancelled));
    }
    私人作废帐户选择已取消(bool已取消)
    {
    如果(取消)
    {
    //在这里取消逻辑
    }
    }
    }
    公共类SomeOtherViewModel:ViewModelBase
    {
    公共SomeOtherViewModel()
    {
    Register(此,AccountSelectedMessageReceived);
    }
    私有无效AccountSelectedMessageReceived(AccountSelectedMessage消息)
    {
    bool someReasonToCancel=true;
    msg.Execute(someReasonToCancel);
    }
    }
    

    如您所见,此过程需要是异步的,并考虑到您不知道有多少邮件收件人可以取消,或者他们需要多长时间才能做出响应。

    一个EventAggregator是一个不错的选择。我们用的是Prism的。但我们并没有把所有的棱镜都拿走。只有与EventAggregator相关的类。我们确实为GUI引用不可用的服务层程序集创建了DomainEvent