Caliburn Micro subscribe to onpropertychanged event from view code behind - silverlight

I'm working on a silverlight project that has a file viewer. This file viewer does not have a Source property or other property that accepts a stream. It does have a LoadDocument(Stream file) method. Since the file will be loaded asynchronously I need to "Notify" the view that the buffer is available and then let the View call the LoadDocument method.
In MVVMLight I could do this with the "Messenger" functionality. I see the EventAggregator but everything I see has the communications going the other way. I feel like this should be really easy to do but I just don't see it.
Is there a way in the Views constructor to bind a method to a property of the ViewModel? It seems to be this is the same functionality that is done in xaml I just want to do it in the code behind.
Thanks
dbl

Not sure by the post but it sounds like you want to bind an event from a control to a method on your view
In that case:
<SomeControl cal:Message.Attach="[Event SomeEvent] = [Action SomeMethod($eventArgs)]" />
If it's the other way round you can either use the event aggregator (the view can subscribe to events... why not, it's decoupled still...)
VM:
SomeEventAggregator.Publish(new SomeMessageInstanceThatTheViewWillSubscribeTo());
View:
class SomeView : UserControl, IHandle<SomeMessageInstanceThatTheViewWillSubscribeTo>
// dont forget to...
SomeEventAggregator.Subscribe(this);
Alternatively - implement an interface on the view
class SomeView : UserControl, IAcceptSomeNotificationMessage
{
public void Notify() { // blah
}
}
VM:
class SomeViewModel : Screen // whatever
{
void SomeMethod()
{
// The VM should be IViewAware so will implement GetView()
var view = GetView();
if(view is IAcceptSomeNotificationMessage)
(view as IAcceptSomeNotificationMessage).Notify();
}
}
Pick one of the above - I'm sure there are more ways. I usually use an event aggregator - of course it depends on how much IoC you are using and how decoupled everything is.

Related

How can I trigger some code to run in the view from the view model?

What is the best way for the view model to "ask" the view to do something, (e.g. manipulate on of the controls)? I don't think that the view model sending events violates MVVM as after all the INotifyPropertyChanged interface is an example of view models sending events to views.
I realize that having code behind in the view is not considered ideal from a MVVM perspective, so I could use an attached behavior to manipulate a particular control for example but the problem remains - how do I ask the attached behavior to do something from my view model?
I could have Boolean dependency property on my view with property changed event handler which runs the code I need to run. I could then bind this property to a property on my view model and then toggle the value of this property whenever I want to trigger the code to run. However this seems like a hack.
I could have an event on the view model and then explicitly attach this event to an event handler in the view in code but this seems anti MVVM - I should be able to achieve the connection using binding.
This must be a fairly common scenario, are there any standard solutions?
You could for example use an event aggregator or a messenger to send an event or message from the view model that the view handles in a loosely coupled way. Both the view and the view model know only about the event aggregator but they don't know anything about each other. Please refer to this blog post for more information about the concept.
Another common approach is to implement an interface in the view and inject the view model with this interface, e.g.:
public interface IDoSomething
{
void DoSomething();
}
public partial class Window1 : Window, IDoSomething
{
public Window1()
{
InitializeComponent();
DataContext = new ViewModel(this);
}
public void DoSomething()
{
//do something...
}
}
public class ViewModel
{
public ViewModel(IDoSomething doSomething)
{
//...
}
}
This doesn't break the MVVM pattern as the view model knows about and is dependant only on an interface.

A Controller for MVVM

