【问题标题】:Sending Update Events to Multiple Forms from a different Class - WPF从不同的类向多个表单发送更新事件 - WPF
【发布时间】:2018-05-16 01:53:53
【问题描述】:

结构

我有一个简单的表单,它会触发一个定期检查更新的计时器。在加载时启动的表单的构造函数如下所示:

public MainWindow()
    {
        InitializeComponent();
        otherWindow = new TheOtherWindow();

        if (Meta.hasUpdate)
        {
            updateImage.Source = new BitmapImage(new Uri("/MyProject;component/Images/updateTrue.gif", UriKind.Relative));
        }

        Thread updateMonitor = new Thread(() =>
        {
            UpdateManager updater = new UpdateManager();
            updater.StartUpdateMonitor();
        });

        updateMonitor.IsBackground = true;
        updateMonitor.Start();
    }

Meta 类包含一些非常基本的信息,存储在多个地方引用但有时会更新的各种字符串。其中一个结构是:

class Meta
{
    ...
    private static bool hasUpdate = false;

    public static bool GetHasUpdate()
    {
        return hasUpdate;
    }

    public static void SetHasUpdate(bool value)
    { 
        hasUpdate = value;
    }
}

另一部分是 UpdateManager 类,其中包含一个小例程,用于每 5 分钟检查一次更新。

class UpdateManager
{
    Timer timer;

    public void CheckForUpdates(Object source, ElapsedEventArgs e)
    {

        if (!isUpToDate())
        {
            timer.Stop();
            Meta.SetHasUpdate(true);

            Application.Current.Dispatcher.Invoke(new Action(() =>
            {
                MessageBox.Show("A new update is now available!);
            }));
        }
    }

    public void StartUpdateMonitor()
    {
        float updateInterval = 300000;

        timer = new Timer(updateInterval); // Milliseconds between checks.

        timer.Elapsed += CheckForUpdates;
        timer.AutoReset = true;
        timer.Enabled = true;
    }
}

问题

简而言之,我想在达到 Meta.SetHasUpdate() 时触发一个事件,然后将其广播到应用程序中的所有表单,目的是更改一个小图标以指示更新可用。

我这样做的尝试已经结束,因为我了解到实现 INotifyPropertyChanged 并不能很好地处理静态成员。这是我实现的尝试...

class Meta : INotifyPropertyChanged

{
    ...
    private static bool hasUpdate = true;

    public static bool GetHasUpdate()
    {
        return hasUpdate;
    }

    public static void SetHasUpdate(bool value)
    { 
        hasUpdate = value;
        NotifyPropertyChanged();
    }

    private static void NotifyPropertyChanged()
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(null, new PropertyChangedEventArgs("hasUpdate"));
        }
    }
}

由于这些成员需要从多个表单中读回,所以我不能在不大量传递对象的情况下使它们不是静态的,我不想这样做。

在这种情况下,如何触发多个表单可以从 Meta 类接收的事件?我是否需要考虑不同的结构,还是我误解了 INotifyPropertyChanged?

【问题讨论】:

  • 尝试单例 Meta,使用 Instance 获取对象,并访问其 props。他们可以使用 INotify 或 propdp`s - 如果 propdps 你可以摆脱更新程序,因为他们通过 wpf 的绑定系统将他们的更改推送给绑定到他们的人
  • 静态属性更改是可行的,但它是不同的,您必须正确了解所有细节:stackoverflow.com/a/41823852/424129

标签: c# wpf events inotifypropertychanged


【解决方案1】:

结合大家非常有用的建议,我整理了以下代码。上面是MVVM解决方案,虽然我没有测试。如果你不使用 MVVM,这就是我所做的。

UpdateManager 类是相同的。 Meta 的结构如下:

class Meta 
{
    private static bool hasUpdate = false;
    public static event PropertyChangedEventHandler StaticPropertyChanged;

    public static bool GetHasUpdate()
    {
        return hasUpdate;
    }

    public static void SetHasUpdate(bool value)
    { 
        hasUpdate = value;
        StaticNotifyPropertyChanged();
    }

    private static void StaticNotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
    }
}

然后,对于我想知道这种变化的任何形式,我都会输入以下代码:

public partial class SomeForm : Window
{
    public SomeForm()
    {
        InitializeComponent();

        Meta.StaticPropertyChanged += MethodThatTriggersOnUpdate;
        ...
    }

    private void MethodThatTriggersOnUpdate(object sender, EventArgs e)
    {
        myImage.Dispatcher.BeginInvoke(
            (Action)(() => myImage.Source = new BitmapImage(
            new Uri("/MyProject;component/Images/myNewImage.gif", UriKind.Relative))));
    }
    ...
}

【讨论】:

    【解决方案2】:

    虽然可以有很多方法来解决这个问题,(将您的 Meta 类的 DI 考虑到您的每个页面的 ViewModel 中并对 INPC 做出反应......这将优于单例方法),但要考虑的一种方法是使用消息传递而不是比事件。消息(在大多数 MVVM 框架中提供)是在松散耦合的组件之间进行通信的好方法。如果您利用像 MVVM Light 这样的 MVVM 库,那么这非常容易,因为它包含一个 Messenger 实现。这种方法的主要优点是您希望接收通知的表单不一定需要保留对源的引用,就像您使用基于事件的方法一样。

    只需让所有感兴趣的表单注册一条消息,并在收到时做出相应的反应。

    例如,使用 MVVM Light,我们可以利用在 INPC 属性更新时自动广播消息的优势。

     private bool hasUpdate;
     public bool HasUpdate
     {
        {
            return hasUpdate;
        }
    
        set
        {
            // the last bool param indicates whether or not to broadcast a message to all interested parties. 
            Set(nameof(HasUpdate), ref hasUpdate, value, true);
        }
    }
    

    然后在应用程序的一个完全独立/不相关的部分(通常在 ViewModel 中),我们可以这样做以表明我们对这样的更新感兴趣:

     Messenger.Default.Register<PropertyChangedMessage<bool>>(this, m => ReceiveHasUpdatedMessage(m));
    

    然后在接收 lambda 中:

     private void ReceiveHasUpdatedMessage(PropertyChangedMessage<bool> m)
     {
        // react accordingly.      
     }
    

    这只是 MVVM Light 提供的Messenger 的一个简单用例。您几乎可以做任何您想做的事情。这里的前提是,使用这种方法可以将相关方从需要对发射器的硬引用中解耦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-19
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多