Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何避免复制/粘贴多个事件处理程序_C#_Events - Fatal编程技术网

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

C# 如何避免复制/粘贴多个事件处理程序,c#,events,C#,Events,除非某些条件为真(DataRepository.IsAllDataLoaded),否则我的应用程序无法访问特定的菜单项。我想出了这个代码,它非常有效。它首先检查情况。如果还没有准备好,它将调用一个计时器,该计时器将等待几毫秒,然后再次调用相同的方法。计时器需要一个延时器 public void FirstMenuItem_Click(object sender, RoutedEventArgs e) { if (!DataRepository.IsAllDataLoaded) {

除非某些条件为真(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给出了一个包含事件的答案。太简单了。这就是我一直在寻找的。要求是菜单应该一直处于启用状态,即使这会让用户在单击后不得不等待。