我的应用程序无法访问特定的菜单项,除非某些条件为真(DataRepository.IsAllDataLoaded)。我想出了这个代码,效果很好。它首先检查条件。如果它没有准备好,它会调用一个计时器,它等待几毫秒并再次调用相同的方法。 Timer需要一个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
。
答案 0 :(得分:2)
使用匿名lambda表达式:
WaitForDataLoading((s,e) => FirstMenuItem_Click(null, null));
答案 1 :(得分:0)
在以下代码中,您可以在数据准备就绪时随时调用窗口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();
}));
}
}
<强>更新强>
如果您可以编辑datarepository的代码,则应该在数据加载完成时添加一个事件。
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();
}));
}
答案 2 :(得分:0)
您似乎使用WPF,基于您对Dispatcher
类的使用。在这种情况下,您可以通过更好的方式控制对UI的访问。
其中两个是:
将菜单的Enabled
属性绑定到ViewModel
类,该类具有指示菜单是否可用的属性。当您的长期作业完成后,将该属性设置为true
并启用菜单。
使用ICommand
来推动菜单的行为。在长时间运行的作业处于活动状态时,命令CanExecute
返回false
,这将导致菜单在作业完成之前自动禁用。
值得注意的是,这会巧妙地改变菜单的行为 - 但我认为,这并不是很糟糕。您的当前代码将在显示对话框之前等待作业完成 - 但在此期间没有任何内容可以阻止用户再次单击该菜单。这些多次单击将等待作业完成,并且每个作业完成时都会显示自己的对话框。在一个微不足道的情况下,这可能意味着我看到多个对话框出现;在严重的情况下,您正在创建的多个计时器可能会严重影响应用程序的性能。
上面提到的任何一种方法都会阻止在作业运行时点击菜单,这不是你当前的行为,但我认为从可用性的角度来看会更有意义。