2017-02-13 6 views
1

Я использую 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); 
     } 
    } 
} 

ViewModel:

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 
    } 
} 
+0

Используйте [асинхронный/ждать] (https://msdn.microsoft.com/en-us/library/mt674882.aspx) в модели и модели представления. – Clemens

+0

@Clemens Вы можете мне привести пример по коду выше –

+0

Извините, вы могли бы легко сделать это самостоятельно после прочтения искусства, с которым я связался. – Clemens

ответ

3

Реализовать INotifyPropertyChanged в модели представления, что является распространенным способом обновить вид при изменении данных. Он отлично работает с привязками (я думаю, что можно использовать ItemsControl с Canvas в качестве панели для отображения результатов расчета без кода).

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")); 
    } 
} 
+0

Хорошо, но чем я должен привязываться к 'CalcValues' в коде позади от представления, так что можно рисовать значения и т. Д. - это то, что вы имели в виду? –

+1

@KevinWallis, я имел в виду smth, как '' в xaml, а не в коде; и ItemsControl + Canvas показано здесь: http://stackoverflow.com/questions/1265364/setting-canvas-properties-in-an-itemscontrol-datatemplate. Вы также можете продолжить работу с подходом к коду, но вместо «Рассчитанного» события подписаться на «PropertyChanged» – ASh

+0

Thx для подсказок! –