Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h2>Quick Answer and Summary:</h2> <p>As you noticed, what you really want is to parameterize your ViewModel from XAML. So my instinct is to write an <strong>Attached Behavior</strong> to provide the ability to pass in parameters for your ViewModel. And more specifically, what comes to mind is that we want a <em>single</em> Attached Behavior class that we can specify <em>both</em> (a) which ViewModel we want <em>and</em> (b) a parameter for that ViewModel. To satisfy <em>both</em> of these desires in a single class while also being as <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="nofollow">DRY</a> as possible, I think it is easiest to use a "Blend" Behavior, since Blend behaviors are not static classes and thus it seems much easier to be able to use them to pass in both pieces of related information together.</p> <h2>Explanation:</h2> <p>First a quick disclaimer: I have not used MEFedMVVM or Prism (but I have used other MVVM libraries), so my answer uses a more general approach that I have recently learned to make use of. Thus, this approach does not rely on any "magic" stuff that Prism may give you when you use things in their "normal" way (i.e., hooking up DataContext automatically, etc.), so let that frame this mindset.</p> <p>For a good writeup about the differences between "regular" Attached Behaviors and "Blend" Behaviors, I like <a href="http://briannoyes.net/2012/12/20/AttachedBehaviorsVsAttachedPropertiesVsBlendBehaviors.aspx" rel="nofollow"><strong>this blog post</strong></a>. I won't repeat his explanations here, but the key thing I notice is that regular Attached Behaviors seem to just rely on a <em>single</em> piece of information (i.e., a single "parameter") in order to do its thing. Such as (from the blog post):</p> <pre><code>&lt;GridView local:ItemClickNavBehavior.Destination="Home" ...&gt; </code></pre> <p>Now lets put that in terms of your case, and examine how it could work <strong>if you just used <em>regular</em> Attached Bahaviors</strong>. You would write an Attached Behavior class, call it "MyViewModel1Creator" that would: <strong>(1)</strong> register an attached property called "Type" and <strong>(2)</strong> include a change callback handler for "Type" (which also gets called when its initially set - see the "HookupBehavior" method in the linked blog post). In this change callback you would instantiate "ViewModel1" and pass in to it the value of the "Type" Attached Property. Also in this method you could take care of any other necessities such as setting the DataContext for the View, etc. You can access the object that the Attached Property is attached to (the the View object in this case) by using the first parameter in the callback handler (the Dependency object param).</p> <p>Then your Xaml use of the "MyViewModel1Creator" class would look like:</p> <pre><code>&lt;views:MyView x:Name="view1" MyBehaviors:MyViewModel1Creator.Type="X" /&gt; &lt;views:MyView x:Name="view2" MyBehaviors:MyViewModel1Creator.Type="Y" /&gt; </code></pre> <p>Although this would work, I see a <strong>disadvantage to this approach</strong> (using <em>regular</em> Attached Properties). To use this approach, you would have to create a separate Attached Behavior class for each ViewModel, meaning that if you had 3 ViewModels ("ViewModel1", "ViewModel2", "ViewModel3") then you would need to write 3 Attached Behavior classes ("ViewModel1Creator", "ViewModel2Creator", "ViewModel3Creator"). Each one would instantiate its respective ViewModel (and expose a "Type" Attached Property as shown above). Another disadvantage is that it seems to be harder to find a way to add <em>additional</em> parameters to pass in. </p> <p>A slightly alternate approach to the one above, but <strong>equally deficient</strong> in terms of being <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="nofollow">DRY</a>, would be to have a single class (call it "MyViewModelCreator" - without the "1" this time) that houses several Attached Properties with names like "CreateViewModel_1_WithType", "CreateViewModel_2_WithType", "CreateViewModel_3_WithType", etc. Its usage would look like:</p> <pre><code>&lt;views:MyView x:Name="view1" MyBehaviors:MyViewModelCreator.CreateViewModel_1_WithType="X" /&gt; &lt;views:MyView x:Name="view2" MyBehaviors:MyViewModelCreator.CreateViewModel_1_WithType="Y" /&gt; </code></pre> <p>Again, these approaches are not very DRY, so we really need to...</p> <h2><strong>Now let's consider how it could work if we used a <a href="http://msdn.microsoft.com/en-us/library/ff726531%28v=expression.40%29.aspx" rel="nofollow">"Blend" behavior</a></strong>:</h2> <p>You would write a class that derives from a typed Behavior - for your views it would probably be <code>Behavior&lt;UserControl&gt;</code>, so your class heading might look like:<br> <code>public class ViewModelSetupBehavior : Behavior&lt;UserControl&gt;</code>. In this class you would: <strong>(1)</strong> register as many Dependency Properties as you like, including a "Type" Dependency Property, and a "ViewModelName" Dependency Property, and <strong>(2)</strong> You will override the <code>OnAttached()</code> method, where you will instantiate whichever ViewModel is indicated by the value of the "ViewModelName" Dependency Property, and also pass in to it the value of the "Type" Dependency Property. Again, this would be the place to also handle any other necessities such as setting the DataContext for the View, etc. You can access the object that the Behavior is "attached to" (your View in this case) by using the <code>AssociatedObject</code> property.</p> <p>This could let you do this:</p> <pre><code>&lt;views:MyView x:Name="view1"&gt; &lt;i:Interaction.Behaviors&gt; &lt;MyBehaviors:ViewModelSetupBehavior ViewModelName="ViewModel1" Type="X" SomeOtherParam="bla" /&gt; &lt;/i:Interaction.Behaviors&gt; &lt;/views:MyView&gt; &lt;views:MyView x:Name="view2"&gt; &lt;i:Interaction.Behaviors&gt; &lt;MyBehaviors:ViewModelSetupBehavior ViewModelName="ViewModel1" Type="Y" /&gt; &lt;/i:Interaction.Behaviors&gt; &lt;/views:MyView&gt; </code></pre> <p>Now notice that we have the ability to use a <em>single</em> Behavior class for the creation of <em>all</em> of our ViewModels, and we can pass in <em>several</em> parameters to dictate how we want the ViewModel to be instantiated.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload