I have what, on the face of it, seems to be a really simple requirement - to be able to show a messagebox from within the view model of my WPF prism application.
Reading the documentation everything sounds good when I'm reading about Interaction Requests but I then find out that WPF doesn't support PopupChildWindowAction.
How are people getting around this. Basically I want a Messagebox in my shell module / or a infrastructure module that will subscribe to events and popup when that event is published.
Another issue I had was I want the popup to be centered on the parent window (the shell).
Just wondered how other people approached this. There seem to be a number of different ways to go but neither seem to fit the bill exactly.
From A CodePlex post by Karl Shifflet:
I've written a WPF version of the Interaction Request for my the Box MVVM Training here:
http://visualstudiogallery.msdn.microsoft.com/en-us/3ab5f02f-0c54-453c-b437-8e8d57eb9942
Install this Visual Studio Extension.
Create a new project with the MVVM Training Template.
Check out DialogInteractionRequestView.xaml and its implementation.
Cheers,
Karl
Use the RegionPopupBehavior from Prism 2.2 RI.
Use the EventAggregator in PRISM to subscribe to events, and have an in-memory presenter that listens for an event and then creates a view using the event data and calls ShowDialog on the view.
The dialog result can then be used to publish a 'response' event that would be routed back to the process that initiated the event that resulted in the display of the dialog.
Since PopupChildWindowAction is only in Silverlight, I have created my own PopupAction by inheriting from TriggerAction class and simply overridden body of Invoke() method to bring up a PopupWindow where I can pass any UserControl from xaml within the prism interaction trigger tag. From within ViewModel I am raising interactivity request event which triggers my PopupAction in view and opens the popup with desired user control being displayed onto it. Seems to work. I'll need to polish the example more. But here is a link -
http://wpfgrid.blogspot.com/2013/01/simple-prism-mvvm-way-to-display-dialog.html#step3
Related
This is my first post on StackOverflow so forgive me if I am not completely clear.
My WPF project uses PRISM 5.0 and Unity as the container. This is my first project using PRISM and Unity.
In my application, I am loading a View into my MainWindow correctly. This view displays a friendly version of information about an item. I have an edit button on this screen and I would like it to call up a modal window with the appropriate controls for editing this item. So far, I have chosen the InteractionRequestTrigger -> PopUpWindowAction approach as it was the most straight-forward seeming approach to achieve the result. I am not married to this approach.
However, I noticed I am not able to get dependency injection to work for the ViewModel constructor for the View I am trying to use in the modal. This is probably because I have not registered the View with a Region or done any of the associated leg work and the PopUpWindowAction is just plopping my user control onto a plain form if I had to guess.
My question is, can I achieve a modal dialog passing a custom View and ViewModel and have it behave as the parent View and ViewModel calling it? That is, supporting Dependency Injection and the like. After doing the edit logic, I'd like to ideally re-use the View and ViewModel for my add item functionality, but I am thinking I will be registering that View with the "Main Region" of my Shell and as such, would like to use dependency injection there as well.
Hopefully this is clear. I didn't think a code example would really help much here, but if so, let me know and I can put together a simple example illustrating the above.
I would not provide tight-coupling between my main view-model and the view-model for my modal dialog.
Instead, I would consider using the EventAggregator that Prism provides to publish notifications that my main view-model can subscribe to and react accordingly.
I am using the MVVM pattern in my WPF application. In one of my Views I have a button that when clicked uses Commands to talk to its ViewModel. The problem I have is that I need the ViewModel to then talk to other ViewModels to call some of their public methods. I use IOC (Unity) and inject the container into the first ViewModel, so could access the others by using this. I’m not sure if this fits in with the MVVM concept.
Is it possible for all my ViewModels to somehow subscribe to the one button click?
Are any of these the recommended way of solving this problem or is there a better way?
To explain a bit more about my application, each view is a tab control with several textboxes. On the first tab there is also a button and combobox. The user is free to enter their own data or select an option from the combo. In this instance, if the button is then clicked I need all the tabs to load their textboxes based on the selected item in the combo from the first tab. I somehow need to wire this button click in such a way that the value from the combo is passed to all the related viewmodels.
You can use the EventAggregator. Have the command publish an event that the other ViewModels can subscribe to.
When the event is raised they'll all get the event, without needing for one VM to know the other VMs
Another option is to use Composite Commands instead of a regular command.
Make the command the button uses a composite command, and have the other viewmodels register to that Composite command.
You could go a few ways with this one:
use some kind of eventing framework to notify all subscribers if something happens: eg Prism EventAggregator. For this to work you'll need to set up Prism obviously. There are other (MVVM) frameworks out there which support some kind of event/message system like Caliburn.Micro or MVVMLight
Create a MasterViewModel that contains all the child viewmodels for all the tabs. This way the 'master' can subscribe to the PropertyChanged events from its children and execute the appropriate actions. Or the Master can even contain the commands which you are binding to.
I would recommend using some form of "Messenger" service. By this, I mean a class that implements the "Subscription Pattern."
I'm not sure which MVVM library you might be using, but if you look at the "MVVM Light Toolkit" - which is available on CodePlex - you will find a very light implementation of a Messenger there.
Basically each ViewModel will subscribe to receive a specific notification and your ViewModel with the combo box and button will publish the message when the button is clicked. It is really quite flexible in how you send the messages and your ViewModels don't need to know anything about each other.
If you are using the MVVM lite toolkit from GalaSoft you have access to the Messenger which would allow you to send a message that you can subscribe to in each of your view models.
// Send message from command handler
Messenger.Default.Send<MyMessage>(new MyMessage());
// Register for message in view models.
Messenger.Default.Register<MyMessage>(this, MyMessageReceived);
// Method to do work
private void MyMessageReceived(MyMessage myMessage)
{
// Do Work
}
I have been developing a Lync Silverlight application in Silverlight and now I am trying to shift it to WPF.
However, I am facing some thread affinity issues. For example I display the Lync client's state on my page in a textblock, and so in my code behind have wired a state changed event handler, that writes the new state into the textblock whenever the state of Lync client changes.
Now, this worked perfectly in silverlight but seemingly is not allowed in WPF.
Now my questions are:
How come it works in Silverlight bt not in WPF, even though Silverlight is supposed to be a subset of WPF?
Thread affinity is an important concept and I know we can use invoke dispatcher, but doesn't it just beat the concept of asynchronous programming in form of event handlers and callbacks?
I have a button defined in my XAML page, and the click event handler defined on it can access other UI elements, it does not suffer the problem outlined above.
But if I define a LyncClient instance in my code-behind, event handlers defined on it cannot access the UI elements. Why so, I detected no such difference between UIElements and other objects in Silverlight?
Based on above comments, I'll suggest the following "answer"...
I would guess it is more likely than not that there is some sort of different in the way that the SL API was written than that of the WPF api. That could explain the difference in the thread that is used when the API issues the callback. To verify this, you could:
Ask MS directly
Put some diagnostics code in your callback method to log the thread ID and compare that to the main thread of the application. Do this for both SL and WPF to see if they are the same or different threads.
Open the assemblies in Reflector to inspect how each API was written.
In terms of handling this specific situation, in your callback, you could:
Get the dispatcher object (different for SL than WPF) and always issue UI updates through Dispatcher.Invoke.
Use databinding and INotifyPropertyChanged to insulate the UI from the property. You could delcare a property on a ViewModel or in the code behind. Then bind the UI's textbox to that property. Databinding has some smarts in it that will automatically marshal property changes to the correct thread (in most cases anyway).
Hope that helps.
I will be starting a new project soon and am looking for some architectural advice from those of you who have experience with WPF, Prism, and MVVM.
The project will definitely be WPF and I will be implementing MVVM (I will likely use Josh Smith's MVVM Foundation as a starting point) in order to be able to benefit from the separation of UI/logic etc. I am not sure though if I would benefit from using Prism as well to structure my project.
Let me briefly describe the project. There will be a main "toolbar" that will display a number of widgets. Each widget displays some basic data related to its function and clicking the widget will open a new window that will display much more detailed data and contain a rich UI for viewing/editing the data.
Now, I was thinking that I can use Prism to frame the project but I have never used it before and am not sure if it is suitable for what I am trying to achieve. For example, would my "toolbar" be a shell that contains regions that each widget would populate? Would each new window that is displayed when a widget is clicked also be its own shell with its own region setup? If I can get the pattern down for the toolbar and one widget on the toolbar, I can replicate it for the rest of the widgets.
Aside from Prism, I have a question about how MVVM should be implemented for certain data editing windows. Let's say I have a chart that displays some data and the user is able to directly click/mouse move on the chart to edit the data that he sees. All of the data is in the model and the view model is making that data available to the view via binding. My question is where will the mouse click/move events, that are specific to the chart in that view, be written? We don't want much/anything in the view's code behind and we don't want to have UI event handlers in the view model so I am not sure how this type of scenario is handled. I know that commands are the likely answer here but the MVVM samples I have seen usually show sample commands for simple button clicks. Is the general idea the same?
So, if anyone has any suggestions on the above or any general tips on working with WPF and MVVM/Prism, please let me know.
Thank you.
There are a few questions in there so I will do my best at covering them all.
I worked on a project that had WPF, MVVM, and Prism along side other frameworks. The best advice is to understand the power and functionality of each before glueing it all together. You don't have to use all the features of Prism for it to be useful in this situation.
For Prism you can use...
Shell and bootstrapper to initialise the application and load modules from other assemblies.
Create and configure Unity for Dependency Injection. You can use other DI Containers. Here you can add global services each module will use.
Use of EventAggregator to notify differnent parts of the application, usually across modules and views
Regions for naming areas on the UI so modules can add a view to a particular location.
The above 4 don't all have to be used but can easily be integrated in a MVVM /WPF application.
For example, would my "toolbar" be a
shell that contains regions that each
widget would populate?
Here you can have a region you create (you can derive from Region) that will manage the buttons on the toolbar. (I have used a region with regards to a Ribbon). A service can be exposed via an interface that each module can supply the command/image (what ever you have) that when it is clicked will create a ViewModel. You can do this inside the module's Initialisation.
Would each new window that is
displayed when a widget is clicked
also be its own shell with its own
region setup?
If each button opens a brand new window I would suggest introducing a common controller class that will create a generic use window and attach a view model that your module creates. No real need to use regions in this case unless you are gluing different views to a application window that stays open longer than the life of the view itself. The window in basic form can simply be this...
<Window ...>
<ContentControl Content="{Binding}" />
</Window>
Where within your controller it can do this...
public void DisplayView(ViewModel vm)
{
var window = new MyWindow { DataContext = vm };
window.Show();
}
The controller can be used within your module directly of wrapped within a service... although for testabilty a service and interface would be best. Make sure you have merged your module resources with the Applicaiton.Resources and use DataTemplate's to link your view to the view model.
My question is where will the mouse
click/move events, that are specific
to the chart in that view, be written?
Don't be afraid of code behind but you can in this case use EventToCommand attached behaviour that will route to a command on your viewmodel. MVVMLight toolkit has this which you can reuse if you want.
DI is very powerful and I encourage using it even without Prism as constructing your view models will be easier.
HTH
I think Prism will work great for you.
->would my "toolbar" be a shell that contains regions that each widget would populate?
Put a single region with an ItemsControl in the Shell
Create modules for each widget
Keep adding the widget modules to the same itemscontrol shell region.
The biggest advantage with this is that if you add more modules you don't need to change anything.
->Would each new window that is displayed when a widget is clicked also be its own shell with its own region setup?
No, you can use a 'WindowRegionAdapter' in the shell to create views for your widgets in separate windows.
->where will the mouse click/move events, that are specific to the chart in that view, be written?
You can use attached behaviors to bind events in your view to commands in the ViewModel purely in XAML. Google 'Blend behaviors' or 'attached bahaviors' for how you could go about doing it. There is no need to write any code behind for this.
To be honest I am only trying to give you the keywords you'd want to search to get all the information you need.
I'm building a custom Silverlight UserControl which needs to listen to events using Preview/Tunneling, but for some reason the compiler is telling me they are not recognized or accessible.
For example, I can add an event handler to MouseLeftButtonDown, but not PreviewMouseLeftButtonDown. This doesn't make sense because according to Microsoft (http://msdn.microsoft.com/en-us/library/system.windows.uielement_members(v=VS.100).aspx) all UIElements should have Preview events attached.
Any ideas as to why this is happening? I'm using Visual Studio 2010 Trial, Blend 4 RC and .Net 4, if that makes a difference.
Silverlight does not support preview events nor does it support routed events (bubbling/tunneling) except for a few core events.
If you are trying to create a control that works with both WPF and Silverlight, you will need to take a different approach. Depending on what you're trying to do, you may be able to accomplish what you want by rigging up a handler in code and specifying that you want handled events too.
// the last parameter indicates we want to receive events that
// were marked as e.Handled = true by other listeners
// this type of event handler can only be done in code
myUserControl.AddHandler(
UIElement.MouseLeftButtonDownEvent,
OnMouseLeftButtonDown,
true
);
You're looking at the help for WPF, not Silverlight. Silverlight is (mostly) a subset of WPF, and much of the functionality is missing.
The Silverlight UIElement help does not show those events, as they do not exist in Silverlight.