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.
Related
My main viewmodel encapsulates a set of workspace viewmodels only one of which is exposed at any given time via a CurrentWorkspace property on the main view model. The user gets to switch between workspaces through a series of radio buttons so that when a radio button is clicked, the value of the CurrentWorkspace is replaced with a new workspace viewmodel.
Each workspace has a corresponding view (datatemplate) so that as workspaces are switched, old view unloads and a new view loads in keeping with the value of CurrentWorkspace property. Now each view has a datagrid that could still be in edit mode when the user may choose to click a radio button forcing view unload that dismantles its visual tree including the datagrid. The problem is that the last pending row edit is not committed to the underlying view model when this happens.
I tried to remedy the situation by trying to handle DataGrid LostFocus, LostKeyboardFocus, Unload events as well as the UnloadingRow event but none of them seem to offer a handle to the issue. It seems that once the view unload is triggered, these events either do not fire or fire too late for me to invoke a commit.
I would appreciate any help or pointer to where I should look to resolve this issue.
The problem that I noted above was only observed when the user clicked RadioButton triggering view unload. However, there are other buttons in the main view that also trigger workspace unload (such as Quit button) but those surprisingly did not produce the same bug.
On close scrutiny I found, that radio buttons had by design set their attribute Focusable=False. Undoing it solves my problem and the datagrid now commits edits properly when the view unloads. As I noted above, DataGrid/DataGridRow LostFocus events were not firing as expected and now I believe I found the reason.
So I guess DataGrid/DataGridRow rely on their LostFocus events to trigger commits and its important that this event be not suppressed in any manner. I still wish though if wpf controls had an "Unloading" event as a fall back option to handle problems created by design decisions like the one in my case.
I have a WPF application based on the MVVM pattern. It has a tree on the left side and a details area on the right side. The tree contains objects of various types and I have a view model for each type. In the view, I have a different data template (containing a user control) for each view model type. The view is then selected via databinding based on the current details view.
Now, when I switch between tree nodes, I also instantiate a new details view model for each node and the view gets changed accordingly, firing both the DataContextChanged event and the Loaded event. That is, until I start to switch between objects of the same type. Here, too, the details view model gets updated, but the view instance stays the same. This means, only the DataContextChanged event is fired, but not the Loaded event.
Is there a way to force the Loaded event to fire, for instance, by re-initializing the view?
The reason why I need the Loaded event is that WPF fires the selection change events on input controls during data binding and since I have logic that acts upon user-triggered selection change events, I need to be able to ignore those triggered by data binding. For now, the Loaded event seems to be the best option to do this. Escept for the described issue.
Thanks, Michael
Move whatever logic you have in the Loaded handler to the DataContextChanged handler if it needs to run every time the data context changes.
I have implemented a UserControl. Then I would like to handle an event that is originally handled by Window (keyboard press). What is the best way to route the event caught by another component (higher in the components' tree)?
Thanks in advance for the replies and hints!
Cheers
It depends on the event you're trying to access. If it's a Preview event and the Window is setting e.Handled to true you'll need to use the method Alex suggests to circumvent the Window's handling of the tunneling. If it is a bubbling event (i.e. KeyDown) you don't need to do anything special since bubbling events hit the handlers on child elements first and go up the visual tree so the Window handler won't occur until after your UC's.
One thing you need to be careful with using Key events is that the event is only going to get picked up by your UC in the first place if the Focus is on or inside of it. This isn't something you need to worry about with things like Mouse events since they start at a specific location in the tree.
I believe you cannot gurantee that.
Window class is wrapping Win32 message-based event model and this will be the only WPF entity which will have access to those information.
I suggest that you create an attached property (which will be used by the Window) and implement the routing of the events yourself so that controls could subscribe to.
You can attach the routed handler specifying that you want to handle handled messages as well:
this.AddHandler(routedEvent, handler, true);
where this is an UIElement or derived class.
However there may still be events (key presses in this case) which don't make it past the window, not sure.
In our Silverlight 2 project we have created an attached property to perform on-the-fly translation to text properties of various user controls. To achieve this, we hook the Loaded event of the FrameworkElement when the property is set. When the event fires, we take the existing text property value and perform some simple string substitutions on it, before replacing the property value with the translated text. However, this results in the control being rendered with the untranslated text, then the text is quickly replaced with the translated version.
Is there an alternate event we can hook that would fire before the control is rendered?
I've changed my code so that it now performs the translation as soon as the setter for the attached property is called. There's no need to wait for the FrameworkElement to have finished loading, as I can change the Text property long before the element is rendered.
My initial thoughts on using the Loaded event were to reduce the startup time of the application by only translating the controls that were visible on the screen. As it turns out, I'm duplicating some of the work performed by the runtime, as the runtime won't call the property setter until it needs to anyway.
I'm not totally sure about this, but can you use the LayoutUpdated event. It will fire when the control is resized and such (you could take measures to ensure your code only executes once.)
I know it doesn't seem like the "right" event for this but unfortunately Silverlight kinda leaves you standing there holding it when it comes to events.
I hope this makes sense.
I have created several WPF User Controls. The lowest level item is 'PostItNote.xaml'. Next, I have a 'NotesGroup.xaml' file that has an ItemsControl bound to a List of PostItNotes. Above that, I have a 'ProgrammerControl.xaml' file. Each ProgrammerControl has a grid with four different NotesGroup user controls on it (and each NotesGroup contains 0-many PostItNotes.
Then, I have my main window. It also has an ItemsControl, bound to a list of Programmers.
So, you end up with a high level visual view of a list of programmers, each programmer has four groups of tickets, each group of tickets has many PostItNotes.
The trouble I'm having, is that I want to respond to a mouse click event in my mainWindow's code behind file.
I can add a MouseClick event into my PostItNote.xaml.vb file and that is getting called when the user clicks a PostItNote, and I can re-raise the event; but I can't seem to get the NotesGroup to listen for that event. I'm not sure if that's even the correct approach.
When the user clicks the PostItNote, I'm going to do a bunch of business-logic type stuff that the PostItNote control doesn't have a reference to/doesn't know about it.
Can anyone point me in the right direction?
You have a couple choices:
Use the PreviewXXX events which are fired during the "tunneling" phase of WPF event routing. The parent controls can always preview the events going down through them to children.
Use the more advanced approach to hooking up events leveraging the AddHandler method to which you can pass a parameter called "handledEventsToo" which basically means you want to know when the event happened "within" you even if some descendent element handled the event itself.
I am going to take a flyer here. You probably don't want to be handling the event that high up; not really anyway. You are catching the event at the lower levels, which is unavoidable. Consider invoking a routed command from the PostItNote click event handler.
The routed commands bubble up and tunnel down through the tree. You can have an architecture where a high-level handler can listen to a logical event (Opening a postit note perhaps?). The handler for this doesn't need to care where the command originates from. It might be from you clicking something, it might be from clicking on a toolbar button. Both are valid scenarios.
It sounds like you are creating some kind of custom UI, am I right? You want the application to respond to the users interactions. That is what the RoutedCommands are for.