如何避免复制/粘贴多个事件处理程序

本文关键字:事件处理 程序 何避免 复制 | 更新日期: 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的访问。

其中两个是:

  1. 将菜单的Enabled属性绑定到ViewModel类,该类将具有一个指示菜单是否可用的属性。当长时间运行的作业完成后,将属性设置为true,菜单将被启用。

  2. 使用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();
    }));
}