【问题标题】:Pattern for delegating events委派事件的模式
【发布时间】:2017-02-13 08:56:13
【问题描述】:

我将 MVVM 用于桌面应用程序。我有一个名为Calculator 的模型,它在自己的线程中进行非常昂贵的计算。 MainViewModel 引用 Calculator 并使用计算结果。视图获取结果并显示它们。

问题是,Calculator 使用事件返回计算结果。而且我不想将视图绑定到来自Calculator 的事件,因为使用的Calculator 可以在运行时更改。作为解决方案,我两次使用了相同的事件,我不喜欢,有更好的方法。

型号:

public class Calculator
{
    public event CalculatedHandler Calculated;
    public delegate void CalculatedHandler(object sender, IEnumerable<string> values);

    protected void OnCalculated(IEnumerable<string> values)
    {
        Calculated?.Invoke(this, values);
    }

    public void Run()
    {
        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += new DoWorkEventHandler(Calculate);
    }

    private void Calculate(object sender, DoWorkEventArgs e)
    {
        List<string> values = new List<string>();
        for (int i = 0; i < 10000; i++)
        {
            // Do expensive stuff
            values.Add(i + "");
            OnCalculated(values);
        }
    }
}

视图模型:

public class CalculatorViewModel
{
    private Calculator calculator;

    public event CalculatedHandler Calculated;
    public delegate void CalculatedHandler(object sender, IEnumerable<string> values);

    protected void OnCalculated(IEnumerable<string> values)
    {
        Calculated?.Invoke(this, values);
    }

    public CalculatorViewModel()
    {
        calculator = new Calculator();
        calculator.Calculated += Calculator_Calculated;
    }

    private void Calculator_Calculated(object sender, IEnumerable<string> values)
    {
        OnCalculated(values);
    }
}

查看 XAML:

<Window.DataContext>
    <viewmodels:CalculatorViewModel />
</Window.DataContext>

查看后面的代码:

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

        DataContextChanged += MainWindow_DataContextChanged;
    }

    private void MainWindow_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        CalculatorViewModel viewModel = e.NewValue as CalculatorViewModel;

        viewModel.Calculated += ViewModel_Calculated;
    }

    private void ViewModel_Calculated(object sender, IEnumerable<string> values)
    {
        // Draw values on the canvas
    }
}

【问题讨论】:

  • 在您的模型和视图模型中使用async/await
  • @Clemens 你能给我一个上面代码的例子吗
  • 抱歉,您可以在阅读我链接的文章后自己轻松完成。
  • 如果你的 VM 上没有 INPC 接口,你就不是真正在做 MVVM。
  • @HenkHolterman 抱歉,上面的代码只是一个小例子——原始代码确实包含 INPC

标签: c# wpf events design-patterns mvvm


【解决方案1】:

在视图模型中实现INotifyPropertyChanged,这是数据变化时更新视图的常用方法。它可以与绑定一起正常工作(我认为可以使用ItemsControlCanvas 作为其面板来显示计算结果而无需代码隐藏)。

public class CalculatorViewModel: INotifyPropertyChanged
{
    private Calculator calculator;

    public event PropertyChangedEventHandler PropertyChanged;

    public IEnumerable<string> CalcValues { get; set; }

    public CalculatorViewModel()
    {
        calculator = new Calculator();
        calculator.Calculated += Calculator_Calculated;
    }

    private void Calculator_Calculated(object sender, IEnumerable<string> values)
    {
        CalcValues = values;
        PropertyChanged?.(this, new PropertyChangedEventArgs("CalcValues"));
    }
}

【讨论】:

  • 好的,但是我必须在视图后面的代码中绑定CalcValues,以便绘制值等 - 这是你的意思吗?跨度>
  • @KevinWallis,我想到的是 xaml 中的 &lt;ItemsControl ItemsSource="{Binding Path=CalcValues}"&gt;,而不是代码隐藏;和 ItemsControl + Canvas 组合显示在此处:stackoverflow.com/questions/1265364/…。您也可以继续使用代码隐藏方法,但不是 Calculated 事件订阅 PropertyChanged
  • 感谢提示!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
相关资源
最近更新 更多