У меня есть вопрос относительно элегантности и лучшей практики на нижеследующем коде. Концепция приложения:Обновление состояния пользовательского интерфейса, когда все методы Async в разных презентаторах завершены
- У меня есть главная форма, которая вызывает пользователь управляет
- Это главная форма имеет контроль прогресса, которые показывают пользователю ход нескольких задач с помощью обработчиков событий, которые прикреплены к элементам управления пользователем при необходимости
- The View (управление пользователя) «ViewPhase1» имеет событие прогресса меняющегося
- Этот взгляд две ведущих
- Каждые из этих предъявителей имеют асинхронные задачи
- Когда задача собирается начать прогресс изменяется
- Когда задача закончилась проверить, если обе задачи были выполнены, и если да прогресс установлен на 100% (сделано)
Потому что у меня есть два разделенных ведущие, которые вызывают методы Async, один из них может завершиться перед другим, поэтому я создал два свойства «DoneTasksWork» в представлении, чтобы иметь возможность в презентаторе, который позволяет узнать, завершены ли задачи каждого презентатора. Если оба варианта завершены, то прогресс в пользовательском интерфейсе устанавливается как 100% (и включает все элементы управления внутри), если прогресс не будет продолжаться по-прежнему.
Это элегантное решение? Думая об этом случае, контроль прогресса только в полном состоянии, когда методы Async в разных классах завершены, могу ли я подойти с другим решением вместо использования логических свойств в качестве флагов?
Спасибо!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Project.Utilities;
namespace Project
{
public partial class ViewPhase1 : UserControl, IViewPhase1Work1, IViewPhase1Work2
{
private PresenterPhase1Work1 _presenterPhase1Work1;
private PresenterPhase1Work2 _presenterPhase1Work2;
public ViewPhase1()
{
InitializeComponent();
_presenterPhase1Work1 = new PresenterPhase1Work1(this);
_presenterPhase1Work2 = new PresenterPhase1Work2(this);
}
/// <summary>
/// This event is listened by form that invokes this user control and updates progress control.
/// </summary>
public event ProgressChangedEventHandler ProgressChangedEvent;
public void OnProgressHandler(object sender, ProgressChangedEventArgs e)
{
this.Invoke((Action)delegate
{
if (this.ProgressChangedEvent != null)
{
ProgressChangedEvent(this, e);
}
});
}
public void ShowException(string exMessage, MessageBoxButtons bts, MessageBoxIcon icon)
{
MessageBox.Show("", exMessage, bts, icon);
}
public DataGridView GridInvoices { get; set; }
public DataGridView GridReceipts { get; set; }
public DataGridView GridProducts { get; set; }
public DataGridView GridCustomers { get; set; }
bool IViewPhase1Work1.DoneTasksWork { get; set; }
bool IViewPhase1Work2.DoneTasksWork { get; set; }
}
public interface IViewProgress
{
event ProgressChangedEventHandler ProgressChangedEvent;
void OnProgressHandler(object sender, ProgressChangedEventArgs e);
}
public interface IViewPhase1Work1 : IViewProgress, IViewException
{
bool DoneTasksWork { get; set; }
DataGridView GridProducts { get; set; }
DataGridView GridCustomers { get; set; }
}
public interface IViewPhase1Work2 : IViewProgress, IViewException
{
bool DoneTasksWork { get; set; }
DataGridView GridInvoices { get; set; }
DataGridView GridReceipts { get; set; }
}
public interface IViewException
{
void ShowException(string exMessage, MessageBoxButtons bts, MessageBoxIcon icon);
}
public class PresenterPhase1Work1
{
private readonly IViewPhase1Work1 _view;
public PresenterPhase1Work1(IViewPhase1Work1 view)
{
_view = view;
GetInformation();
}
private void GetInformation()
{
try
{
var task1 = Task.Run(() => GetDataProducts());
var task2 = Task.Run(() => GetDataCustomers());
Task.WhenAll(task1, task2);
_view.GridProducts.DataSource = task1.Result;
_view.GridCustomers.DataSource = task2.Result;
}
catch (Exception ex)
{
_view.ShowException(ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_view.DoneTasksWork = true;
_view.OnProgressHandler(this, new ProgressChangedEventArgs(_view.DoneTasksWork && _view.DoneTasksWork ? 100 : 50, _view.DoneTasksWork && _view.DoneTasksWork ? "Done" : "Getting data"));
}
}
private async Task<object> GetDataCustomers()
{
return await Util.GetDataCustomerAsync();
}
private async Task<object> GetDataProducts()
{
return await Util.GetDataProductsAsync();
}
}
public class PresenterPhase1Work2
{
private readonly IViewPhase1Work2 _view;
public PresenterPhase1Work2(IViewPhase1Work2 view)
{
_view = view;
GetInformation();
}
private void GetInformation()
{
try
{
var task1 = Task.Run(() => GetDataInvoices());
var task2 = Task.Run(() => GetDataReceipts());
Task.WhenAll(task1, task2);
_view.GridInvoices.DataSource = task1.Result;
_view.GridReceipts.DataSource = task2.Result;
}
catch (Exception ex)
{
_view.ShowException(ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_view.DoneTasksWork = true;
_view.OnProgressHandler(this, new ProgressChangedEventArgs(_view.DoneTasksWork && _view.DoneTasksWork ? 100 : 50, _view.DoneTasksWork && _view.DoneTasksWork ? "Done" : "Getting data"));
}
}
private async Task<object> GetDataInvoices()
{
return await Util.GetDataInvoicesAsync();
}
private async Task<object> GetDataReceipts()
{
return await Util.GetDataReceiptsAsync();
}
}
}
Спасибо! Вы правы в отношении отсутствующих ключевых слов async. также спасибо о WhenAny, не думал об этом решении. Теперь вы упомянули, что метод async вызывается в конструкторе, но в этом случае происходит сбор данных при загрузке формы, что означает, что конструктор формы (view) инициализирует личные поля презентаторов, вызывая конструкторы-докладчики - и там, где вызываются методы сбора данных. Так что в этом случае без взаимодействия с пользователем, кроме открытия формы, я нахожу dificult для использования другого подхода. Еще раз спасибо! – Libas
Не можете ли вы загрузить данные в переопределении 'Form.OnLoad' или' Form.OnShown'? Таким образом, вы можете ждать там ведущего, и пользователю все равно не нужно ничего делать. –
Да, и это была моя первая идея, но конструктор-презентатор по-прежнему вызовет методы асинхронной загрузки данных. Я считаю, что это также падает в плохой практике, о которой вы говорили. – Libas