Rookie questions on WPF MVVM and user controls - wpf

I am beginning WPF, and I am having a bit of a hard time implementing data binding.
Specifically, I have created a simple user control which holds a Label and a Button.
For this user control, I have created a ViewModel which holds just two properties, string "Text" and SimpleEnum "Status".
The point of the control is to display a status of something, like "Connected" yes/no, etc. The background color of the button indicates the status.
My XAML looks something like this
<Control.DataContext>
<vm:OnOffStatusViewModel />
</Control.DataContext>
<Label x:Name="label1" Height="Auto" HorizontalAlignment="Left" Content="{Binding Text}" Width="280" />
<Button Style="{StaticResource GlassButton}" Height="14" Width="14" Background="{Binding Status}" Grid.Column="1" />
with xmlns:vm="clr-namespace:Controls"
The code-behind has a property ViewModel exposing the view model, implementing INotifyPropertyChanged, and initializes as _viewModel = (OnOffStatusViewModel) DataContext;
Now, in my view that is using this control, I have managed to set the Text to something, as I in my implementing view code-behind have onOffStatus1.ViewModel.Text = ..., however, the status is set by enum, and is as such not really bindable to the background property of the button.
My questions related to this:
Is the way I have done the control correct? If not, what is the proper way of implementing data binding in user controls?
How can I have my enum status update the background property of the button using binding?

How can I have my enum status update the background property of the button using binding?
It's recommended to use a value converter for this task, returning a brush for every possible value of the enumeration. This way, your view model does not need to know anything about colors or brushes, and you can use the converter wherever you would like to visualize the status.
XAML
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<UserControl.Resources>
<local:StatusColorConverter x:Key="StatusColorConverter" />
</UserControl.Resources>
<Button Background="{Binding Status, Converter={StaticResource StatusColorConverter}" />
</UserControl>
Converter
public enum Status
{
Connected
}
public class StatusColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
switch ((Status)value)
{
case Status.Connected: return new SolidColorBrush(Colors.Green);
}
return new SolidColorBrush(Colors.Black);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Is the way I have done the control correct? If not, what is the proper
way of implementing data binding in user controls?
Your implementation seems fine to me. You might want to eliminate the coupling between the view model and the view (which currently holds a reference to the view model) via dependency injection. But this depends on your use-cases and the architecture you want to use.

I would take a slightly different approach than the other answers here, I like to put the code and logic into my view models directly, so here's how I would do it:
<Control.DataContext>
<vm:OnOffStatusViewModel />
</Control.DataContext>
<Label x:Name="label1" Height="Auto" HorizontalAlignment="Left" Content="{Binding Text}" Width="280" />
<Button Style="{StaticResource GlassButton}" Height="14" Width="14" Background="{Binding ButtonBg}" Grid.Column="1" />
In the VM:
public MyStatus Status
{
get { return _status; }
set
{
_status = value;
OnPropertyChanged("Status");
ButtonBg = Colors.Red;
}
}
public Color ButtonBg
{
get { ... }
set { ... }
}
Since your button background is bound to a property on your view model, then you have the freedom to change that in reaction to whatever is going on in your view model without needing to move logic or code out to converters and templates.

Personally, I have NOT been able to use custom UserControls with MVVM. Either my mind hasn't wrapped around how to use them together or they just don't mix. I use DataTemplates for everything that's not a Window.
Keeping it concise...
OnOffStatusVM : INPC
string Status
Color Color (or Brush)
(set Color when enum value updates)
(OnOffStatus DataTemplate)
<DataTemplate DataType="{x:Type ViewModel:OnOffStatusVM}" x:Shared="False" x:Key="rezOnOffStatus">
<Grid>
<Label Height="Auto" HorizontalAlignment="Left" Content="{Binding Status}" Width="280" />
<Button Style="{StaticResource GlassButton}" Height="14" Width="14" Background="{Binding Color}" Grid.Column="1" />
</Grid>
</DataTemplate>
Usage if DataContext derives from OnOffStatusVM
<ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource rezOnOffStatus}" />
Usage if DataContext has a OnOffStatusVM OnOffStatus property
<ContentPresenter Content="{Binding OnOffStatus}" ContentTemplate="{StaticResource rezOnOffStatus}" />
Clarification provided if needed..

Related

User Control is not updating in window (WPF)

