设置:带有进度条和标签的主MDI表单。
主要表单中的代码。
public delegate void UpdateMainProgressDelegate(string message, bool isProgressBarStopped);
private void UpdateMainProgress(string message, bool isProgressBarStopped)
{
// make sure we are running on the right thread to be
// updating this form's controls.
if (InvokeRequired == false)
{
// we are running on the right thread. Have your way with me!
bsStatusMessage.Caption = message + " [ " + System.DateTime.Now.ToShortTimeString() + " ]";
progressBarStatus.Stopped = isProgressBarStopped;
}
else
{
// we are running on the wrong thread.
// Transfer control to the correct thread!
Invoke(new ApplicationLevelValues.UpdateMainProgressDelegate(UpdateMainProgress), message, isProgressBarStopped);
}
}
儿童表格
private readonly ApplicationLevelValues.UpdateMainProgressDelegate _UpdateMainForm;
private void btnX_Click(object sender, EventArgs e)
{
_UpdateMainForm.BeginInvoke("StartA", false, null, null);
try
{
if(UpdateOperationA())
{ _UpdateMainForm.BeginInvoke("CompletedA", true, null, null); }
else
{ _UpdateMainForm.BeginInvoke("CanceledA", true, null, null); }
}
catch (System.Exception ex)
{
_UpdateMainForm.BeginInvoke("ErrorA", true, null, null);
throw ex;
}
}
它的工作非常好,但是对于N个按钮或N个操作,我必须一次又一次地编写相同的代码。有没有什么方法可以推广或更新UI的任何其他更好的方法。
答案 0 :(得分:4)
如果您的操作都可以表示为单个委托类型,那么这实际上只是一个简单的重构问题。 e.g:
private void RunOperationWithMainProgressFeedback(
Func<bool> operation,
string startMessage,
string completionMessage,
string cancellationMessage,
string errorMessage)
{
this._UpdateMainForm.BeginInvoke(startMessage, false, null, null);
try
{
if (operation.Invoke())
{
this._UpdateMainForm.BeginInvoke(completionMessage, true, null, null);
}
else
{
this._UpdateMainForm.BeginInvoke(cancellationMessage, true, null, null);
}
}
catch (Exception)
{
this._UpdateMainForm.BeginInvoke(errorMessage, true, null, null);
throw;
}
}
private void btnX_Click(object sender, EventArgs e)
{
this.RunOperationWithMainProgressFeedback(
this.UpdateOperationA,
"StartA",
"CompletedA",
"CanceledA",
"ErrorA");
}
虽然可以使用字典存储参数值(如VinayC早期的答案中所述),但这不是必需的。就个人而言,我会因为可读性和性能原因而避免使用它,但是ymmv ......
答案 1 :(得分:2)
您可以创建一个字典/列表,其中包含每个按钮的相关详细信息。这些细节将包括操作名称和委托调用操作等。现在,您可以为所有按钮设置通用事件处理程序,这些按钮将查找字典以获取要执行的操作名称和操作。
另一种方法是创建从按钮继承的自定义按钮,自定义按钮可以具有这些属性来保存上述细节。根据自己的喜好选择。
答案 2 :(得分:1)
我厌倦了一遍又一遍地解决这个完全相同的问题,所以我写了一套通用的类来解决这个问题。基本思路是:
使用您关注的字段创建一个抽象的Progress对象,例如statusMessage。
创建一个抽象的Job对象。 Job就像一个线程,但除了Main和Start之外,它还有一个方法UpdateProgress(Progress p)。 UpdateProgress将当前进度复制到p。它通常是唯一可以获得锁的地方。
在您的特定用法中,子类Progress并根据需要添加字段。然后继承Job来保存你想要做的东西,并实现UpdateProgress。
在UI中,创建一个主调用作业的计时器。 UpdateProgress然后更新ui。
通常,定时器对于ui更新来说已经足够了,并且采用pull-and-sync-ui模型比执行推送更改模型更简单。 Pull-and-sync-ui避免了很多交叉线程问题,并且让UI进入了奇怪的状态。
BONUS:让您的Progress对象成为INotifyProperyChanged并进行数据绑定。 (这就是你可能不想使用IDictionary的原因。)