C# 如何避免复制/粘贴多个事件处理程序
除非某些条件为真(DataRepository.IsAllDataLoaded),否则我的应用程序无法访问特定的菜单项。我想出了这个代码,它非常有效。它首先检查情况。如果还没有准备好,它将调用一个计时器,该计时器将等待几毫秒,然后再次调用相同的方法。计时器需要一个延时器C# 如何避免复制/粘贴多个事件处理程序,c#,events,C#,Events,除非某些条件为真(DataRepository.IsAllDataLoaded),否则我的应用程序无法访问特定的菜单项。我想出了这个代码,它非常有效。它首先检查情况。如果还没有准备好,它将调用一个计时器,该计时器将等待几毫秒,然后再次调用相同的方法。计时器需要一个延时器 public void FirstMenuItem_Click(object sender, RoutedEventArgs e) { if (!DataRepository.IsAllDataLoaded) {
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
if (!DataRepository.IsAllDataLoaded)
{
WaitForDataLoading(FirstTimedEvent);
}
else
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}
}
private void FirstTimedEvent(object source, ElapsedEventArgs e)
{
FirstMenuItem_Click(null, null);
}
private static void WaitForDataLoading(ElapsedEventHandler timerEvent)
{
Timer t = new Timer();
t.Interval = 0.2;
t.AutoReset = false;
t.Elapsed += new ElapsedEventHandler(timerEvent);
t.Start();
}
最初,单击第一个菜单项是唯一的方法。我必须为计时器添加FirstTimedEvent
处理程序。有没有办法避免创建ElapsedEventHandler
?我可以在我的FirstMenuItem\u Click
方法中内联创建它吗
现在,我必须对许多其他单击项目的方法使用相同的模式。我希望我不必为每个项目创建一个
ElapsedEventHandler
_Click方法。在下面的代码中,您可以在数据准备好后随时调用方法CheckDataShowWindow()
。如果要将其添加到另一个cick处理程序中,只需将另一个类似于:
public void Another_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
主代码:
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
private void CheckDataShowWindow()
{
if (!DataRepository.IsAllDataLoaded)
{
Timer t = new Timer();
t.Interval = 0.2;
t.AutoReset = false;
t.Elapsed += (s,e) => CheckDataShowWindow();
t.Start();
}
else
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}
}
更新
如果可以编辑数据存储库的代码,则应在数据加载完成时添加事件
public delegate void DoneLoadingHandler(object sender, EventArgs e);
public class DataRepository
{
public event DoneLoadingHandler DoneLoading;
//Your loading function
private void LoadAllData()
{
//Load like you do now
//Now fire the event that loading is done.
if(DoneLoading != null)
DoneLoading(this, new EventArgs());
}
}
现在在另一节课上:
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
private bool AllReadyWaiting = false;
private void CheckDataShowWindow()
{
if (!DataRepository.IsAllDataLoaded)
{
if(!AllReadyWaiting)
{
DataRepository.DoneLoading += (s,e) => ShowWindow();
AllReadyWaiting = true;
}
}
else
{
ShowWindow();
}
}
private void ShowWindow()
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}
使用匿名lambda表达式:
WaitForDataLoading((s,e) => FirstMenuItem_Click(null, null));
根据您对
Dispatcher
类的使用情况,您似乎正在使用WPF。在这种情况下,有更好的方法来控制对UI的访问
其中两项是:
Enabled
属性绑定到ViewModel
类,该类将有一个属性来指示菜单是否可用。长时间运行的作业完成后,将属性设置为true
,菜单将启用ICommand
驱动菜单的行为。在长时间运行的作业处于活动状态时,命令的CanExecute
返回false
,这将导致菜单自动禁用,直到作业完成上面建议的任何一种方法都可以防止在作业运行时单击菜单,这与您当前的行为不太一样,但我认为,从可用性角度来看,这更有意义。可能禁用
FirstMenuItem
,直到DataRepository.IsAllDataLoaded
为真。如果您担心混淆,请向FirstMenuItem
引用的控件添加一点IsBusy
指示符,而DataRepository.IsAllDataLoaded
保持为false。发送一个进程,在它等待数据时只旋转一个静态时间间隔,这是一个棘手的问题。所有这一切的目标是保持菜单始终处于启用状态,给人一种软件准备就绪的印象,即使它没有准备就绪。谢谢你的意见!我想这回答了他关于创建与此方法内联的计时器的问题,但它并没有真正触及问题的根源。让计时器等待数据是一种等待某些事情完成的糟糕方法。请看我上面的评论。@tnw给出了一个包含事件的答案。太简单了。这就是我一直在寻找的。要求是菜单应该一直处于启用状态,即使这会让用户在单击后不得不等待。