There is a UserControl which contains the bindings like below.
<TextBox Margin="5" Padding="0" IsReadOnly="True" Background="Transparent" BorderThickness="0" TextWrapping="Wrap" IsTabStop="False" FontSize="{DynamicResource TitleFontSize}" Text="{Binding ErrorTitle, Mode=OneWay}" />
it is bound by stack panel with name of GenericErrorControl and binding is as
<Visibility="{Binding IsShown, Mode=OneWay, Converter={StaticResource BoolToVis}, FallbackValue=Collapsed}">
Above control is added to one of view as below.
<views:GenericErrorControl Grid.Row="8" DataContext="{Binding GenericErrorControl, Mode=OneWay}" VerticalAlignment="Top/>
The problem is that user control is not appearing in the window after. In my viewmodel creating object i'm setting the value of IsShown but its not appearing. Kindly help and let me know if any other details needed.
It means that the binding is failing ie the fallback value is used from above code.
Things to do :
Ensure that your ViewModel inherits from the base class BindableBase ie it somehow implements the INotifyPropertyChanged interface and on property change, the PropertyChanged event is fired.
ie You have something similar to this in your view model.
private bool _IsShown;
public bool IsShown
{
get { return _IsShown; }
set { SetProperty(ref _IsShown, value); }
}
Double check your converter or post code here.

Handling GridItems click

Starting with a Grouped Items Page template, I want to be able to perform tasks on the grid items when they are clicked. Namely, I want to change the background image, and add/remove the underlying object to a list of selected items.
Here's my DataTemplate:
<GridView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="LightGray" BorderThickness="2" Margin="0,0,20,20">
<Grid HorizontalAlignment="Left" Width="390" Height="190">
<Grid.Background>
<ImageBrush ImageSource="/Assets/unselected.png" Stretch="None"/>
</Grid.Background>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Image VerticalAlignment="Top" Stretch="None" Source="{Binding ImageUrl}" Margin="10,10,0,0"/>
<StackPanel MaxWidth="270">
<TextBlock Text="{Binding Summary}"/>
<TextBlock Text="{Binding Brand}" />
<TextBlock Text="{Binding Detail}" TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
OnTap, I want to togle the ImageSource value of the Grid.Background from unselected.png to selected.png. This I believe I can do using VisualStates and Storyboards, but I've been unable to get this to work in the past (I'll spare you the chaos of my attempts in xaml).
Needless to say, I've tried following the steps detailed here using Blend, but the Grid.Background property doesn't seems to be state specific. If I try changing the background brush in the Pressed or Selected states, it also changes for the Normal state.
Since I want to grab the data context of the selected item and add/remove it from a list, should I just be handling all this together in an OnTap event handler? I would prefer to keep these concerns separated, but I'll do what I need to...
thanks!
One clean way to do this would be engage the selection method (Tap) in such a way that it only opperates on its items, and the items themselves have properties which Implement the INotifyPropertyChanged interface
Your View Model would have a collection of your custom objects that have properties that can notify the ui
public class MyObject : INotifyPropertyChanged
{
private string _summary;
public string summary
{
get {return _summary}
set
{
_summary = value;
OnPropertyChanged()
}
}
//Other Properties: brand || detail
private ImageSource _backgroundImage;
public ImageSource backgroundImage
{
get {return _backgroundImage}
set
{
_backgroundImage = value;
OnPropertyChanged()
}
}
private bool _IsSelected;
public bool IsSelected
{
get {return _IsSelected;}
set
{
_IsSelected = value;
OnPropertyChanged()
}
}
}
Then although your code behind can be used to change the value of IsSelected, or Background image ... if you choose to go with IsSelected, you can still separate your concerns by not directly setting the resource of the background image in code behind. The Codebehind will only iterate over the items to toggle the IsSelected property, and you can use xaml to define the image that the background should use by creating a custom converter.
public class MyCustomControlOrPage.cs : UserControl //Or ApplicationPage
{
//.......code
protected void HandleTap(object sender, GestureEventArgs e)
{
foreach(var item in ((Listbox)sender).ItemsSource)
{
((MyObject)item.IsSelected = (MyObject)item.Name == (e.NewItems[0] as MyObject).Name? true: false;
}
}
}
then the converter
public class BackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ImageSource source = value == true ? new BitmapImage(uriForSelected) : new BitmapImage(uriForunselected);
return source;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
BitmapImage thisValue = value as BitmapImage;
return thisValue;
}
}
and FINALLY the XAML where the grid background binds to the IsSelected property and allows the converter to transform the bool to an ImageSource of type BitmapImage:
//add xmlns:Converters=clr-namesapce:Yournamespace.UpTo.TheNamespaceBackgroundConverterIsIn" to the page or control definition
<UserControl.Resources>
<Converters:BackgroundConverter x:key="BgSourceConverter" />
</UserControl.Resources>
<GridView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="LightGray" BorderThickness="2" Margin="0,0,20,20">
<Grid HorizontalAlignment="Left" Width="390" Height="190">
<Grid.Background>
<ImageBrush ImageSource="{Binding Path=IsSelected, Mode=TwoWay, Converter={Binding Source={StaticResource BGSourceConverter}}}" Stretch="None"/>
</Grid.Background>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Image VerticalAlignment="Top" Stretch="None" Source="{Binding ImageUrl}" Margin="10,10,0,0"/>
<StackPanel MaxWidth="270">
<TextBlock Text="{Binding Summary}"/>
<TextBlock Text="{Binding Brand}" />
<TextBlock Text="{Binding Detail}" TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</GridView.ItemTemplate>

