【问题标题】:How to handle events that happened on different page如何处理不同页面上发生的事件
【发布时间】:2020-12-12 23:33:43
【问题描述】:

到目前为止,我有一个包含 2 页的 UWP 项目。 MainPage.xaml 是应用程序的基本布局(汉堡菜单、搜索栏等)。此 MainPage 的另一部分包含一个框架,另一个页面 LandingPage.xaml 加载到该框架中。我想从 MainPage.xaml 中的 AutosuggestBox 捕获用户输入,并在 LandingPage.xaml 上显示结果(位于 MainPage.xaml 内的框架中)。

我尝试继承 MainPage,但这是不允许的。

【问题讨论】:

  • 你在使用 MVVM 吗?

标签: c# xaml uwp


【解决方案1】:

虽然玛丽安的回答肯定会奏效,但我认为它远非“干净”或“好”的代码。

首先,你应该在你的 UWP 应用中实现 MVVM 模式(如果你还没有这样做的话)并为此使用依赖注入框架。一个非常基本且易于理解的框架是 MVVMLight,而更复杂的框架选择可能是 Autofac。我建议你从前者开始,先把头绕起来要快得多。

在 MVVM 中,有一个概念可以解决您的问题:信使。我不想在这里详细介绍,因为已经有很多非常好的资源,这些资源都是由比我聪明得多的人写的。例如 MVVMLight 的作者本人的这篇文章:https://msdn.microsoft.com/en-us/magazine/jj694937.aspx(我知道它是 2013 年的,谈论的是 Windows 8,但不要害怕,概念是一样的。)

这个想法是,不同的 ViewModel 之间不应该有严格的依赖关系——它使单元测试(这是首先进行 MVVM 的主要点之一)变得困难。因此,在您的情况下,您应该有两个 ViewModel:MainViewModel 和 LandingViewModel。一个用于 MainPage,一个用于 LandingPage。现在您应该在 MainPage 的代码隐藏中为 AutoSuggestBox 的 QuerySubmitted 事件实现一个处理程序,并在 MainViewModel 中调用一个函数。在该函数中,您将使用来自 AutoSuggestBox 的字符串实例化一条新消息(您可以通过对其进行数据绑定或通过 QuerySubmitted 的事件处理程序获取,这取决于您)并通过 Messenger 发送。在 LandingViewModel 中,您将订阅此确切消息,然后通过 LandingPage 上的数据绑定再次显示接收到的消息只需几行。

我知道像这样非常基本的东西看起来很麻烦,特别是如果你将它与玛丽安的直截了当的解决方案进行比较。但相信我,从长远来看,编写干净的代码、很好地分离、易于单元测试的 ViewModel 将弥补您最初为使它们工作而必须投入的额外努力。在两个 ViewModel 之间建立这样的系统后,添加第三个(我假设您很快需要这样做)绝对是微不足道的,并且可以很快完成。

【讨论】:

  • 完全不同意。 MVVM 是一个流行词,虽然在很多情况下它都有其优势,但同样有很多——较小的项目,而不是团队中的项目等——它只会引入很多不必要的复杂性。即使在这些情况下,也有其他方法可以提供必要的分离,而不会产生 MVVM 的额外抽象。特别是如果您还建议完整的框架。一切看起来都像钉子的经典例子......
  • 我大体上同意你的观点,但根据我的经验,如果你比 Visual Studio 中的模板项目更进一步,开发一个没有 MVVM 模式的基于 XAML 的应用程序会很快变得很痛苦。最重要的是,我在这个(现在 3 岁)答案中建议的框架是/是一个非常准系统的框架。除了正确的单元测试(DI、IoC)、ViewModel 基类和 Messenger 实现所需的最低代码之外,它确实没有太多其他内容。我认为这与 UWP 的“引入许多不必要的复杂性”相去甚远。
【解决方案2】:

如果您不使用 MVVM,我建议在 AutoSuggestBox 上添加 x:FieldModifier="public",并向 MainPage 添加一个公共静态属性以存储其实例。

MainPage.xaml.cs

public static MainPage Current { get; private set; }

public MainPage()
{
    Current = this;
    // Rest of your code in ctor
}

然后您可以使用它访问它

string text = MainPage.Current.NameOfYourAutoSuggestBox.Text;

【讨论】:

    【解决方案3】:

    只需使用您自己的简单消息传递机制,如下所示:

    public class Messages {
      public static Messages Instance { get; } = new Messages();
    
      private readonly List<Subscription> subscriptions;
    
      private Messages() {
        subscriptions = new List<Subscription>();
      }
    
      public void Send<T>(T message) {
        var msgType = message.GetType();
        foreach (var sub in subscriptions)
          if (sub.Type.IsAssignableFrom(msgType))
            sub.Handle(message);
      }
    
      public Guid Subscribe<T>(Action<T> action) {
        var key = Guid.NewGuid();
        lock (subscriptions) {
          subscriptions.Add(new Subscription(typeof(T), key, action));
        }
        return key;
      }
    
      public void Unsubscribe(Guid key) {
        lock (subscriptions) {
          subscriptions.RemoveAll(sub => sub.Key == key);
        }
      }
    
      public bool IsSubscribed(Guid key) {
        lock (subscriptions) {
          return subscriptions.Any(sub => sub.Key == key);
        }
      }
    
      public void Dispose() {
        subscriptions.Clear();
      }
    }
    
    internal sealed class Subscription {
      internal Guid Key { get; }
      internal Type Type { get; }
      private object Handler { get; }
    
      internal Subscription(Type type, Guid key, object handler) {
        Type = type;
        Key = key;
        Handler = handler;
      }
    
      internal void Handle<T>(T message) {
        ((Action<T>)Handler).Invoke(message);
      }
    }
    

    它小而简单,但它允许并行订阅不同的消息,按消息类型分隔。在与您类似的情况下,您可以通过以下方式订阅:

    Messages.Instance.Subscribe<TextChangeArgs>(OnTextChanged);
    

    您的其他页面可以使用以下方式发送消息:

    Messages.Instance.Send(new TextChangeArgs(...));
    

    从所有订阅者中,只有对这种特定消息类型感兴趣的人才能收到消息。您可以(当然也应该)取消订阅。在现实世界的场景中,可能还需要更多的错误处理。

    如有必要,您可以轻松添加限制等额外功能(以避免在给定时间段内出现过多连续消息)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-20
      • 2019-11-11
      • 1970-01-01
      相关资源
      最近更新 更多