I'm working on a WPF project that's a mishmash of code-behind xaml/xaml.cs and a few not-quite ViewModels as well.
(Disclaimer: Until recently I've had very little in the way of WPF experience. I can design and lay-out a Window or UserControl fairly proficiently, and I think I get the hang of separating an MVVM ViewModel from the View and doing binding wire-ups, but that's the limit of my experience with WPF at present.)
I've been tasked with adding some new features to the program, such that it looks like converting it to use MVVM properly first is going to be necessary.
I'll demonstrate a specific problem I'm facing:
There is a View called SettingsWindow.xaml that I'm working with. It's a set of textboxes, labels and whatnot. I've stripped-out all of the View data into a ViewModel class which resembles something like this:
class SettingsViewModel : ViewModelBase {
private String _outputDirectory;
public String OutputDirectory {
get { return _outputDirectory; }
set { SetValue( () => this.OutputDirectory, ref _outputDirectory, value) ); }
}
// `SetValue` calls `PropertyChanged` and does other common-tasks.
// Repeat for other properties, like "Int32 Timeout" and "Color FontColor"
}
In the original ViewModel class there were 2 methods: ReadFromRegistry and SaveToRegistry. The ReadFromRegistry method was called by the ViewModel's constructor, and the SaveToRegistry method was called by MainWindow.xaml.cs's code-behind like so:
private void Settings_Click(Object sender, RoutedEventArgs e) {
SettingsViewModel model = new SettingsViewModel(); // loads from registry via constructor
SettingsWindow window = new SettingsWindow();
window.Owner = this;
window.DataContext = model;
if( dialog.ShowDialog() == true ) {
model.SaveToRegistry();
}
}
...but this seems wrong to me. I thought a ViewModel should consist only of an observable data bag for binding purposes, it should not be responsible for self-population or persistence, which is the responsibility of the controller or some other orchestrator.
I've done a few days' worth of reading about MVVM, and none of the articles I've read mention a controller or where the logic for opening child-windows or saving state should go. I've seen some articles that do put that code in the ViewModels, others continue to use code-behind for this, others abstract away everything and use IService-based solutions, which is OTT for me.
Given this is a conversion project where I'll convert each Window/View individually over-time I can't really overhaul it, but where can I go from here? What does a Controller in MVVM look-like, exactly? (My apologies for the vague terminology, it's 3am :) ).
My aim with the refactoring is to separate concerns; testability is not an objective nor would it be implemented.
I personally disagree with putting much in my ViewModels beyond the stuff that is pertinent to the View (it is, after all, a model of a View!)
So I use a Controller paradigm whereby when the View tells the ViewModel to perform some action (via a Command usually) and the ViewModel uses a Command class to perfrom actions, such as saving the data, instantiating new View/Viewmodel pairs etc.
I also actually separate my ViewModel and ViewData (the ViewModel 'contains' the ViewData) so the ViewData is puirely dealing with the data, the ViewModel with some logic and command handling etc.
I wrote about it here
What you need is called Commanding in WPF.
Basically you bind Button.Command to a ICommand property in your ViewModel and when Button is clicked you get a notification in ViewModel without using code behind and casing DataContext or whathever hacks you tried.
http://msdn.microsoft.com/en-us/library/ms752308.aspx

Calling a Method of a UserControl in MVVM

I'm having an issue with calling a method on a UserControl. Hear me out:
I have a UserControl someControl in SomeView.xaml
SomeView.xaml's DataContext is SomeViewModel.cs
I want to be able to call someControl.DoStuff() somehow, somewhere.
DoStuff is not UI specific (I could have just called DoStuff from the code-behind of SomeView.Xaml.Cs if it was UI specific, but in this case, it may not be.)
Any ideas?
Thanks!
You're probably not going to like the answer, but your ViewModel should have no knowledge of your UI. If you have a non-UI method on your UserControl, it's probably in the wrong place.
The only thing I could think of is that you may want to implement some type of messaging (like they have in MVVM Light) that could trigger the execution.
It's either that, or rethink how you've architected your code.
One the SO answer to Achive this by decouples the ViewModel's knowledge about View is by using the Action delegates answered by Mert here
Pasted his code here, if the link breaks by any chance.
class MyCodeBehind
{
public MyCodeBehind()
{
Action action = new Action(()=> this.SomeMethodIWantToCall());
var myVM = new MyVM(action); // This is your ViewModel
this.DataContext = myVM;
}
private void SomeMethodIWantToCall(){...}
}
class MyVM
{
private Action action;
public MyVM(Action someAction)
{
this.action = someAction;
}
private void SomeMethodInVM()
{
this.action(); // Calls the method SomeMethodIWantToCall() in your code behind
}
}
It sounds like you want DoStuff to happen in response to some data or logic in your VM, in which case the cleanest method would probably be to use an event originating in your VM and handled by DoStuff. If the trigger is more like a state change you could also bind the appropriate VM data to a new Dependency Property on your UserControl and call DoStuff from the DP's change handler.
Maybe your UserControl should really be a View, which then should have a ViewModel, which would contain the DoStuff() method. SomeViewModel will have instantiated (are at leased casused to be instantiated) SomeControlViewModel, and so be able to call a method on it.
If you have View-first approach (and your VM is instantiated as Resource in XAML) you may use some normal events to connect your control DoStuff method with some event on VM (on Loaded event).
If the method DoStuff(); does some UI specific logic then the method is in the right place. When not then it should be in another object (e.g. SomeViewModel).
SomeViewModel is allowed to call a method on SomeView when it is separated via an interface. How this can be accomplished is shown by the WPF Application Framework (WAF).
In MVVM design, the idea is generally not to have ANY code in your UserControl (the xaml.cs file) (in an ideal world). All interaction between the UI and the ViewModel should be handled via Commands and Bindings...so why do you need DoStuff in your user control?
You might have something like
<Button Command="{Binding myCommandOnTheDataContextViewModel}" Content="{Binding somePropertyOnTheViewModel}" />

MVVM question, Event fire in the View

I am new in MVVM and WPF. so be easy with me.
I have a model (model A) in MVVM, in the ViewModel I have a collection.
The collection is present in the View as ListView.
I have another model (model B - not ui model) that need to do something every time that the listview is changing.
How can I alert model B on the selection change? What will be the right way?
By event that model A (ViewModel) will fire, and model B will catch?
By attached property of model A?
By notify property change?
By sending relay commands from model B to model A?
Use Publish /Subscriber pattern
like used in the EventAggregator
http://msdn.microsoft.com/en-us/library/ff647984.aspx
Or in the Messenger
.http://geekswithblogs.net/lbugnion/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx
usualy MVVM frameworks ship mechanism for this build in.
Personally I would send the commands from VM to VM and make them update the Model
hope this helps
I would either
Expose an event in ViewModel A that ViewModel B can subscribe to. I would then raise that event anytime the selection changes.
Leverage INotifyPropertyChanged for notification to ViewModel B
I prefer option 1 because it makes it more obvious what you're trying to do. Plus it's more efficient (you don't have code smell of filtering on which property changed and then doing some action.)
IMHO I think relay commands should only be used as an interface between a view and a viewmodel to aid in a separation of concerns. But when you're programming from a class to a class, just use standard OOP conventions.
so pseudo code would probably look like this:
public class ViewModelA
{
public event EventHandler SelectedObjectChanged;
public IList<MyObject> ObjectList {get;set;}
public MyObject _SelectedObject;
public MyObject SelectedObject
{
get { return _SelectedObject;}
set
{
_SelectedObject = value;
if (SelectedObjectChanged != null)
SelectedObjectChanged(value);
}
}
}

WPF MVVM and Unit Testing

I have been working on a WPF application and I am using the ModelViewViewModel design pattern. I have a number of events that come out of the view, that result in ViewModel activity.
What is the resonable way to get these events raised from a UnitTest? For example, I want to simulate the drop event. I don't really want to build a stub view, just to raise the event.
Any suggestions welcome.
Thanks.
According to the MVVM pattern:
The View knows about the ViewModel - it will have a reference to it either as a concrete instance or an interface
The ViewModel should not know about the view at all.
If you need to handle events, then there are two ways which I know of to do it:
1: Expose a command in your viewmodel, and use databinding to trigger it. This is my preferred way, eg:
class MyViewModel
{
public ICommand ClickCommand { get; set; }
}
<Button Command="{Binding Path=ClickCommand}" />
If you do this then you can test the command by simply calling myViewModel.ClickCommand.Execute manually.
2: Expose a function in the viewmodel, and write the absolute minimum in the .xaml.cs file to handle the event and call the function, eg:
class MyViewModel
{
public void HandleClick(){ }
}
<Button Click="MyClickHandler">
//.xaml.cs file
public void MyClickHandler( Object sender, EventArgs e ) {
m_viewModel.HandleClick()
}
If you do this, then you can test by simply calling myViewModel.HandleClick manually. You shouldn't need to bother with unit testing the MyClickHandler code as it's only 1 line!
It sounds like you have an event handler for the drop event directly in your ViewModel class. Would it make more sense to have the handler in your UI layer, which in turn will call a function in your ViewModel? This way, your unit test could just call the function (simulating a drag and drop operation, as far as the ViewModel is concerned).
Plus, it would better separate your ViewModel from your UI code.
Don't raise an event, just call the handlers (which means they should be public, and probably take less event handler centric arguments). Check out how this is done in Caliburn (http://www.codeplex.com/caliburn) using "Actions".
Why don't you use a mocking framework, such as Moq? Check out their quick start, it has a sample on mocking events. The url is: http://code.google.com/p/moq/wiki/QuickStart

Resources