What can I do with Prism Event Aggregator that cannot be done using bubbling/tunneling? - wpf

Imagine a Visual Studio type user interface in which there is a left pane and a right pane. I need to send a message/event that originates in the left pane to an element in the right pane. As a WPF newbie, I have the following linked questions:
Can this be done using bubbling and tunneling events?
If the answer is 'yes', which is better: bubbling/tunneling, or Prism's event aggregator?

I use Event Aggregation to notify my 'panes' of events that happen and both need to respond.
So, for one example, I would subscribe both 'panes' to an event. Now, say I kick of a request to the database or webservice, and upon return of results I want to notify both 'panes' simultaneously that data has arrived. I can easily do this by publishing to my event, then both 'panes' will kick off whatever they need to.
I like this way, because then if I had another module dropped in the left 'pane', all I would need to do is subscribe to that event to respond to any data coming in.

Related

Creating a Visual Studio style errors tool window with jump to error functionality

I'm using Caliburn Micro to create a Visual Studio style interface for my application.
The user could have multiple errors in multiple windows which are all shown on an 'errors' view which is docked at the bottom of my application. I've managed to implement a nice notification mechanism so that when changes are made to any document, the errors VM is notified and queries the source object.
I'm having trouble, however, in figuring out how to get a double-click to navigate to the source of the error.
Imagine I have bound 'description' to a textbox on my document view and this provides a 'description is required' validation message. Double clicking the message should navigate the user to the document in question and focus on the textbox.
The validation objects that provide the messages already contain a reference to the viewmodel (as an IViewAware interface) which allows me to call GetView() to get a reference to the view. I've tried using this approach to enumerate the bindings on my view and find the controls that are bound to a particular property, though this is very slow and more of a brute force - pot luck approach
Does anyone have any recommendations on approaches to this problem? My only other thought is to pass responsibility of the 'focus' action to the view itself and have that decide how to handle a request for navigation to a certain property - maybe using attached properties to identify particular controls by a unique property identifier. The application could cache this list in a dictionary to make things quicker (all the processing done up front as the app is loading)
I assume Visual Studio implements this quite easily for the standard code editor window, since it just needs a line number to jump to the right place..
Ok so after a couple of hours messing about with this I've come to a solution which seems to work ok. I've implemented an interface class for my views which allows them to navigate.
The basic setup is:
ErrorsViewModel - receives notifications that a business object needs requerying for errors and manages the list of errors and when it needs to query (so that any work can be done on a background thread to prevent locking the UI)
WorkspaceViewModel - the main workspace VM that hosts the tool panes and documents
ICanNavigate - interface that the views will impelement to decide how to handle navigation arguments
NavigationEventMessage - the message that is sent to the event aggregator to provide a navigation notification and arguments
The ErrorsViewModel receives an event message from another VM via the event aggregator and eventually queries the object (when it can). Once the errors are gathered, it shows the items in the view (in a grid control at the moment).
When the user double clicks on a row a NavigationEventMessage is dispatched which contains some arguments such as the view that dispatched it and the target business object etc. It is handled by..
1) The WorkspaceViewModels view. This allows it to bring the correct document into activation by looking at the DataContext of each object and checking if it matches the view passed in the message
2) The target documents view, the view decides what to highlight/show/seek to based on the arguments sent in the message
This seemed to be the most logical way to separate the VM from the View as the ViewModels still have no coupling with the views. The view just implements the interface, and the VM calls it if it's there and passes in the args.

Load view on double-click of row - have bindings working, and event being fired on click, but how do I actually get the view to pop up?

I have a view in Silverlight which contains a telerik:RadGridView with a number of columns.
I have it wired up so that when the user double-clicks on one of these columns, an event is fired. However, I don't know what to put in the event handler.
private void RowClicked()
{
//What goes here?
}
All I wish to do is load a popup view over my current view, with a close button so that the user can return to the previous view. A simple idea that is surely done a billion times everywhere, but I cannot figure it out or find examples of this anywhere.
Can anyone help?
Thanks very much.
You can set a previous view as input parameter to "RowClicked()" method. You will have a reference on previous view in current method. You can use it via Commands (bind a command and a command parameter to some action/event).
I have an one more idea (if you have a lot of views): you can create a navigation service. It is an interface, which contains events and methods. You should use events for navigation and methods - for sending needed data. Everyone of view should implement this interface. Needed event will be raised under view via some action (for example: button click). As for events: you can create a custom event handler, there you will set a sender instance and needed parameters. You should create a Navigation manager, there you should create a property for selected view and subscribe on everyone event. If user want navigate to another view, he will do some action and system will raise an event. You can create a custom container for created views. This container you can use for getting created instance of needed view. As you know, creating a new instance is heavy for system: need a some time and system resources. Will be easy to get a created instance of view instead a create a new. For setting default data or refreshing a binding you can user a custom method, contractor for which will be added to navigation interface.
It is a simple idea, which I used in one project. As for others samples: You can find another navigation frameworks and custom classes in internet. But, process of creating an own system will give you a level up in your work experience.

Events routing in WPF

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.

Responding to a WPF Click Event in a Data-bound User Control

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.

WPF Routed Events Across Element Tree Branches

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.

Resources