Jasper
Jasper

Reputation: 484

Set ViewModel in UserControl.Resources from ancestor Page

Suppose I have a usercontrol as below.

<UserControl 
x:Class="MyApp.Controls.MyList"
xmlns:local="using:MyApp.Controls"
xmlns:viewModels="using:MyApp.ViewModels"
>
  <UserControl.Resources>
      <viewModels:CustomerViewModel x:Key="ViewModel"/>
  </UserControl.Resources>

  <UserControl.DataContext>
      <Binding Source="{StaticResource ResourceKey=ViewModel}" />
  </UserControl.DataContext>

  <UserControl.Content>
      <ListView ItemsSource={Binding ItemList} />
  </UserControl.Content>
</UserControl>

I'm using this control in a Page:

<Page
  x:Class="MyApp.Views.CustomerPage"
  xmlns:control="using:MyApp.Controls">

    <controls:MyList />

</Page>

So far so good.

Now I'd like to re-use this same control for other ViewModels. My CustomerViewModel, like all my viewmodel is inherited from interface IViewModel.

What can I do to use the same control for let's say SalesOrderViewModel?

I tried the following, but that throws an XamlParseException exception upon InitializeComponent():

<Page
  x:Class="MyApp.Views.CustomerPage"
  xmlns:control="using:MyApp.Controls">

    <controls:MyList>
      <controls:MyList.Resources>
        <viewModels:SalesOrderViewModel x:Key="ViewModel"/>
      </controls:MyList.Resources>
    </controls:>

</Page>

What would be a working approach here?

Upvotes: 1

Views: 1374

Answers (2)

Petter Hesselberg
Petter Hesselberg

Reputation: 5498

Viewmodel (just my quickie, a bit different from yours):

public class ViewModel
{
    public string Value { get; set; } = "Default";
}

UserControl:

<UserControl
    x:Class="App1.MyList"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid>
        <TextBlock Text="{Binding Value}" />
    </Grid>
</UserControl>

In the page, set different DataContexts for different Usercontrols:

<Page.Resources>
    <local:ViewModel x:Key="ViewModel1" Value="First"/>
    <local:ViewModel x:Key="ViewModel2" Value="Second"/>
</Page.Resources>

<StackPanel>
    <local:MyList DataContext="{StaticResource ViewModel1}" />
    <local:MyList DataContext="{StaticResource ViewModel2}" />
</StackPanel>

Upvotes: 1

RDaniel
RDaniel

Reputation: 49

You can use data templates for this. You can set the data type of a data template with your view model.

<UserControl.Resources>
  <DataTemplate DataType="{x:Type vm:ImageViewModel}" >
    <view:ImageView/>
  </DataTemplate>

  <DataTemplate DataType="{x:Type vm:VideoViewModel}">
    <view:VideoView/>
  </DataTemplate>
</UserControl.Resources>
<UserControl x:Class="Overlay.View.ImageView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Example.View"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
       <Image Source="/Assets/screenshot.png"/>   
    </Grid>
</UserControl>

<UserControl x:Class="Overlay.View.VideoView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Example.View"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <MediaElement x:Name="Player" Source="./Assets/Sample_mp4.mp4"/>
</Grid>

Suppose you have a view model for your page control. This view model can have a property of type IViewModel which can be set depending on some conditions. You can bind this property to the content property of a content control or content presenter.

<ContentControl Grid.Row="0" x:Name="ctnCtrl" Content="{Binding CurrentVm}"/>

The content control will load the view depending on your selected view model.

Upvotes: 0

Related Questions