Disable multiple GUI controls on button click - wpf

I bind DelegateCommands to buttons in the UI.
And I am not using Prism.
Now I want to disable/hide certain controls on the UI when a button is clicked.
Do I have to put the Disable/Hide logic into the execute handler of the DelegateCommand itself?
Special focus here: background Worker thread.
this.MyCommand = new DelegateCommand(MyExecutehandler);
void MyExecutehandler(object obj){
// 1.) disable controls here
// 2.) long running operation on background worker here
// 3.) enable the controls again in the worker_completed handler?
}
The controls would then be disabled/enabled through MVVM.

Special focus here: background Worker thread
So i just make an assumption that you are asking how to modify UI control state from another thread.
Normally we use way below to modify UI thread's control from worker thread
this.Dispatcher.BeginInvoke( <your delegate here>)
But i suspect that you can't do that in background worker thread as 'this' will mostly differ. So you may try this :
button.Dispatcher.BeginInvoke(new Action(()=>
{
//disable button here
}));
It is like worker thread send a message to tell UI thread to run the delegate.
One more thing, normally we disabled a control and re-enable a button after some process to avoid some unnecessary attached event/propertychanged event. So I suspect you may need this:
You can done that by removing event temporarily:
button -= button_click_event
and Re-add event after that
button += button_click_event
Hope this helps.

You can bind visibility property of controls which you want to disable and in MyExecutehandler function set property values to visibility.collapse

Related

GUI of a WPF application is freezing

The Whole GUI is loaded. After clicked on certain button, the GUI is not responsive: any buttons are no response. If I switch to other app and switch back, the GUI is OK immediately.
Behind the clicked button, it is a handle sending requests to back end. I debugged app, and data has always been returned.
Since the app is huge and I'm not familiar with it, I cannot extract a simple model of sending requests and processing data.I wonder possible causes, since I have no idea now.
Best regards,
-----Add More-----
The back end request sending is in a threadpool thread; when getting data, no UI controls are updated directly. Only presenters (view model) are updated, which are binding to UI control.
I think as sa-ddam213 have suggested and I too believe that you are executing a code block in background Thread or Task.
I think problem is that
- On button click, start execution in background.
- You have kept a flag for checking if background process is running for CanExecute() for the Button's Command.
- UI checks CanExecute() for the Button's Command for a while then does not as mentioned in another question here - Is Josh Smith's implementation of the RelayCommand flawed?.
- Process returns in background.
- UI does not knows the background process is completed and as it has stopped checking the CanExecute() for the Button's Command, UI will not come to know itself.. (you need to tell it)
- Therefore UI is not responding but when user will click somewhere in the application or do an in-out as you said, it will back again.
Solution
- By using InvalidateRequerySuggested method you can invoke the command requery on UI thread so UI will recheck the CanExecute() for each Control and/or Button Command.
// Forcing the CommandManager to raise the RequerySuggested event
CommandManager.InvalidateRequerySuggested();
The InvalidateRequerySuggested method forces the CommandManager to raise the RequerySuggested event. The RequerySuggested event informs a command source to query the command it is associated with to determine whether or not the command can execute.
For more refer:
- How does CommandManager.RequerySuggested work?
- MSDN - CommandManager
- MSDN - CommandManager.InvalidateRequerySuggested Method
Its just a wild guess but try dropping the priority of the logic inside your click event
Example
private void Button_Click(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)delegate
{
// all your code here.
});
}

How To catch global load event in WPF

For each UI control on wpf, there is a 'loaded' event. Suppose I have a user control with a list of other controls, like Combobox. Now, If I catch loaded event for both "usercontrol" and for "Combobox", then the the loaded event is first occurred for Usercontrol and then for Combo box, which means when the user control is already loaded, its child elements may not be loaded completed. But, I want to catch the global load event, that means that load event will be occurred only when all controls are loaded successfully. How to achieve this please? Thanks in advance.
There is no global Loaded event, you state that the 'loaded event is first occurred for Usercontrol and then for Combo box', this is probably due to the order in which you registered for these events. What exactly are you trying to achieve?
Other events that might be of use to you are LayoutUpdated, this fires each time the visual tree is modified. You can register a handler, catch the first time this event is raised, then check your UI state to determine when your UI is initially rendered.
However, you normally only need to use these techniques if you are doing something quite complex or special within the UI, like creating a complex new control. For most applications you do not need to handle either of these events.

How to open and update WPF window by threading

I have Two WPF window Window1.xaml and window2.xaml.
In window2.xaml.cs i have one function which does some complex calculation and display intermediate resuls on a TextBlock.
Now What i want.
by clicking on button of Window1.xaml i want to open Window2.xaml as a dialog box and want to execute complex function of windows2.xaml.
If i call complex button on Window2.xaml' load event then dilog box apear after execution of complex function.
How to do this by Threading.
You need not open the window in a thread. Once you've opened Window2, start a thread for the complex function in the Window2.Loaded event handler. This will leave your UI undisturbed.
Opening a Window in a thread that is not UI thread is not recommended at all. You can open a popup window using Show() (modeless) method or ShowDialog() (modal) method. In Window2's load method, you can start a new thread which does a complex operation and once it is done with the operation, it can show a dialog.
Now, while in a different thread than UI thread, if you want to show any UI (dialogs, windows) or change existing UI (textblock, etc), you must use Dispatcher.Invoke method.

WPF: Is there a simple way to create a Progress Window?

I tried creating one, but the BackgroundWorker in Window1 couldn't access the ProgressBar in Window2 once the reportProgress was activated, because "The calling thread cannot access this object because a different thread owns it".
Seems there's a lower level thread model I could use, but it also seems a lot more complicated.
You just need to get the ProgressBar disptacher.
You can access the ProgressBar with:
Window2.prograssbar.Dispatcher.Invoke(
() => /*the code for modifying the progressbar*/ );
In WPF, UI controls and properties may only be activated from the UI thread. In order to change the progress bar's value from a different thread, you can add a command to the GUI thread's dispatcher queue. You can do this by passing a delegate to the Dispatcher.Invoke() method. See the article at http://msdn.microsoft.com/en-us/magazine/cc163328.aspx for more details.
You need to look into Delegates

What is UserPreferenceChangedEventHandler in C# winform applications?

I found some of my winform application controls, such as DataGridView and ToolStrips, are referred to by UserPreferenceChangedEventHandlers. I have no idea what setting of the controls will generate such references and why such references keep my control alive in memory. How can I remove such references from that event? Thanks.
It is the delegate type for the SystemEvents.UserPreferenceChanged event. This event fires when Windows broadcasts the WM_SETTINGCHANGE message. Which typically happens when the user uses a control panel applet and changes a system setting.
Several controls register an event handler for this event, DataGridView, DateTimePicker, MonthCalendar, ProgressBar, PropertyGrid, RichTextBox, ToolStrip, NumericUpDown. They typically are interested in font or cue changes and anything that would affect the layout.
SystemEvents.UserPreferenceChanged is a static event. Registering a handler and forgetting to unregister it causes a memory leak, it prevents the control from being garbage collected. The listed controls ensure this doesn't happen, they unregister the event handler in either the OnHandleDestroyed() or the Dispose() method.
You'll get in trouble when neither of those two methods run. That will happen when you remove the control from the container's Controls collection and forget to Dispose() it. While forgetting to call Dispose() is not normally a problem, it is a hard requirement for controls. It is easy to forget too, controls are normally automatically disposed by the Form. But that only happens for controls in the Controls collection.
Also be sure to call Dispose() on forms that you display with the ShowDialog() method, after you obtained the dialog results. The using statement is the best way to handle that.
One more excruciating detail is important about the UserPreferenceChanged event, it is often the one that deadlocks your app when you create controls on a worker thread. Typically when the workstation is locked (press Win+L). Which cannot come to a good end when you use the controls I listed, the SystemEvents class tries to raise the event on the UI thread but of course cannot do this correctly when more than one thread has created them.
Also the kind of bug that can have a lasting effect, a splash screen for example can get the SystemEvents class to guess wrong about which thread is your UI thread. After which it then permanently raises the event on the wrong thread. Very ugly to diagnose, the deadlock is well hidden.

Resources