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}" />
Related
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
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.
I want to use WPF with MVVM pattern in my project, but i am confused about some points regarding MVVM pattern. Please help me to clarify these points.
I am using DataTemplate for ViewModel, but i want specific control to be keyboard focused.
How can i focus specific control after ICommand Executed.
How can i move focus to not validated control.
Is there any way to separate DataTemplate depending on ViewModel property value.
How can i validate all controls before ICommand
Is there any other better approach to ask any confirmation from ViewModel with MessageBox
Regards,
Mitan
I highly suggest you have a look at caliburn (or caliburn.micro) which exposes different UImanager interfaces so your viewmodel can do such things without losing unit testability.
To set the foucs on control use codebehind. MVVM doesn't say don't not use codebehind.
Write a method on code behind to set the focus and call this method from view model.
Example
public interface IView
{
void setFoucs();
}
//Code Behind
public class MyWindow : Window, IView
{
public void SetFoucs()
{
MyControl.Focus();
}
}
public class ViewModel
{
public IView _view { get; set; }
public ViewModel(IView view)
{
_view = view;
}
public void SomeMethod()
{
_view.SetFocus();
}
}
For question no 4 - I think your are looking to selecte specific datatemplate based on your some logic. To achieve this use DataTemplateSelector class.
http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-a-datatemplateselector
Question 1:
Not clear what you mean/want. Generally the TabIndex controls the focus flow in your application, with silverlight it is however not as easy to configure as in windows forms. Silverlight also does a good job at setting the tab sequence automatically.
However, you should note that all controls inheriting from Control receive, by default, the focus. This incudes some controls that may be used as a container for other controls (e.g. ContentControl). This behaviour might lead to some unwanted effects. Use the IsTabStop property to remove these controls from the tab order.
Question 2:
Well, it depends on how decoupled you want your application (the more decoupled the better). #pchajer's approach is one way of doing it, however it couples the view to the view model and this - although abstracted via an interface - is IMHO not a good idea for the following reasons:
Usually the view model is pulled from a locator in order to allow for blendability. Now if I have to use code behind to pass the View to the ViewModel this might break it. Better would be if it could be injected into the ViewModel via a constructor parameter and this would then break the locator.
The code becomes less testable as it now depends on the view. To make it testable you need to inject an implementaion of IView into the ViewModel, and this breaks the locator again.
Therefore, I would advise you to use Messaging to send a message to your view once the Command is complete. Then you can set the focus in the message handler. However, be aware that your might have to use the Dispatcher as the message handler could run in a separate thread.
Question 3:
You could capture the BindingValidationError on the control and then set the focus. Again be aware of possible threading issues.
Question 4:
Not sure, but if you mean that you want to use different DataTemplates based on whether a property has a certain value or not a TemplateSelector might help you. See http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-a-datatemplateselector.
Question 5:
The controls are validated when the property change event is fired, usually on the lost focus event. Your Model/ViewModel can implement IDataError to do the validation, and your can access this value from the CanExecute method associated with your command. However, you should try to keep the code in the CanExecute method as quick as possible as this method is called quite frequently.
Question 6:
You can implement your own Window that provides a custom layout. However, using the message box is a lot simpler. Again you should think of using messaging or a dialog service (e.g. http://blog.roboblob.com/2010/01/19/modal-dialogs-with-mvvm-and-silverlight-4/) to decouple your View and ViewModel. In fact there is even a DialogMessage in MVVMLight.
This question already has answers here:
How can I Have a WPF EventTrigger on a View trigger when the underlying Viewmodel dictates it should?
(4 answers)
Closed 8 years ago.
I have quite simple (I hope :)) problem:
In MVVM, View usually listens on changes of ViewModel's properties. However, I would sometimes like to listen on event, so that, for example, View could start animation, or close window, when VM signals.
Doing it via bool property with NotifyPropertyChanged (and starting animation only when it changes from false to true) is possible, but it feels like a hack, I'd much prefer to expose event, as it is semantically correct.
Also, I'd like to do it without code in codebehind, as doing viewModel.myEvent += handler there would mean that I'd have manually unregister the event in order to allow View to be GC'd - WPF Views are already able to listen on properties 'weakly', and I'd much prefer to program only declaratively in View.
The standard strong event subscription is also bad, because I need to switch multiple ViewModels for one View (because creating View every time takes too much CPU time).
Thank you for ideas (if there is a standard solution, a link to msdn will suffice)!
Some comments:
You can use the weak event pattern to ensure that the view can be GC'd even if it is still attached to the view model's event
If you're already switching multiple VMs in for the one view, wouldn't that be the ideal place to attach/detach the handler?
Depending on your exact scenario, you could just have the VM expose a state property which the view uses as a trigger for animations, transitions, and other visual changes. Visual state manager is great for this kind of thing.
This is something that I wrestled with as well...
Similar to what others are saying, but here is an example with some code snippets... This example shows how to use pub/sub to have a View subscribe to an event fired by the VM - in this case I do a GridView. Rebind to ensure the gv is in sync with the VM...
View (Sub):
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Events;
private SubscriptionToken getRequiresRebindToken = null;
private void SubscribeToRequiresRebindEvents()
{
this.getRequiresRebindToken =
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Subscribe(this.OnRequiresRebindEventReceived,
ThreadOption.PublisherThread, false,
MemoryLeakHelper.DummyPredicate);
}
public void OnRequiresRebindEventReceived(RequiresRebindEventPayload payload)
{
if (payload != null)
{
if (payload.RequiresRebind)
{
using (this.gridView.DeferRefresh())
{
this.gridView.Rebind();
}
}
}
}
private void UnsubscribeFromRequiresRebindEvents()
{
if (this.getRequiresRebindToken != null)
{
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Unsubscribe(this.getRequiresRebindToken);
this.getRequiresRebindToken = null;
}
}
Call unsub from the close method to prevent memory leaks.
ViewModel (Pub):
private void PublishRequiresRebindEvent()
{
var payload = new RequiresRebindEventPayload();
payload.SetRequiresRebind();
EventBus.Current.GetEvent<RequiresRebindEvent>().Publish(payload);
}
Payload class
using System;
using Microsoft.Practices.Composite.Presentation.Events;
public class RequiresRebindEvent
: CompositePresentationEvent<RequiresRebindEventPayload>
{
}
public class RequiresRebindEventPayload
{
public RequiresRebindEventPayload()
{
this.RequiresRebind = false;
}
public bool RequiresRebind { get; private set; }
public void SetRequiresRebind()
{
this.RequiresRebind = true;
}
}
Note that you can also set the constructor up to pass in a Guid, or some identified in, which can be set on Pub and checked on sub to be sure pub/sub is in sync.
imho yYand separated
state - to be able to move data back/forth between view <-> vm
actions - to be able to call onto view model functions/commands
notifications - to be able to signal to the view that something has happened and you want it to take a viewy action like make an element glow, switch styles, change layout, focus another element etc.
while is true that you can do this with a property binding, its more of a hack as tomas mentioned; always has felt like this to me.
my solution to be able to listen for 'events' from a view model aka notifications is to simple listen for data-context changes and when it does change i verify the type is the vm i'm looking for and connect the events. crude but simple.
what i would really like is a simple way to define some 'view model event' triggers and then provide some kind of handler for it that would react on the view side of things all in the xaml and only drop to code behind for stuff thats not do-able in xaml
Like adrianm said, when you trigger your animation off a bool property you are actually responding to an event. Specifically the event PropertyChanged which the WPF subsystem. Which is designed to attach/detach correctly to/from so that you don't leak memory (you may forget to do this when wiring an event yourself and cause a memory leak by having a reference active to an object which otherwise should be GCed).
This allows you to expose your ViewModel as the DataContext for the control and respond correctly to the changing of properties on the datacontext through databinding.
MVVM is a pattern that works particularly well with WPF because of all these things that WPF gives you, and triggering off a property change is actually an elegant way to use the entire WPF subsystem to accomplish your goals :)
A more general question to ask is: "Why am I trying to deal with this event in my ViewModel?"
If the answer has anything to do with view-only things like animations, I'd argue the ViewModel needs not know about it: code behind (when appropriate), Data/Event/PropertyTriggers, and the newer VisualStateManager constructs will serve you much better, and maintain the clean separation between View and ViewModel.
If something needs to "happen" as a result of the event, then what you really want to use is a Command pattern - either by using the CommandManger, handling the event in code behind and invoking the command on the view model, or by using attached behaviors in the System.Interactivity libs.
Either way, you want to keep your ViewModel as "pure" as you can - if you see anything View-specific in there, you're probably doing it wrong. :)
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