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.
Related
As I am trying to make my own custom "WinForms", I am left confused on when does each mouse event occurs. I have made my own custom classes, but now the events are something I have to rework, as they won't work right.
I have a custom class for controls. Objects from that class can contain other controls, which can contain other controls and so on. There is a main control, which gets input from a picture box. That input is what is where the mouse is and what even has been activated in the picture box.
So far I have figured, that MouseMove, MouseHover and MouseDown events are the simplest to write, as they occur in simple conditions. But the rest require additional data about the mouse's location, state and past. MouseDoubleClick seems to activate after a specific sequence of events (strictly down-up-down-up, down-up-down-move-up and down-up-down-move-leave-enter-move-up, with the movement events not activating). With that in mind, I am even more confused.
In what conditions and sequences does each mouse event occur?
EDIT
Further testing made things even more confusing. For one, now I want to know at what rate is the MouseMove being registered, and testing it shows that between each event there is a different time (or so does my use of a StopWatch say). This is important, because then that raises the question when is Hover being triggered.
Click is down-up, where moving is allowed between the two.
DoubleClick proved to be simple enough - down-up-down-up, where moving is allowed explicitly only between the second down-up.
Hover activates only once after each Enter, when the mouse remains stationary; if you want to trigger Hover again, the mouse has to leave and then re-enter.
So the question now is how the system tracks the mouse's activity - how does it detect the mouse moving, being held down and being released. Hopefully that would help me get the full answer.
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.
A WPF window should have hundreds of objects (rows of rectangles) and mouse clicking on each of them should fire similar actions. These actions differ only by several parameters (say "No. of Row" and "No. of position in a row").
Should I have hundreds of almost the same event handlers or how I could optimize my code?
Please give me some tips, just to move to the right direction.
Best regards.
WPF mitigates this problem by introducing Routed Events. At any level in the element hierarchy you may intercept events from its child elements and base your logic depending on the actual element that received this event in the first place (as presented by the Source property of RoutedEventArgs).
I'm no expert in WPF, but in event handling you could write 1 dans point every similar event to this handler. In the handler use the senter parameter to know whish control it came from.
Instead of 100's of similar event hander you could have a big one with a switch
Hope that's help
Can't you just use an instance of ICommand on your viewmodel and use the command parameter to determine which rectangle was clicked?
I'm working in WPF using the MVVM pattern, and generally things seem to be working pretty well, as I wrap my brain around the nuances of both WPF and MVVM. However, I'm currently stuck on a particular issue. My actual application is fairly complex, so to simplify, let's take Josh Smith's near-defining article on the pattern and use the application therein.
Consider Figure 2, and imagine that the user has typed some stuff in the first and last name fields. Then the user clicks away from the workspace (viewmodel) entirely, either by clicking a different customer tab, or possibly a completely different viewmodel in the same application. In this case, what I'd like to have happen is for the application to ask "Hey, did you want to save your changes? Yes/No/Cancel" and respond appropriately. This has presented... challenges.
Because I'd like the user to be able to 'cancel' that first-pass suggests needing PreviewLostKeyboardFocus (since I could set Handled=true and cancel the focus shift). However, several user actions (such as clicking the tab of a different workspace) don't shift keyboard focus. LostFocus covers me better in that respect, but that's only after the focus has already been lost (though of course I could switch it back?) and there are issues with determining if the event was from the view itself (i.e., we're leaving the whole view) or if it's simply bubbled up from some contained object.
And big picture on all this - this seems to be an issue for the view, but then that implies writing code in the view rather than the magic viewmodel. Which makes me think i'm not looking at this correctly.
So I'm hoping I'm missing some big conceptual a-ha that will make all this clear. Help?
You need to concentrate on your model rather than your view. That is, what does change that should trigger your logic? In this case, I'd say it's when an attempt is made to change the active tab.
So you need an overarching view model whose responsibilities are:
Expose a collection of all sub view models (each of which appears in its own tab)
Track the active (selected) sub view model (ie. the active tab)
Your view would bind to these properties in the usual way:
<TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}"/>
The SelectedTab property would apply your logic as follows:
Is the current tab dirty?
If so, prompt the user via a service
If the user cancels, don't change the active tab
If the user saves or discards changes, then change the active tab
I think the key thing you're missing is the overarching view model. Working your way through my ActiveAwareCommand sample project may help increase your understanding.
I am wondering what the correct mechanism to enable communication between controls in WPF is. My goal is to not use conventional events and have to manually wire them up. The default behavior of routed commands (tunneling, bubbling) seems to be along the right lines but I guess I'm missing something.
Routed events are a new infrastructure provided by WPF which allows events to tunnel down the visual tree to the target element, or bubble up to the root element. When an event is raised, it “travels” up or down the visual tree invoking handlers for that event on any element subscribed to that event it encounters en route. Note that this tree traversal does not cover the entire visual tree, only the ancestral element
That is from this WPF Article
Using the image in the article, I want "Immediate Element #1" to initiate (raise) an event and then have "Immediate Element #2" handle that event. I'd like to achieve this without having to put any code in the "Root Element".
Basically fire an event (save, status updated, selection changed, etc..) from any where in my app, then have it be handled somewhere else with out the 2 parties knowing anything about each other. Is this possible?
I dont believe data bainding is the answer. I'd like to use Routed Events / Commands as they were designed just across the entire tree, not just within the source control's branch. Maybe it can't be done using routed events / commands, and data binding is the answer. I just dont know...
Any ideas?
The best mechanism is to refactor and separate the data view from the data model.
Create a data model that provides DependencyProperty properties (rather than standard C# properties) for each data point, but does not provide a UI. The values in the data model can affect each other when modified.
You can then bind each WPF element to the appropriate DependencyProperty from the data model. Modify the value in one element and all other elements are updated to reflect any data model changes in the bound properties.
If you want to transfer data between elements, Binding is the way to go. There are many tutorials and books about this on the net.
If you want to effect Style changes, then you can use DataTriggers, which also use Bindings.
There is no way to send events in the traditional sense between unrelated controls without wiring it up in the common root.