1
votes

I'm using a MVVM-Pattern with a ModelView-First approach. This works fine, so far. Now I have a UserControl (View) which should display various content depending on a Property located in my ViewModel.

First, I tried to solve the issue with DataTemplates and a DataTemplateSelector (See this tutorial) This was working very well. But I was not happy with the solution, because then I have a class (the overrided DataTemplateSelector) which is not connected to the ViewModel and can't be filled from the model.

So I tried to create a own TemplateSelector which uses a Property from the ViewModel. Unfortunately the DataTrigger is not triggering. The Binding from a CheckBox to the ViewModel is also working but not at the DataTrigger (even the designer can't find this path).

Ok, please have a look at the code:

<UserControl.Resources>     
        <!--Define Template which is displayed for Users-->
        <DataTemplate x:Key="templateUser">     
            <Image 
                Name="logo"
                Source="blanked out"
                HorizontalAlignment="Center" 
                VerticalAlignment="Center" />
        </DataTemplate>

        <!--Define Template which is displayed for Administrators-->
        <DataTemplate x:Key="templateAdmin">
            <TextBlock Background="Yellow" Margin="3" Text="YEAH, I'm an Administrator" />
        </DataTemplate>

        <!--My own TemplateSelectpr-->
        <DataTemplate x:Key="myTemplateSelector">
            <ContentControl x:Name="DynamicContent" ContentTemplate="{StaticResource templateUser}"/>

            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=IsAdministrator}" Value="true">
                    <Setter TargetName="DynamicContent" Property="ContentTemplate" Value="{StaticResource templateAdmin}" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </UserControl.Resources>
    <Grid>
            <ContentPresenter ContentTemplate="{StaticResource myTemplateSelector}"/>
    </Grid> 

Of course, I can seperate the Task in two further contentcontrols, but I don't want to maintain those if same content is intersecting. So can someone suggest anything?

Best regards, and thanks in advance!

2

2 Answers

1
votes

The simpler, the better: use a single template, which includes all the controls you need to show. Then switch their visibility using a binding to your property:

<UserControl.Resources>
    <DataTemplate x:Key="myTemplate">
      <Grid>
        <Grid Visibility="{Binding IsAdministrator, Converter={StaticResource BooleanToVisibilityConverter}}">
           <!-- Content for admin -->
        </Grid>
        <Grid Visibility="{Binding IsAdministrator, Converter={StaticResource NotBooleanToVisibilityConverter}}">
           <!-- Content for user -->
        </Grid>
      </Grid>
    </DataTemplate>
</UserControl.Resources>

<Grid>
        <ContentPresenter ContentTemplate="{StaticResource myTemplate}"/>
</Grid> 
1
votes

Answer is to long for comment

Arnaud Weil brought me on the right way:

To access the Property 'IsAdministrator' in ViewModel from the Datatemplate, I gave the UserControl a Name e.g.:

<UserControl    
    x:Class="blanked out"
    x:Name="this"

Used the code from Arnaud with some modifications, to inherit the Binding to the ViewModel from UserControl

<UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        <helper:NotBooleanToVisibilityConverter x:Key="NotBooleanToVisibilityConverter"/>
        <DataTemplate x:Key="myTemplate">
            <Grid>
                <Grid Visibility="{Binding DataContext.IsAdministrator, ElementName=this, Converter={StaticResource BooleanToVisibilityConverter}}">
                    <!-- Content for admin -->
                    <TextBlock Background="Yellow" Margin="3" Text="ICH BIN ADMNIN; JUCHUUU" />
                </Grid>
                <Grid Visibility="{Binding DataContext.IsAdministrator, ElementName=this, Converter={StaticResource NotBooleanToVisibilityConverter}}">
                    <!-- Content for user -->
                    <Image 
                        Name="logo"
                        Source="/blanked out"
                        HorizontalAlignment="Center" 
                        VerticalAlignment="Center" />
                </Grid>
            </Grid>
        </DataTemplate>
    </UserControl.Resources>

And for the inverted BooleanToVisibilityConverter:

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace blankedout.Helper
{
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class NotBooleanToVisibilityConverter:IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var boolValue = (bool)value;
            return !boolValue ? Visibility.Visible : Visibility.Hidden;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Thanks once again to Arnaud Weil

Regards