Search code examples
c#wpfxamluser-controlsdatatemplate

How to inject a view using datatemplate selector?


To solve this, I can imagine I need to use PRISM or a datatemplate selector. I'm not really sure. Well, let me explain my situation. I've got this class called BinaryProblem and is the model.

public class BinaryProblem<T> {
    public T Number1 { get; set; }
    public T Number2 { get; set; }
}

BinaryProblem is a generic class, so T can be int, double, decimal, or inclussive another one, Fraction.

public class Fraction {
    public int Numerator {get;set;}
    public int Denominator {get;set;}
}

The point is was thinking create a view for the primitive datatypes and another one for the fraction. This is the view:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <..Something.. Text="{Binding Number1}" Grid.Column="0" />
    <TextBlock Grid.Column="1" Text="+" />
    <..Something.. Text="{Binding Number2}"  Grid.Column="2" />
</Grid>

Where says <..Something..>, I do not know what to do. The idea is, if T is a primitive datatype should draw only a textblock; but if is a Fraction datatype should show the next template or something like this:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Text="{Binding Numerator}" />
    <Rectangle Grid.Row="1" Fill="Black" Height="5" />
    <TextBlock Grid.Row="2" Text="{Binding Denominator}" />
</Grid>

I don't want to create two views, I guess is it possible to avoid create two views? I mean, to have only one view and detect if must show an fraction template or the textblock.


Solution

  • Try this: First create data templates for the supported types:

        <DataTemplate DataType="{x:Type local:Fraction}" >
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <TextBlock Grid.Row="0" Text="{Binding Numerator}" />
                <Rectangle Grid.Row="1" Fill="Black" Height="5" />
                <TextBlock Grid.Row="2" Text="{Binding Denominator}" />
            </Grid>
        </DataTemplate>
    
        <DataTemplate xmlns:sys="clr-namespace:System;assembly=mscorlib" 
                      DataType="{x:Type sys:Int32}" >
            <TextBlock Background="Green" Text="{Binding}" />
        </DataTemplate>
    

    Then replace the 'Something' part with a ContentPresenter:

    <ContentPresenter Grid.Column="0" Content="{Binding Number1}">