Question

I have a User class and an Author class that extends User. I have an ObservableCollection<User> being displayed in a ListBox. For this, I have a DataTemplate to display each item and another to display each selected item. I also have a column of TextBoxes that are bound to the properties of the ListBox.SelectedItem property. So far, so good.

At the moment, I am displaying extra controls in the column and DataTemplates if the selected User is an Author and it all works fine, but I'm cheating. I have added an IsAuthor bool property into the User class so that I could bind to it and determine whether a User was an Author. I know it's wrong, but I couldn't work out any other way to do it, so my first question is how do you display extended classes differently from the base class? I tried a different DataTemplate for the type Author, but it never worked... maybe because the collection was of type User?

The second question is should I have all of the many TextBox controls in the column in a UserControl and change the Visibility of the Author related controls, or somehow put them in a DataTemplate and create one for each type? I am using the first method currently and the problem is that each control bound to an Author property is throwing errors (I can see them in the Output window in Visual Studio) when the currently selected item is not an Author.

Was it helpful?

Solution

I have a similar setup which uses data templates and it works just fine with inherited classes. This is how I did it.

<ListBox Name="UserList" ItemsSource="{Binding Path=Users}"
         ItemTemplate="{StaticResource ShowUserName}"
         SelectedItem="{Binding Path=SelectedUser, Mode=TwoWay}">
</ListBox>
<ContentControl Content="{Binding ElementName=UserList, Path=SelectedItem}"/>

In the Window.Resources section I have the following DataTemplates:

<DataTemplate x:Key="ShowTime" DataType="TestApp.User">
    <TextBlock Text="{Binding Path=Name}" HorizontalAlignment="Center"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:User}">
   <StackPanel Margin="10">
     <TextBlock Text="{Binding Path=Name}"/>
     <TextBlock Text="{Binding Path=Age}"/>
   </StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Author}">
   <StackPanel Margin="10">
     <TextBlock Text="{Binding Path=Name}"/>
     <TextBlock Text="{Binding Path=Age}"/>
     <TextBlock Text="{Binding Path=FirstTitle}"/>
   </StackPanel>
</DataTemplate>

The first template is what will be displayed in the list itself. We are referencing it by key in the ItemTemplate property of the listbox. The other two data templates are used by the content control when determining what to display for the selected item. When the selected item is just a User, the User DataTemplate will be displayed, if an author is selected, the author DataTemplate will be shown.

The x:Type local:Author is referring to the the class type. local should be declared in your namespace declarations.

xmlns:local="clr-namespace:TestApp"

Keep in mind that this is my namespace, you will have to specify the one you are using. And of course the data templates are just basic examples, presumably you will want to do something more tailored to your application.

However it might be irritating to have to define two separate Data templates that are almost exactly the same for your two classes. Although you certainly could. I do it in my own application (not in this example), because what I want to display for each type are vastly different.

So what might be useful is to create a common DataTemplate for all the User properties, and simply extend this DataTemplate for Authors. If you want to do that you could set up your templates this way:

<DataTemplate x:Key="UserTemplate">
  <!-- show all the properties of the user class here -->
</DataTemplate>
<DataTemplate DataType="{x:Type local:User}">
  <ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource UserTemplate}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Author}">
  <StackPanel>
    <ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource UserTemplate}"/>
    <!-- show all the additional Author properties here -->
  </StackPanel>
</DataTemplate>

So as you can see, both of the DataTemplates for User and for Author start out using the DataTemplate called "UserTemplate". But in the Author DataTemplate we will add Author specific properties.

I hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top