Avoiding copying / pasting many event handlers

My application cannot access a specific menu item unless a condition is met (DataRepository.IsAllDataLoaded). I came up with this code that works great. First, he checks the status. If it is not ready, it calls a timer that waits a few milliseconds and calls the same method again. A timer needs an 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(); } 

Initially, the only way was FirstMenuItem_Click . I had to add a FirstTimedEvent handler for my timer. Is there a way to avoid creating an ElapsedEventHandler ? Can I create it inline in my FirstMenuItem_Click method?

Now I have to use the same template for many other Item_Click methods. I'm sorry that I do not need to create an ElapsedEventHandler for each Item_Click method.

+4
source share
3 answers

Use the anonymous lambda expression:

 WaitForDataLoading((s,e) => FirstMenuItem_Click(null, null)); 
+2
source

In the following code, you can call the CheckDataShowWindow() method anytime you want to show windows when the data is ready. If you want to add it to another cick handler, you can just do something else like this:

 public void Another_Click(object sender, RoutedEventArgs e) { CheckDataShowWindow(); } 

Main code :

 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(); })); } } 

Update

If you can edit the data warehouse code, you must add an event to load the data.

 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()); } } 

Now in your other class:

 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(); })); } 
0
source

You seem to be using WPF based on using the Dispatcher class. In this case, there are more convenient means for controlling access to the user interface.

Two of them:

  • bind your Enabled menu to the ViewModel class, which will have the property to indicate whether the menu should be accessible. When your long task is completed, set this property to true and the menu will be turned on.

  • use ICommand to control the behavior of your menu. The CanExecute command returns false while your lengthy job is active, which will automatically turn off the menu before the job completes.

It is worth noting that this will subtly change the behavior of your menu - but not, I think, badly. Your current code will wait for the task to complete before displaying a dialog, but there is nothing to do so that the user clicks on the menu again. These multiple clicks will wait for the task to complete, and each of them will display its own dialog when the task is completed. In the trivial case, this may mean that I see several dialogues; in a difficult case, several timers you create can greatly affect application performance.

Any of the methods proposed above will not allow you to click the menu during the task, which is not exactly your current behavior, but, I think, will make more sense in terms of ease of use.

0
source

Source: https://habr.com/ru/post/1482386/


All Articles