4

除非某些条件为真 (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 方法使用相同的模式。我希望我不必ElapsedEventHandler为每个 Item_Click 方法创建一个。

4

3 回答 3

2

使用匿名 lambda 表达式:

WaitForDataLoading((s,e) => FirstMenuItem_Click(null, null));
于 2013-05-23T12:47:10.650 回答
0

Dispatcher根据您对该类的使用,您似乎正在使用 WPF 。在这种情况下,您可以使用更好的方法来控制对 UI 的访问。

其中两个是:

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

  2. 使用 anICommand来驱动菜单的行为。该命令在您的长时间运行的作业处于活动状态时CanExecute返回false,这将导致菜单自动禁用,直到作业完成。

值得注意的是,这会巧妙地改变菜单的行为——但我认为不会以一种糟糕的方式。您当前的代码将在显示对话框之前等待作业完成 - 但在此期间没有什么可以阻止用户再次单击菜单。这些多次单击将分别等待作业完成,并在作业完成时显示各自的对话框。在一个微不足道的情况下,这可能意味着我看到多个对话框出现;在严重的情况下,您创建的多个计时器可能会严重影响应用程序的性能。

上面建议的任何一种方法都会阻止在作业运行时单击菜单,这不是您当前的行为,但我认为从可用性的角度来看会更有意义。

于 2013-05-23T12:52:49.210 回答
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();
        }));
    }
}

更新

如果您可以编辑数据存储库的代码,则应在数据加载完成时添加一个事件。

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();
    }));
}
于 2013-05-23T12:43:34.207 回答