views:

103

answers:

1

I have a WPF UserControl with a ListBox and ContentPanel. The ListBox is bound to a ObservableCollection that has apples and oranges in it.

What is considered the proper way to have it setup so if I select an apple I see an AppleEditor on the right and if I select an orange an OrangeEditor shows up in the content panel?

+1  A: 

I would suggest using DataTemplating to create and apply the different editors. Depending on how different your 'apples' and 'oranges' are I would recommend using a DataTemplateSelector. Also, if they had something like a Type property you could also use DataTriggers to switch out the editors.

Lets set up a small sample with apples and oranges. They'll have some shared properties, and a few different properties as well. And then we can create an ObservableCollection of the base IFruits to use in the UI.

public partial class Window1 : Window
{
 public ObservableCollection<IFruit> Fruits { get; set; }
 public Window1()
 {
  InitializeComponent();

  Fruits = new ObservableCollection<IFruit>();
  Fruits.Add(new Apple { AppleType = "Granny Smith", HasWorms = false });
  Fruits.Add(new Orange { OrangeType = "Florida Orange", VitaminCContent = 75 });
  Fruits.Add(new Apple { AppleType = "Red Delicious", HasWorms = true });
  Fruits.Add(new Orange { OrangeType = "Navel Orange", VitaminCContent = 130 });

  this.DataContext = this;
 }
}

public interface IFruit
{
 string Name { get; }
 string Color { get; }
}

public class Apple : IFruit
{
 public Apple() { }
 public string AppleType { get; set; }
 public bool HasWorms { get; set; }
 #region IFruit Members
 public string Name { get { return "Apple"; } }
 public string Color { get { return "Red"; } }
 #endregion
}

public class Orange : IFruit
{
 public Orange() { }
 public string OrangeType { get; set; }
 public int VitaminCContent { get; set; }
 #region IFruit Members
 public string Name { get { return "Orange"; } }
 public string Color { get { return "Orange"; } }
 #endregion
}

Next, we can create DataTemplateSelector, that will just check the type of the Fruit and assign the correct DataTemplate.

public class FruitTemplateSelector : DataTemplateSelector
{
 public override DataTemplate SelectTemplate(object item, DependencyObject container)
 {
  string templateKey = null;

  if (item is Orange)
  {
   templateKey = "OrangeTemplate";
  }
  else if (item is Apple)
  {
   templateKey = "AppleTemplate";
  }

  if (templateKey != null)
  {
   return (DataTemplate)((FrameworkElement)container).FindResource(templateKey);
  }
  else
  {
   return base.SelectTemplate(item, container);
  }
 }
}

Then in the UI, we can create the two templates for Apples and Oranges, and use the selector to determine which gets applied to our content.

<Window x:Class="FruitSample.Window1"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:local="clr-namespace:FruitSample"
 Title="Fruits"
 Height="300"
 Width="300">
<Window.Resources>

 <local:FruitTemplateSelector x:Key="Local_FruitTemplateSelector" />

 <DataTemplate x:Key="AppleTemplate">
  <StackPanel Background="{Binding Color}">
   <TextBlock Text="{Binding AppleType}" />
   <TextBlock Text="{Binding HasWorms, StringFormat=Has Worms: {0}}" />
  </StackPanel>
 </DataTemplate>

 <DataTemplate x:Key="OrangeTemplate">
  <StackPanel Background="{Binding Color}">
   <TextBlock Text="{Binding OrangeType}" />
   <TextBlock Text="{Binding VitaminCContent, StringFormat=Has {0} % of daily Vitamin C}" />
  </StackPanel>
 </DataTemplate>

</Window.Resources>

<DockPanel>
 <ListBox x:Name="uiFruitList"
    ItemsSource="{Binding Fruits}"
    DisplayMemberPath="Name" />
 <ContentControl Content="{Binding Path=SelectedItem, ElementName=uiFruitList}"
     ContentTemplateSelector="{StaticResource Local_FruitTemplateSelector}"/>
</DockPanel>
</Window>
rmoore
Thanks for the super detailed answer.
Jake Pearson
Also, can I use a Template Selector to select between 2 different UserControls instead of separate templates?
Jake Pearson
If you want to switch between UserControls, then take a look at using a DataTrigger instead, and set the Content in the Trigger's setter.
rmoore