In my silverlight application I need to send a notification from a ViewModel to a View. In response to it a method on a UI control should be called. I know about 2 ways to accomplish this:
1) Raise an event in the ViewModel and handle it in the View's code behind.
2) Send a message from the ViewModel (using the MVVM Light messaging support) and respond to this message in the View's code behind.
I'd like to know if there is a way to accomplish this without using code in the View's code behind, for instance through some kind of data binding in the XAML?
Please share any ideas.
Additional info about what the View should do when it receives notification from ViewModel
In the XAML of the View I declare an instance of a custom Silverlight grid control which has the following method:
public void FileExportFinished(bool fileExportSucceeded)
I want to call this method from the XAML in response to the notification received from the ViewModel passing a boolean value received with the notification.
Yes...you can do it with the help of a dependency property.
Create a dependency property for that view (Make it boolean type since we just need this property to call another view method).
In its property changed call back, make provisions to call your required view method.
Then bind the DependencyProperty with a propert in ViewModel.
So when you need the view to be updated, just set the binded Property mentioned above, this will fire the property changed call back of Dependency property and form there your required view method will be called.
why not simply use a Property in your viewmodel and a DataTrigger in your xaml?
if you want some kind of dialog popup you can use a dialogservice. you should really add what you wanna do to your question. what should happen in your view when the notification arrive?
btw Messenger is for viewmodel-viewmodel communication, so thats not an option.
Related
I'm pretty new to wpf and mvvm so this may be a easy question but I'm hoping someone can explain it to me. I have a class in my model that all it does is polls processes and if it see that "calc" is running it adds it process id to a List. If you close calc.exe it removes it from the List. If the List changes it fires and event. In my ViewModel i subscribe to that event and update my property that fires off PropertyChanged. Now if my Property is a List in the view model then my binding in my view does not update correctly. If I changed my List to an ObservableCollection in my Model and ViewModel then i get a cross thread issue. However, if i leave my List in my model and change my property in my ViewModel to a ObservableCollection and copy the values of the the list into an observable collection everything works as expected.... I don't get it, do i really need to do the copy to get the binding in my ListBox to work properly?
Take a look at the DispatcherNotifiedObservableCollection that Cinch implements. It will automatically use the Dispatcher if need be. Read this article to see the code for it:
http://www.codeproject.com/KB/WPF/CinchIII.aspx#ObsCol
You need to update the observable collection from the dispatch thread.
Something like (not technically/syntactically correct, but psuedo-close)
Dispatcher.BeginInvoke( () => theList.Add( theThing ) );
A better way to achieve this functionality, is expose the Model via a property in the ViewModel, and bind the ListBox to Model.ObservableList. And use John's suggestion when adding and removing items to this list. This will not require you to copy the values from list to an observablecollection.
So your viewModel code would like
public class ViewModel
{
public Model Model { get { return _model; } }
}
The binding in xaml:
<ListBox ItemsSource=Model.ObservableList/>
where the ObservableList property returns your ObservableCollection.
As all UI elements in WPF have thread affinity (to the Dispatcher thread), any updates to the UI should be marshaled via the Dispatcher. You can marshal calls via the Dispatcher, using Dispatcher.Invoke. In this case, your view, viewModel and Model reside in the Dispatcher thread, so any call to update the UI via the viewModel or Model, would require you to call Dispatcher.Invoke.
I want to change a DependencyProperty of my ViewModel from a class which connects the application to a database.
This class raises events which should initiate a change of some properties in my ViewModel.
How can I realize that? I don't have the Dispatcher of the View.
I'm assuming you don't really have dependency properties on your viewmodels but rather normal C# properties which raises the PropertyChanged event.
If so, you should be fine already. Modify your properties from your background thread (normal concurrency issues apply obviously) and when they are bound to a WPF element's Dependency Property the runtime system will take care of marshalling the change to the proper thread (by using the view's Dispatcher object)
This works for normal properties, I'm not sure it works for ObservableCollections.
There are also different approaches for doing the marshalling inside the viewmodels. The simplest way is to just store the value of Dispatcher.CurrentDispatcher in your viewmodel's constructor. This works as long as your viewmodels are created on the UI thread.
One immediate solution to the problem is to capture the view's Dispatcher and store it on the view model when you create it, so you can Invoke/BeginInvoke the change to it in response to the event.
That being said, you should consider making your viewmodels use INotifyPropertyChanged with CLR properties rather than DependencyProperties to avoid issues like this. That way, any thread can make changes to your viewmodel and have the results reflected in the view.
I have a menu in MainViewModel, now on selection of a particular menuItem I wanted to update data of a view which is already loaded.
i.e. although there's an instance of that viewModel in MainViewModel, when I try to invoke the method thru that instance and change the data property, it doesnt show the changes in the view. Whereas same changes occur when I invoke that method through relay command using a button on that viewModel's view.
Now its like I need to invoke relay command of that viewModel from MainViewModel, I guess that will fix the problem, but how to do that? what's easiest way. Will i need to use messaging?
I tried MVVM Light messenger class, its quite straightforward and elegant (keeps ViewModels loosely coupled)!! and most importantly it works
code:
Send:
Messenger.Default.Send(stringParameter, "key_anything");
Register:
Messenger.Default.Register<string>(this, "key_anything", invokeFunction);
private void invokeFunction(string stringParamter)
{
//code goes here!
}
I am trying to use MVVM light to achieve something like this. I have the following scenario:
In my Model--I have set the properties like ActivityName,Image and there is a class constructor whose is accepting 2 parameters like name and image.
Im my DataAccess--I have set the database connection and implement the required method who will fetch the data from DB and I am storing in the List and returning the list to ViewModel.
In my ViewModel--I have created the list property who will return the list by calling the GetActivities() method that I have defined in the DataAccess.
Now my problem is I am not getting how to bind it in the View so that by clicking on a button it will display the list of activities with image. By clicking on some button a new window should open with the desired result. How to bind the above list and implement the button functionality using MVVM light.
Kindly help?
Thanks
First of all, use an ObservableCollection instead of a List as it would notify the view when property or collection changes.
Then set the DataContext of your view to the viewmodel. If you use MVVMLight View Class, then the DataContext would be automatically set. You've to just give the ViewModel Name there.
Then set the ItemsSource of the DataGrid like this <dg:DataGrid ItemsSource="{Binding YourListInViewModel}"/>
For handling click event you can use the Event-To-Command behaviour and write your logics in the Button's corresponding Command handler.
Bind to DataContext of the control
I am developing a Silverlight 3 application, in which I have a boolean property in my Model class (using MVVM approach) that's bound to "IsEnabled" target property of two buttons. I need to find out which button invoked this boolean property when I raise the PropertyChanged event (i.e. during databinding).
Is there something in the callstack that I can look for to figure this out? Or is there some other way by which I can do this?
TIA...
Sudeep
You could check the call stack e.g.
var st = new System.Diagnostics.StackTrace();
var callingtypeOfAMethod = st.GetFrame(1).GetMethod().DeclaringType;
i hope this gets you the idea. you can get the calling control type using this.