如何避免复制/粘贴多个事件处理程序
本文关键字:事件处理 程序 何避免 复制 | 更新日期: 2023-09-27 18:14:56
除非某些条件为true(DataRepository.IsAllDataLoaded(,否则我的应用程序无法访问特定的菜单项。它首先检查状况。如果它还没有准备好,它会调用一个计时器,等待几毫秒,然后再次调用相同的方法。计时器需要一个ElapsedEventHandler。
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();
}
最初,FirstMenuItem_Click
是唯一的方法。我不得不为我的计时器添加FirstTimedEvent
处理程序。有没有办法避免创建ElapsedEventHandler
?我可以在FirstMenuItem_Click
方法中内联创建它吗?
我现在不得不对许多其他Item_Click方法使用相同的模式。我希望不必为每个Item_Click方法创建ElapsedEventHandler
。
使用匿名lambda表达式:
WaitForDataLoading((s,e) => FirstMenuItem_Click(null, null));
根据您对Dispatcher
类的使用,您似乎在使用WPF。在这种情况下,有更好的方法可以控制对UI的访问。
其中两个是:
-
将菜单的
Enabled
属性绑定到ViewModel
类,该类将具有一个指示菜单是否可用的属性。当长时间运行的作业完成后,将属性设置为true
,菜单将被启用。 -
使用
ICommand
来驱动菜单的行为。当长时间运行的作业处于活动状态时,命令的CanExecute
将返回false
,这将导致菜单自动禁用,直到作业完成。
值得注意的是,这会微妙地改变你菜单的行为,但我认为不会以糟糕的方式。您当前的代码将等待作业完成后再显示对话框,但在此期间,没有什么可以阻止用户再次单击菜单。这些多次单击将分别等待作业完成,并在作业完成时显示各自的对话框。在一个琐碎的情况下,这可能意味着我看到多个对话框出现;在严重的情况下,您创建的多个计时器可能会严重影响应用程序的性能。
上面建议的任何一种方法都可以防止在作业运行时点击菜单,这不是你目前的行为,但我认为,从可用性的角度来看,这会更有意义。
在下面的代码中,您可以随时调用方法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();
}));
}