Caliburn.Micro - doing something when a view becomes visible - wpf

I am currently getting into WPF and Caliburn.Micro ,for now without something like MEF or Autofac.
Right now i am trying to execute some code in a viewmodel right after its view becomes visible.
In a related tutorial this code displays a messagebox just before a view is shown:
protected override void OnActivate()
{
MessageBox.Show("Page Two Activated"); //Don't do this in a real VM.
base.OnActivate();
}
Mr. Eisenberg then writes this:
Remember, if you have any activation logic that is dependent on the
view being already loaded, you should override Screen.OnViewLoaded
instead of/in combination with OnActivate.
This is what i have:
protected override void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
MessageBox.Show("OnPageTwoViewLoaded");
}
I also tried it via a Grid EventTrigger and a cal:ActionMessage.
But in all three cases the MessageBox appears before the view is visible.
Surely i am missing something, what am i doing wrong?

Maybe not the most elegant solution, but I guess you can do this from the code-behind, since - strictly speaking - this is a very view/gui specific thing you're trying to do here. For instance in OnInitialized or OnRender. If you give your view a reference to the EventAggregator, you could raise an event and make the view model - or whatever class you want, subscribe to this event and do it's thing. Or in the case of showing a MessageBox, you really wouldn't have that any place else than in the View anyway.

Related

WPF: Button Click on one ViewModel should exxecute a command on another viewmodel

i am kind of new to mvvm and i understand the basic concpects.
now i have a question:
i have two different viewmodels, which will be attached together on another wpf gui.
in one viewmodel, there is a button and a checkbox; ("left sided control")
now the "trick":
on the other viewmodel there is a checkbox, too. ("right sided control")
now: if the button was hit, then on the other viewmodel should be checked if the checkbox is set, too.
basicly i would do it with an event or a "signal", but the thing is, if the checkbox on the "right sided control" is checked, it needs a value from the "left sided".
the implemenation would be done by an event, and if so: how can i pass parameters??
as i am new to that mvvm i don't know exactly what i am really looking for and which solution would be "state of the art" and "mvvm"-style.
have a look at http://www.galasoft.ch/mvvm/, it has a Messenger class that i think it's exactly what you need
Firstly the UI interaction sounds a little complicated - it might be worth reviewing your UI interaction - could that be simplifed? Assuming not (i.e complexe UI need is real):
It sounds like left side view model (LVM) depends on a property of right side view model (RVM). So is it possible to setup that relationship in your view model properties i.e. Can LVM be setup to hold a ref to RVM and that the property that is bound to the check box itselft checks the dependant property on RVM? Then your command (bound on LVM) just has to check a proerty of LVM.
You need to use some Event Aggregator (for example from Prism library) for such stuff. Here is an c# pseudocode example of how to do it using Prism's Event Aggregator:
In your RVM:
_eventAggregator.GetEvent<LeftCBCheckedEvent>()
.Subscribe(SaveStateOfLeftCBLocally);
...
private void SaveStateOfLeftCBLocally(bool isLeftCBChecked)
{
_isLeftCBChecked = isLeftCBChecked;
}
In your LVM:
public bool IsLeftCBChecked {get; set;}
...
_eventAggregator.GetEvent<LeftCBCheckedEvent>().Publish(IsLeftCBChecked);
Event definition:
public class LeftCBCheckedEvent : CompositePresentationEvent<bool>{}
So when that button is pressed you'll already know the state of your left check box. And I strongly recommend to check Prism, it's a great library for composite applications, I think it can add a big value to your project.

WPF MVVM Problems with View

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.

MVVM messaging or events or what other option out therer?

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!
}

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}" />

WPF: how to signal an event from ViewModel to View without code in codebehind? [duplicate]

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. :)

Resources