XAML collapse all child elements

I am working on a WPF Xaml application. The app has various stackpanels (that behave like icons) that I need to change the Visibility based on certain criteria.
Question:
How can I collapse all child elements (stackpanels)?
I am collapsing each one by one in the backend in vb.net. But much rather find a cool way to do it all at once.
In that case you can have two options
you can achieve it through style(This will not work if your following MVVM, that is if your binding)
Create coustom control
With Style:
Write the style as below with the target type which is used to display the image
<Window.Resources>
<Style TargetType="TextBox">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox Height="26" Width="200" Name="text1"/>
<TextBox Height="26" Width="200" Name="text2"/>
<Button Height="26" Width="200" Click="Button_Click_2" />
</StackPanel>
</Grid>
TextBox by default will be collapsed you can make it visible based on the search in the backend code
Custom control:
This will be just a wrapper for what ever control your using to display the icon but with only one change is that the default visibility will be collapsed. Then you can make it visible which ever you want
Override hide the already existing Visibility the property with the default value collapsed
You can set the visibility to parent instead of setting it to each control
For example
<StackPanel>
<StackPanel Name="pane1">
<Button Height="30" Width="200" Content="one" Click="Button_Click" />
</StackPanel>
<StackPanel Name="panel2">
<Button Height="30" Width="200" Content="two" Click="Button_Click_1" />
</StackPanel>
</StackPanel>
In you back end write the logic to set the visibility for stackpanel instead of each control
private void Button_Click(object sender, RoutedEventArgs e)
{
pane1.Visibility = Visibility.Collapsed;
panel2.Visibility = Visibility.Visible;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
panel2.Visibility = Visibility.Collapsed;
pane1.Visibility = Visibility.Visible;
}
If your following mvvm then bind to the visibility property of the stack panel like below
<StackPanel>
<StackPanel Visibility="{Binding CanShowPanel1}">
<Button Height="30" Width="200" Content="one" Click="Button_Click" />
</StackPanel>
<StackPanel Visibility="{Binding CanShowPanel2}">
<Button Height="30" Width="200" Content="two" Click="Button_Click_1" />
</StackPanel>
</StackPanel>
Bind them using an IValueConverter implementation like BooleanToVisibilityConverter.
If that isn't good enough, you will have to do them one by one. Maybe write a custom behavior?
The easiest way to do that is to use IValueConverter with parameter.
<StackPanel>
<StackPanel Visibility="{Binding TheQuery,Converter={StaticResource QueryConverter,ConverterParameter="MyFirstStackPanelVisible"}}">
</StackPanel>
<StackPanel Visibility="{Binding TheQuery,Converter={StaticResource QueryConverter,ConverterParameter="MySecondStackPanelVisible"}}">
</StackPanel>
</StackPanel>
public class QueryConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch((string)parameter)
{
case "MyFirstStackPanelVisible"
bool result =CheckQueryCriteriaForFirstStackPanel();
return Visibility.Visible or Visibility.Collapsed;
case "MySecondStackPanelVisible"
bool result =CheckQueryCriteriaForSecondStackPanel();
return Visibility.Visible or Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Of course you shouldn't make CheckQueryCriteriaFor... function for every case.
This approach guarantee logic to be in one place.

wpf trouble using dependency properties in a UserControl

I made a UserControl that is meant to be updated once every few seconds with data from a serial port. This UserControl should be very simple, consisting of a Label for a field name, and another Label containing the field value. I say that it should be simple, but it doesn't work. It does not update at all, and doesn't even display the field name.
Below is the code:
public partial class LabeledField : UserControl {
public LabeledField() {
InitializeComponent();
}
public string fieldName {
get { return fieldNameLabel.Content.ToString(); }
set { fieldNameLabel.Content = value; }
}
public string fieldValue {
get { return (string)GetValue(fieldValueProperty); }
set { SetValue(fieldValueProperty, value); }
}
public static readonly DependencyProperty fieldValueProperty =
DependencyProperty.Register(
"fieldValue",
typeof(string),
typeof(LabeledField),
new FrameworkPropertyMetadata(
"No Data"
)
)
;
}
Here is the XAML:
<UserControl x:Class="DAS1.LabeledField" Name="LF"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Orientation="Horizontal">
<Label Width="100" Height="30" Background="Gray" Name="fieldNameLabel" />
<Label Width="100" Height="30" Background="Silver" Name="fieldValueLabel" Content="{Binding fieldValue}" />
</StackPanel>
And here is the XAML for the Window which references the UserControl. First the header:
<Window x:Class="DAS1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:me="clr-namespace:DAS1"
Title="Window1" Height="580" Width="780">
Then the UserControl itself:
<me:LabeledField fieldName="Test" Width="200" Height="30" fieldValue="{Binding businessObjectField}"/>
If I knew of a more specific question to ask, I would--but can anyone tell me why this doesn't work?
Turns out that in the XAML for the user control, the binding was incorrectly specified.
Originally it was:
<Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding fieldValue}" />
But I had not specified the element to which fieldValue belongs. It should be (assuming my user control is named "LF":
<Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding ElementName=LF, Path=fieldValue}" />
If you want to bind to properties of the control, you should specify so in the binding. Bindings are evaluated relative to DataContext if their source isn't explicitly specified, so your binding doesn't bind to your control, but to the inherited context (which is likely missing the property you're binding to). What you need is:
<Label Width="100" Height="30" Name="fieldValueLabel"
Content="{Binding Path=fieldValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DAS1.LabeledField}}}" />
You really don't need a dependency property on your user control, in fact you should strive to keep user controls without anything special in the code-behind, custom Controls should be used for that.
You should define your UserControl like this (without any code behind):
<UserControl x:Class="DAS1.LabeledField"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Orientation="Horizontal">
<Label Width="100" Height="30" Name="fieldNameLabel" Content="{Binding fieldName}" />
<Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding field}" />
</StackPanel>
Then, make sure your business object implements INotifyPropertyChanged, because you cannot update from your business object efficiently without modifying it at least this much. The fieldName is just an example how you could bind the display name on the label automatically to a property on your business object.
Then, simply make sure the DataContext of your UserControl is your business object.
How will this work? The Label.Content property is a DependencyProperty and will support binding itself. Your business object implements INotifyPropertyChanged and thus supports updates to binding - without it, the binding system does not get notified when your field's value changes, regardless if you bound it to a DependencyProperty on one end.
And if you want to reuse this user control elsewhere, simply place a desired instance of your business object to the DataContext of the desired LabeledField control. The binding will hook up itself from the DataContext.

