TriggerAction w/ TargetControl of a ViewModel

TriggerAction w/ TargetControl of a ViewModel

Old forum URL: forums.lhotka.net/forums/t/10743.aspx


skagen00 posted on Thursday, October 06, 2011

We have a pretty good sized application that we are moving from 3.8.3 to 4.1.

One of the things that created more work than anticipated (overall the upgrade wasn't too bad) was the change for ViewModelBase to inherit from DependencyObject instead of FrameworkElement.

It involved adjusting some SetBinding calls in codebehind of the viewmodel to use BindingOperations.SetBinding, and that obviously wasn't too bad (it wasn't clear whether Silverlight 4 supports this - in the documentation, it suggests an exception will be thrown if it isn't a FrameworkElement or other DependencyObject descendant that I can't recall). 

One thing we did, for good or for bad, is to have a triggeraction against the save of a viewmodel (which has a view via FloatableWindow) and the overall datacontext for the floatable window ends up being a separate ViewModel that we end up making a method call against when the second viewmodel saves.

Of course, TargetControl in triggeraction is typed to be a FrameworkElement, so a viewmodel cannot be a TargetControl.

Is our use of triggeraction in this way something we need to get away from, or is this acceptable and could triggeraction's targetcontrol be typed to be dependencyobject? I looked at the code very briefly and it looked like it might work.

 

skagen00 replied on Thursday, October 06, 2011

It did work, adjusting the TriggerAction to use DependencyObject instead of FrameworkElement - it did introduce the need to cast the TargetControl in TriggerAction event handlers, though, in cases where we looked @ datacontext & such.

In the end, we temporarily decided to make our only adjustment to CSLA, retaining the inheritence of FrameworkElement for ViewModelBase.  It seems like that inheritance gives you a little more flexibility, even if it's not consistent with WPF (apparently a collegue of mine said that was in the notes).

I suspect we'll address this issue on our end later on to get back to being fully standard; if there's anything "future-thinking" that would say "you want to get away from using FrameworkElement for viewmodels", that would be good to know.

RockfordLhotka replied on Thursday, October 06, 2011

There are two reasons for being a DependencyObject (rather than a simple class implementing INotifyPropertyChanged):

  1. You can write code in the viewmodel to detect if you are in design mode
  2. You can bind to the Model property to create cascading (parent-child) viewmodels

The second one is the primary driver for using the DO base type. This is important for some MVVM scenarios where you don't use a CollectionViewSource, and want to have a set of XAML resources that expose a hierarchy of parent-child viewmodels.

The design mode thing can be solved in other ways, so it isn't a requirement as much as a convenience.

fwiw, I pretty much always use CollectionViewSource objects now, so I am open to arguments that ViewModelBase should become a simple class and not inherit from anything. That'd obviously be a breaking change though, and there's no strong motivation (that I'm aware of) to make this change.

 

skagen00 replied on Thursday, October 06, 2011

So the notion of hooking up to a trigger action to a view model's event doesn't make any sense? (I'm not sure if I rambled too much to be unclear... it was mainly about losing the ability to use the viewmodel as a target control in a trigger action.)

My guess is that  you were saying that the only two reasons why it's a dependency object at all is to support the two items you listed, and that having a trigger action on a viewmodel event wasn't an option you necessarily feel makes a lot of sense.

Doesn't seem impractical to want to do that, but maybe I'm overlooking a reason why it's a bad idea.

TygreWolf replied on Monday, July 01, 2013

I hate to bring up an old issue, but I'm having a similar problem myself.  I have one view with two view models - one view model is a read-only list (UserList containing UserInfo objects), and the other view model is an editable instance of an item in the list (User).

I'd like to be able to use the TriggerAction and define my XAML in such a way that when a User object is saved (in my UserEditViewModel), it will call a RefreshList() method on my UserListViewModel object, which will refresh the list.

Currently, I believe I'm breaking the MVVM pattern by passing my UserListViewModel as a resource in the MethodParameter of my "save" button, and then calling refresh in my Save routine of my UserEditViewModel:

<Button x:Name="BtnSaveUser" IsEnabled="{Binding Path=IsSavable}">Save User</Button>
<csla:TriggerAction x:Name="BtnSaveUserTrigger" DataContext="{Binding Source={StaticResource UserEditViewModel
}}"
TargetControl="{Binding ElementName
=BtnSaveUser}"
MethodParameter="{StaticResource UserListViewModel
}"
MethodName
="SaveUser"/>

public void SaveUser(object sender, ExecuteEventArgs
e)
{
BeginSave();
var ulvm = (UserListViewModel
) e.MethodParameter;
ulvm.RefreshList();
}

I really don't like doing it this way, but I just don't know how I can tell my User List to refresh after my single user is saved, since each are defined in two different view models.  Can you define the CSLA TriggerAction to listen to an event directly on a view model?

Copyright (c) Marimer LLC