Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ContentTemplateSelector is only called one time showing always the same datatemplate

I have made a sample demo VS 2010 RC sample project, because in my production project I have the same error using MVVM.

In my sample demo project I use only Code-behind without 3rd party dependencies so you can download the demo project here and run it for yourself: http://www.sendspace.com/file/mwx7wv

Now to the problem: When I click the girls/boys button it should switch the datatemplate, not?

What do I wrong?

OK I offer here a code snippet too:

Code-Behind MainWindow.cs:

namespace ContentTemplateSelectorDemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Person person;

        public MainWindow()
        {
            InitializeComponent();

            person = new Person(){ Gender = "xxx"};
            person.IsBoy = true;    

            ContentGrid.DataContext = person;
        }

        private void btnBoys_Click(object sender, RoutedEventArgs e)
        {
            person.IsBoy = true;
            person.IsGirl = false;
            this.ContentGrid.DataContext = person;
        }

        private void btnGirls_Click(object sender, RoutedEventArgs e)
        {
            person.IsGirl = true;
            person.IsBoy = false;
            this.ContentGrid.DataContext = person;    
        }        
    }
}

XAML MainWindow.xaml:

<Window x:Class="ContentTemplateSelectorDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ContentTemplateSelectorDemo"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>            
        <DataTemplate x:Key="girlsViewTemplate">
            <local:UserControl1 />
        </DataTemplate>

        <DataTemplate x:Key="boysViewTemplate" >
            <local:UserControl2 />
        </DataTemplate>

        <local:PersonDataTemplateSelector x:Key="PersonSelector" />            
    </Window.Resources>

    <Grid x:Name="ContentGrid" >
        <StackPanel>
            <Button Name="btnGirls" Click="btnGirls_Click">Switch Girls</Button>
            <Button Name="btnBoys" Click="btnBoys_Click">Switch Boys</Button>
        <ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource ResourceKey=PersonSelector}" />
        </StackPanel>
    </Grid>
</Window>

DataTemplateSelector class:

public class PersonDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item,DependencyObject container)
    {
        if (item is Person)
        {
            Person person = item as Person;

            Window window = Application.Current.MainWindow;

            if (System.ComponentModel.DesignerProperties.GetIsInDesignMode( window))
                return null;

            if (person.IsBoy)               
                return window.FindResource("boysViewTemplate") as DataTemplate;
            if (person.IsGirl)            
                return window.FindResource("girlsViewTemplate") as DataTemplate;

        }
        return null;
    }
}

:)

like image 501
msfanboy Avatar asked Apr 02 '10 09:04

msfanboy


1 Answers

Note: I think this method is quite clumsy, but could work for some scenarios. I favor the method of using a trigger (from Neil) that I posted as a separate answer.


Another possible way is to bind the Content of the ContentTemplateSelector to the property that determines the template that should be selected. For instance here I have two different toolbars chosen based upon the value of SourceSystem. I set the Content to be the sourcesystem property itself.

<ContentControl ContentTemplateSelector="{StaticResource toolbarTemplateSelector}" 
                DataContext="{Binding}" Content="{Binding SourceSystem}" />

The template selector simply looks at the source system and returns the necessary template.

If the template needs access to the datacontext of the control, just use element binding to set it.

 <UserControl.Resources>
    <DataTemplate x:Key="toolbar1">
        <views:OrdersToolbar1View Margin="0,5,0,0" 
               DataContext="{Binding ElementName=control,Path=DataContext}"/>
    </DataTemplate>
    <DataTemplate x:Key="toolbar2">
        <views:OrdersToolbar2View Margin="0,5,0,0" 
               DataContext="{Binding ElementName=control,Path=DataContext}"/>
    </DataTemplate>
 </UserControl.Resources>
like image 92
Simon_Weaver Avatar answered Nov 10 '22 07:11

Simon_Weaver