Selecting DataTemplate based on sub-object type

I want to databind an ItemsCollection, but instead of rendering the collection items, I want to render sub-objects reached via a property on the collection item.
To be more specific: this will be a 2D map viewer for a game (though in its current state it isn't 2D yet). I databind an ItemsControl to an ObservableCollection<Square>, where Square has a property called Terrain (of type Terrain). Terrain is a base class and has various descendants.
What I want is for the ItemsControl to render the Terrain property from each collection element, not the collection element itself.
I can already make this work, but with some unnecessary overhead. I want to know if there's a good way to remove the unnecessary overhead.
What I currently have are the following classes (simplified):
public class Terrain {}
public class Dirt : Terrain {}
public class SteelPlate : Terrain {}
public class Square
{
public Square(Terrain terrain)
{
Terrain = terrain;
}
public Terrain Terrain { get; private set; }
// additional properties not relevant here
}
And a UserControl called MapView, containing the following:
<UserControl.Resources>
<DataTemplate DataType="{x:Type TerrainDataModels:Square}">
<ContentControl Content="{Binding Path=Terrain}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type TerrainDataModels:Dirt}">
<Canvas Width="40" Height="40" Background="Tan"/>
</DataTemplate>
<DataTemplate DataType="{x:Type TerrainDataModels:SteelPlate}">
<Canvas Width="40" Height="40" Background="Silver"/>
</DataTemplate>
</UserControl.Resources>
<ItemsControl ItemsSource="{Binding}"/>
Given this code, if I do:
mapView.DataContext = new ObservableCollection<Square> {
new Square(new Dirt()),
new Square(new SteelPlate())
};
I get something that looks exactly like what I expect: a StackPanel containing a tan box (for the Dirt) and a silver box (for the SteelPlate). But I get it with unnecessary overhead.
My specific concern is with my DataTemplate for Square:
<DataTemplate DataType="{x:Type TerrainDataModels:Square}">
<ContentControl Content="{Binding Path=Terrain}"/>
</DataTemplate>
What I really want to say is "no, don't bother rendering the Square itself, render its Terrain property instead". This gets close to that, but this adds an extra two controls to the visual tree for every Square: a ContentControl, as coded explicitly in the above XAML, and its ContentPresenter. I don't particularly want a ContentControl here; I really want to short-circuit and insert the Terrain property's DataTemplate directly into the control tree.
But how do I tell the ItemsControl to render collectionitem.Terrain (thus looking up one of the above DataTemplates for the Terrain object) rather than rendering collectionitem (and looking for a DataTemplate for the Square object)?
I want to use DataTemplates for the terrains, but not at all necessarily for the Square -- that was just the first approach I found that worked adequately. In fact, what I really want to do is something completely different -- I really want to set the ItemsControl's DisplayMemberPath to "Terrain". That renders the right object (the Dirt or SteelPlate object) directly, without adding an extra ContentControl or ContentPresenter. Unfortunately, DisplayMemberPath always renders a string, ignoring the DataTemplates for the terrains. So it's got the right idea, but it's useless to me.
This whole thing may be premature optimization, and if there's no easy way to get what I want, I'll live with what I've got. But if there's a "WPF way" I don't yet know about to bind to a property instead of the whole collection item, it'll add to my understanding of WPF, which is really what I'm after.
I'm not exactly sure what your model looks like, but you can always use a . to bind to an objects property. For example:
<DataTemplate DataType="TerrainModels:Square">
<StackPanel>
<TextBlock Content="{Binding Path=Feature.Name}"/>
<TextBlock Content="{Binding Path=Feature.Type}"/>
</StackPanel>
</DataTemplate>
Update
Although, if you are looking for a way to bind two different objects in a collection you might want to take a look at the ItemTemplateSelector property.
In your scenario it would be something like this (not tested):
public class TerrainSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var square = item as Square;
if (square == null)
return null;
if (square.Terrain is Dirt)
{
return Application.Resources["DirtTemplate"] as DataTemplate;
}
if (square.Terrain is Steel)
{
return Application.Resources["SteelTemplate"] as DataTemplate;
}
return null;
}
}
Then to use it you would have:
App.xaml
<Application ..>
<Application.Resources>
<DataTemplate x:Key="DirtTemplate">
<!-- template here -->
</DataTemplate>
<DataTemplate x:Key="SteelTemplate">
<!-- template here -->
</DataTemplate>
</Application.Resources>
</Application>
Window.xaml
<Window ..>
<Window.Resources>
<local:TerrainSelector x:Key="templateSelector" />
</Window.Resources>
<ItemsControl ItemSource="{Binding Path=Terrain}" ItemTemplateSelector="{StaticResource templateSelector}" />
</Window>
I'm adding another answer, because this is kind of a different take on the problem then my other answer.
If you are trying to change the background of the Canvas, then you can use a DataTrigger like this:
<DataTemplate DataType="{x:Type WpfApplication1:Square}">
<DataTemplate.Resources>
<WpfApplication1:TypeOfConverter x:Key="typeOfConverter" />
</DataTemplate.Resources>
<Canvas Name="background" Fill="Green" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path="Terrain" Converter={StaticResource typeOfConverter}}" Value="{x:Type WpfApplication1:Dirt}">
<Setter TargetName="background"Property="Fill" Value="Tan" />
</DataTrigger>
<DataTrigger Binding="{Binding Path="Terrain" Converter={StaticResource typeOfConverter}}" Value="{x:Type WpfApplication1:SteelPlate}">
<Setter TargetName="background" Property="Fill" Value="Silver" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
You'd also need to use this Converter:
public class TypeOfConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.GetType();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
I believe the best you can do to eliminate visual tree overhead (and redundancy) is this:
<ItemsControl ItemsSource="{Binding Squares}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Terrain}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I could have sworn you could take this a step further by directly assigning to the Content property of the ContentPresenter generated for each item in the ItemsControl:
<ItemsControl ItemsSource="{Binding Squares}">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="ContentPresenter.Content" Content="{Binding Terrain}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
However, the ContentPresenter appears to have the parent DataContext as its DataContext rather than the Square. This makes no sense to me. It works fine with a ListBox or any other ItemsControl subclass. Perhaps this is a WPF bug - not sure. I will have to look into it further.

Resources