ay wpf in net6 第5天 - 引入CommunityToolkitMvvm 8.0 RequestMessage和CollectionRequestMessage

11 篇文章 0 订阅

由于8.0预览版有些重名的bug,提示波浪,说二重性的错误CS0229

image.png

可空类型警告

image.png

消息实例的另一个有用特性是它们也可以用于从一个模块向另一个模块请求值。 为了做到这一点,该包包含一个基本的 RequestMessage<T> 类,可以像这样使用它:

场景: 以前的send 都是没有返回值的,现在如果需要返回值,你的消息就要继承RequestMessage<T> 其中的T就是返回的值的类型

比如我们注册了一个消息,返回一个Teacher

我们需要定义消息体Teacher,然后用TeacherRequestMessage : RequestMessage<Teacher> 包装下

   public class Teacher
    {
        public string TeacherName { get; set; }
    }
    public class TeacherRequestMessage : RequestMessage<Teacher>
    {

    }

接下来注册消息有点不一样

打开twowindowviewmodel.cs

     public partial class TwoWindowViewModel : ObservableRecipient
    {
        protected override void OnActivated()
        {
            WeakReferenceMessenger.Default.Register<ShowLoginMessage>(this, (r, m) =>
            {
                InputCode = m.LoginName;
            });
            WeakReferenceMessenger.Default.Register<ShowLoginMessage, string>(this, "TwoWindowViewModel_show1", (r, m) =>
            {
                InputCode = "当前登陆:" + m.LoginName;
            });
            WeakReferenceMessenger.Default.Register<ShowLoginMessage, string>(this, "TwoWindowViewModel_show2", (r, m) =>
            {
                InputCode = "当前2登陆:" + m.LoginName;
            });


            WeakReferenceMessenger.Default.Register<TwoWindowViewModel, TeacherRequestMessage>(this, (r, m) =>
            {
                m.Reply(new Teacher { TeacherName = "杨老师" });
            });

            WeakReferenceMessenger.Default.Register<TwoWindowViewModel, TeacherRequestMessage,string>(this,"returnTeacher", (r, m) =>
            {
                m.Reply(new Teacher { TeacherName = "杨老师带token的" });
            });

        }

接下来send,在MainWindow里新增2个按钮,一个不带token的,一个调用带token的

        private void Show7_Click(object sender, RoutedEventArgs e)
        {
            Teacher teacher = WeakReferenceMessenger.Default.Send<TeacherRequestMessage>();
            MessageBox.Show(teacher.TeacherName);
        }
        private void Show8_Click(object sender, RoutedEventArgs e)
        {
            //Teacher teacher = WeakReferenceMessenger.Default.Send<TeacherRequestMessage,string>(new TeacherRequestMessage(), "returnTeacher");
            Teacher teacher = WeakReferenceMessenger.Default.Send(new TeacherRequestMessage(), "returnTeacher");
            MessageBox.Show(teacher.TeacherName);
        }

这里要注意一个异常,当twowindow窗体没打开,send带返回值的,会报异常,所以这里要判断下消息是否注册了,还有个事,

通过这个判断

   WeakReferenceMessenger.Default.IsRegistered

先显示窗体,消息被注册了,单击 获取值的消息按钮,正常,然后关闭了TwoWindow后,消息竟然还能send

不过弱引用的,内存应该会回收的,为了防止泄露,我手动unload取消注册所有消息

由于注册是在ViewModel注册是在vm注册的,所以只能vm取消了,我尝试如下成功

using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace AyWpfNet6
{
    /// <summary>
    /// TwoWindow.xaml 的交互逻辑
    /// </summary>
    public partial class TwoWindow : Window
    {
        public TwoWindow(ILogger<TwoWindow> logger)
        {
            InitializeComponent();
            this.Unloaded += TwoWindow_Unloaded;
        }

        private void TwoWindow_Unloaded(object sender, RoutedEventArgs e)
        {
            this.Unloaded -= TwoWindow_Unloaded;
            WeakReferenceMessenger.Default.Send("1","unregistertwowindow");
        }
    }
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AyWpfNet6.ViewModels
{
    public class Teacher
    {
        public string TeacherName { get; set; }
    }
    public class TeacherRequestMessage : RequestMessage<Teacher>
    {

    }
    public partial class TwoWindowViewModel : ObservableRecipient
    {
        protected override void OnActivated()
        {
            WeakReferenceMessenger.Default.Register<ShowLoginMessage>(this, (r, m) =>
            {
                InputCode = m.LoginName;
            });
            WeakReferenceMessenger.Default.Register<ShowLoginMessage, string>(this, "TwoWindowViewModel_show1", (r, m) =>
            {
                InputCode = "当前登陆:" + m.LoginName;
            });
            WeakReferenceMessenger.Default.Register<ShowLoginMessage, string>(this, "TwoWindowViewModel_show2", (r, m) =>
            {
                InputCode = "当前2登陆:" + m.LoginName;
            });


            WeakReferenceMessenger.Default.Register<TwoWindowViewModel, TeacherRequestMessage>(this, (r, m) =>
            {
                m.Reply(new Teacher { TeacherName = "杨老师" });
            });

            WeakReferenceMessenger.Default.Register<TwoWindowViewModel, TeacherRequestMessage,string>(this,"returnTeacher", (r, m) =>
            {
                m.Reply(new Teacher { TeacherName = "杨老师带token的" });
            });

            WeakReferenceMessenger.Default.Register<string, string>(this, "unregistertwowindow", (r, m) =>
            {
                this.IsActive = false;
            });
        }

        protected override void OnDeactivated()
        {
            base.OnDeactivated();
            //WeakReferenceMessenger.Default.Unregister<ShowLoginMessage>(this);
            WeakReferenceMessenger.Default.UnregisterAll(this);
        }


        // Register that specific message...
        //WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this);

         ...or alternatively, register all declared handlers
        //WeakReferenceMessenger.Default.RegisterAll(this);

         Send a message from some other module
        //WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));


         Unregisters the recipient from a message type
        //WeakReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage>(this);

         Unregisters the recipient from a message type in a specified channel
        //WeakReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage, int>(this, 42);

         Unregister the recipient from all messages, across all channels
        //WeakReferenceMessenger.Default.UnregisterAll(this);


        [ObservableProperty]
        private string inputCode;


        public TwoWindowViewModel()
        {
            IsActive = true;
        }




        [ICommand]
        public void ShowCode()
        {
            WeakReferenceMessenger.Default.Send<MessageBase>(new MessageBase { Code = "AY1991来自TwoWindowViewModel", Value = "来自twowindow" });
        }




    }
}

image.png

设置了IsActive=false后,会触发Deactivated事件,此时就取消注册了

一般来说,注册消息,都在xaml.cs中注册

接下来测试带参数的,然后返回值的send

    public class TeacherRequestMessage : RequestMessage<Teacher>
    {
        public string TeacherId { get; set; }
    }
   WeakReferenceMessenger.Default.Register<TwoWindowViewModel, TeacherRequestMessage, string>(this, "returnTeacher", (r, m) =>
            {
                if (m.TeacherId == "1")
                {
                    m.Reply(new Teacher { TeacherName = "杨老师带token的" + "id=1" });
                }
                else
                {
                    m.Reply(new Teacher { TeacherName = "十年老师带token的" + "id=任意" });
                }
            });

MainWindow.xaml.cs

        private void Show8_Click(object sender, RoutedEventArgs e)
        {
            //Teacher teacher = WeakReferenceMessenger.Default.Send<TeacherRequestMessage,string>(new TeacherRequestMessage(), "returnTeacher");
            Teacher teacher = WeakReferenceMessenger.Default.Send(new TeacherRequestMessage { TeacherId="1"}, "returnTeacher");
            MessageBox.Show(teacher.TeacherName);
        }

TeacherId传入1,返回第一个,传入其他的,就是十年老师了

同样的CollectionRequestMessage类型,一次可以返回一个列表,AY通过F12查看类型定义摸索学习的

定义消息体

    public class ModuleMenu
    {
        public string MenuName { get; set; }
        public Action MenuCommand { get; set; }
    }
    public class ModuleMenuCollectionMessage : CollectionRequestMessage<ModuleMenu>
    {
        public string ModuleId { get; set; }
    }

注册消息

  WeakReferenceMessenger.Default.Register<TwoWindowViewModel, ModuleMenuCollectionMessage>(this, (r, m) =>
            {
                if (m.ModuleId == "1")
                {
                    m.Reply(new ModuleMenu { MenuCommand=()=> { },MenuName="新建" });
                    m.Reply(new ModuleMenu { MenuCommand = () => { }, MenuName = "保存" });
                    m.Reply(new ModuleMenu { MenuCommand = () => { }, MenuName = "关闭" });
                }
                else
                {
                    m.Reply(new ModuleMenu { MenuCommand = () => { }, MenuName = "帮助" });
                    m.Reply(new ModuleMenu { MenuCommand = () => { }, MenuName = "关于" });
                }
            });

根据模块id,返回一个列表

  private void Show9_Click(object sender, RoutedEventArgs e)
        {
            //Teacher teacher = WeakReferenceMessenger.Default.Send<TeacherRequestMessage,string>(new TeacherRequestMessage(), "returnTeacher");
            var module = WeakReferenceMessenger.Default.Send(new ModuleMenuCollectionMessage { ModuleId = "1" });
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            foreach (var item in module)
            {
                sb.Append(item.MenuName);
            }
            MessageBox.Show(sb.ToString());
        }

效果

image.png

同样的还有异步的两个

image.png

把第二个改成异步的

    public class ModuleMenuCollectionMessage : AsyncCollectionRequestMessage<ModuleMenu>
    {
        public string ModuleId { get; set; }
    }
        private async void Show9_Click(object sender, RoutedEventArgs e)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            await foreach (var item in WeakReferenceMessenger.Default.Send<ModuleMenuCollectionMessage>(new ModuleMenuCollectionMessage { ModuleId = "1" }))
            {
                sb.Append(item.MenuName);
            }

            //CancellationTokenSource cts = new CancellationTokenSource();
            //await foreach (var item in WeakReferenceMessenger.Default.Send<ModuleMenuCollectionMessage>(new ModuleMenuCollectionMessage { ModuleId = "1" }).WithCancellation(cts.Token))
            //{
            //    sb.Append(item.MenuName);
            //}
            MessageBox.Show(sb.ToString());
        }

你也可以这样调用

           var response= await WeakReferenceMessenger.Default.Send<ModuleMenuCollectionMessage>(new ModuleMenuCollectionMessage { ModuleId = "1" }).GetResponsesAsync();
            foreach (var item in response)
            {
                sb.Append(item.MenuName);
            }

其他的不变,如果取消参考下面的注释的,关于Cancel的用法,参考CancellationTokenSource.Cancel Method (System.Threading) | Microsoft Docs

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值