I try to make custom control based on DataGridTemplateColumn for using it in simple datagrid.
My XAML code looks:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dgNuCol="clr-namespace:Columns.DataGridNumberColumn"
xmlns:nb="clr-namespace:NumberBox" >
<Style TargetType="{x:Type dgNuCol:DataGridNumberColumn}">
<Setter Property="CellEditingTemplate">
<Setter.Value>
<ControlTemplate TargetType="{x:Type dgNuCol:DataGridNumberColumn}">
<nb:NumberBox Text="123"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="CellTemplate">
<Setter.Value>
<ControlTemplate TargetType="{x:Type dgNuCol:DataGridNumberColumn}">
<StackPanel>
<TextBlock Text="123" HorizontalAlignment="Center" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And my cs code:
namespace Columns.DataGridNumberColumn
{
public partial class DataGridNumberColumn : DataGridTemplateColumn
{
}
}
And I try to use it in my datagrid:
<dgNuCol:DataGridNumberColumn Header="Values" CanUserReorder="False"/>
Nothing happens. There are no any changes in my datagrid, just empty cell. What I am doing wrong?
UPDATE:
I try to make it programmatically:
public partial class DataGridNumberColumn : DataGridTemplateColumn
{
public DataGridNumberColumn()
{
FrameworkElementFactory textFactory = new FrameworkElementFactory(typeof(TextBox));
textFactory.SetValue(TextBox.TextProperty, "123");
DataTemplate textTemplate = new DataTemplate();
textTemplate.VisualTree = textFactory;
this.CellTemplate = textTemplate;
}
}
But, again, no any changes in datagrid.
UPDATE2:
<DataGrid>
<DataGrid.Columns>
<dgNuCol:DataGridNumberColumn Header="Values" CanUserReorder="False"/>
</DataGrid.Columns>
</DataGrid>
Related
I'm using reflection and expression trees in C# to build a fairly adaptable search tool for our database. Because of this, I have a need for a custom ContentControl - termed 'MultiStyleInputBox' - which uses data triggers to adjust its ContentTemplate to the Type of input expected. The problem is, while the code builds just fine and I have confirmed that both the public and static constructors are being hit when the code executes, the ContentControl's content doesn't show up at all in my UI.
Now, I'm relatively new to writing custom XAML/C# UI control classes, but I have been able to cobble together the following:
<ContentControl x:Class="MyApp.MultiStyleInputBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Name="multiStyleInputBox">
<ContentControl.Resources>
<Style TargetType="ContentControl" BasedOn="{StaticResource {x:Type ContentControl}}">
<Style.Triggers>
<DataTrigger Binding="{Binding InputType, ElementName=multiStyleInputBox}" Value="{x:Type sys:DateTime}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<DatePicker SelectedDate="{Binding Value, ElementName=multiStyleInputBox}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<!--I have several of these triggers for different data types-->
</Style.Triggers>
<Style.Setters>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Text="{Binding Value, ElementName=multiStyleInputBox}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</ContentControl.Resources>
</ContentControl>
And the code behind:
public sealed partial class MultiStyleInputBox : ContentControl
{
//Dependency properties
public Type InputType
{
get { return (Type)GetValue(InputTypeProperty); }
set { SetValue(InputTypeProperty, value); }
}
public static readonly DependencyProperty InputTypeProperty =
DependencyProperty.Register("InputType", typeof(Type), typeof(MultiStyleInputBox));
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(MultiStyleInputBox));
//Constructors
public MultiStyleInputBox() : base()
{
}
static MultiStyleInputBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiStyleInputBox),
new FrameworkPropertyMetadata(typeof(MultiStyleInputBox)));
}
}
I thought at one point that I might not have set the content of the ContentControl, and so I added a <ContentPresenter/>, but I received an error saying that the content is set more than once, so I believe that my <Style.Setters></Style.Setters> section is taking care of that. Otherwise, even running around using PresentationTraceSources.TraceLevel="High" on my bindings, I haven't so far been able to run into any useful errors.
Is there some sort of glaring issue in my code that I can immediately address (hopefully)? Do I need to reevaluate my approach to the problem?
Update
After suggested corrections in the answers below, here is the latest version of the code:
<ContentControl x:Class="MyApp.MultiStyleInputBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Name="multiStyleInputBox">
<ContentControl.Style>
<Style TargetType="ContentControl" BasedOn="{StaticResource {x:Type ContentControl}}">
<Style.Triggers>
<DataTrigger Binding="{Binding InputType, ElementName=multiStyleInputBox, Value="{x:Type sys:DateTime}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<DatePicker SelectedDate="{Binding Value, ElementName=multiStyleInputBox}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<!--I have several of these triggers for different data types-->
</Style.Triggers>
<Style.Setters>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Text="{Binding Value, ElementName=multiStyleInputBox}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</ContentControl.Style>
</ContentControl>
And the code-behind:
public partial class MultiStyleInputBox : ContentControl
{
//Dependency properties
public Type InputType
{
get { return (Type)GetValue(InputTypeProperty); }
set { SetValue(InputTypeProperty, value); }
}
public static readonly DependencyProperty InputTypeProperty =
DependencyProperty.Register("InputType", typeof(Type), typeof(MultiStyleInputBox));
public object Value
{
get { return GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(MultiStyleInputBox),
new FrameworkPropertyMetadata(DateTime.Now,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
//Constructors
public MultiStyleInputBox() : base()
{
}
static MultiStyleInputBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiStyleInputBox),
new FrameworkPropertyMetadata(typeof(MultiStyleInputBox)));
}
}
Here is a test instantiation of the MultiStyleInputBox (I'm using Mahapps.Metro):
<Controls:MetroWindow
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
x:Class="MyApp.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyApp"
Title="Test Window" Height="450" Width="800"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<StackPanel>
<local:MultiStyleInputBox x:Name="TestMultiBox" Value="1" InputType="{x:Type sys:Int32}"/>
</StackPanel>
</Controls:MetroWindow>
When I try to instantiate this class, I'm still not getting anything showing up in my UI, and the ContentControl isn't taking up any space. Even if I include Width="50" Height="24", I still get nothing. I've tested setting both Value and InputType in code-behind and using a breakpoint to inspect the object, and I'm finding that, while both values get set, the Content of the ContentControl remains null.
The immediate problem is that your style isn't applied to the ContentControl you want to apply it to. You're defining an implicit ContentControl style which will be applied to any ContentControls you create in the content of this control -- but you aren't creating any, and that's not what you want anyhow.
For a quick fix, just change ContentControl.Resources to ContentControl.Style.
<ContentControl x:Class="MyApp.MultiStyleInputBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Name="multiStyleInputBox">
<ContentControl.Style>
<Style TargetType="ContentControl" BasedOn="{StaticResource {x:Type ContentControl}}">
<Style.Triggers>
<DataTrigger Binding="{Binding InputType, ElementName=multiStyleInputBox}" Value="{x:Type sys:DateTime}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<DatePicker SelectedDate="{Binding Value, ElementName=multiStyleInputBox}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<!--I have several of these triggers for different data types-->
</Style.Triggers>
<Style.Setters>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Text="{Binding Value, ElementName=multiStyleInputBox}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</ContentControl.Style>
</ContentControl>
Your next problem will be that selecting a new DateTime in the DatePicker won't update a property bound to the Value property of your viewmodel. Here's the fix for that:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(MultiStyleInputBox),
new FrameworkPropertyMetadata(DateTime.Now,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
And the last problem (or the first, perhaps) was that you weren't calling InitializeComponent() in the constructor, which is always required in any WPF codebehind class:
public MultiStyleInputBox()
{
InitializeComponent();
}
I am trying to bind some values to ToolTipService.ShowDuration and some other ToolTip's properties in a CellStyle of DataGridTextColumn.
Normaly, I am doing something like this:
<UserControl
...namespace declarations...>
<UserControl.Resources>
<mycontrols:BindingProxy x:Key="proxy" Data="{Binding MySettings}"/>
</UserControl.Resources>
<DataGrid>
<DataGridTextColumn
Binding="{Binding SomeBinding}">
<DataGridTextColumn.CellStyle>
<Style
TargetType="DataGridCell"
BasedOn="{StaticResource ResourceKey={x:Type DataGridCell}}">
<Setter
Property="ToolTipService.ShowDuration"
Value="{Binding Data.ToolTipDuration, Source={StaticResource proxy}}"/>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock
Text="{Binding SomeBinding}"
MaxWidth="{Binding Data.ToolTipMaxWidth, Source={StaticResource proxy}}"
TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid>
</UserControl>
Since ToolTip has it's own visual tree, I am using binding proxy like this:
public class BindingProxy : Freezable
{
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
Up to this point, all works as expected. But I wanted to re-use this DataGridTextColumn, so I created new file like this:
<DataGridTextColumn
x:Class="Test.MyControls.DataGridLargeTextColumn"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test.MyControls">
<DataGridTextColumn.CellStyle>
<Style
TargetType="DataGridCell"
BasedOn="{StaticResource ResourceKey={x:Type DataGridCell}}">
<Setter
Property="ToolTipService.ShowDuration"
Value="{Binding ToolTipDuration}"/>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock
Text="{Binding SomeBinding}"
MaxWidth="{Binding ToolTipWidth}"
TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
With code behinde:
public partial class DataGridLargeTextColumn : DataGridTextColumn
{
public int ToolTipDuration
{
get { return (int)GetValue(ToolTipDurationProperty); }
set { SetValue(ToolTipDurationProperty, value); }
}
public static readonly DependencyProperty ToolTipDurationProperty =
DependencyProperty.Register("ToolTipDuration", typeof(int), typeof(DataGridLargeTextColumn), new UIPropertyMetadata(default(int)));
public string SomeBinding
{
get { return (string)GetValue(SomeBindingProperty); }
set { SetValue(SomeBindingProperty, value); }
}
public static readonly DependencyProperty SomeBindingProperty =
DependencyProperty.Register("SomeBinding", typeof(string), typeof(DataGridLargeTextColumn), new UIPropertyMetadata(default(string)));
public int ToolTipWidth
{
get { return (int)GetValue(ToolTipWidthProperty); }
set { SetValue(ToolTipWidthProperty, value); }
}
public static readonly DependencyProperty ToolTipWidthProperty =
DependencyProperty.Register("ToolTipWidth", typeof(int), typeof(DataGridLargeTextColumn), new UIPropertyMetadata(default(int)));
public DataGridLargeTextColumn()
{
InitializeComponent();
}
}
This does't work because ToolTip has it's own visual tree, but since I have nowhere to put proxy, I don't know how to make it work or if it is even possible. I found this answer, and it seems to be on the right track, however, I tried to implement it like this with no luck:
<Setter
Property="ToolTipService.ShowDuration"
Value="{Binding Path=PlacementTarget.(local:DataGridLargeTextColumn.ToolTipDuration), RelativeSource={RelativeSource Self}}"/>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock
Text="{Binding Path=PlacementTarget.(local:DataGridLargeTextColumn.SomeBinding), RelativeSource={RelativeSource Self}}"
MaxWidth="{Binding Path=PlacementTarget.(local:DataGridLargeTextColumn.ToolTipWidth), RelativeSource={RelativeSource Self}}"
TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/>
</Setter.Value>
</Setter>
Am I using PlacementTarget wrong? If not, why is it not working, and is there another solution?
UPDATE:
As per Mark's answer, I've modified the DataGridLargeTextColumn's Style:
<Style
TargetType="DataGridCell"
BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter
Property="ToolTipService.ShowDuration" Value="{Binding Path=PlacementTarget.ToolTipShowDuration, RelativeSource={x:Static RelativeSource.Self}}"/>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding Path=PlacementTarget, RelativeSource={x:Static RelativeSource.Self}}">
<TextBlock
Text="{Binding DataContext.SomeBinding}"
MaxWidth="{Binding Column.ToolTipWidth}"
TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
And I'm using that control like this:
<UserControl
...namespace declarations...>
<UserControl.Resources>
<mycontrols:BindingProxy x:Key="proxy" Data="{Binding MySettings}"/>
</UserControl.Resources>
<DataGrid>
<DataGrid.Columns>
<mycontrols:DataGridLargeTextColumn
Binding="{Binding SomeBinding}"
ToolTipShowDuration="{Binding Data.ToolTipDuration, Source={StaticResource proxy}}"
ToolTipWidth="{Binding Data.ToolTipMaxWidth, Source={StaticResource proxy}}"/>
</DataGrid.Columns>
</DataGrid>
</UserControl>
Width binding now works like a charm, but there are two problems I still cannot solve:
I cannot get tool tip's duration to bind, I have tried few different approches, but since it's abstract, it cannot be declared explicitly
ToolTip's Text property is set to SomeBinding, which is OK in this particular case, but I want to be able to set it to whatever, so I tried to declare it using DependencProperty from above like this:
Text="{Binding Column.ToolTipText}"
This works OK if i use it with string literal:
<myControls:DataGridLargeTextColumn
Binding="{Binding SomeBinding}"
ToolTipText="12345"
ToolTipShowDuration="{Binding Data.ToolTipDuration, Source={StaticResource proxy}}"
ToolTipWidth="{Binding Data.ToolTipMaxWidth, Source={StaticResource proxy}}"/>
But it doesn't work when I try to bind it, which is what I am trying to achieve:
<myControls:DataGridLargeTextColumn
Binding="{Binding SomeBinding}"
ToolTipText="{Binding SomeOtherPropertyBinding}"
ToolTipShowDuration="{Binding Data.ToolTipDuration, Source={StaticResource proxy}}"
ToolTipWidth="{Binding Data.ToolTipMaxWidth, Source={StaticResource proxy}}"/>
By default your ToolTip's DataContext gets set to the DataContext of the cell. You, however, are trying to bind to dependency properties in the cell's column instead, so you're going to have to change the DataContext to point to the cell itself and then reference DataContext explicitly when you want to access the data and Column when you want to access the DPs in your DataGridLargeTextColumn.
In other words, declare the ToolTip explicitly in addition to its content and set its DataContext, like this:
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding Path=PlacementTarget, RelativeSource={x:Static RelativeSource.Self}}">
<TextBlock
Text="{Binding DataContext.SomeBinding}"
Width="{Binding Column.ToolTipWidth}" />
</ToolTip>
</Setter.Value>
</Setter>
...where Text in this case is binding to the data and Width is binding to the custom column DP.
Alternatively you could also just leave the DataContext as is and instead use the ToolTip's Tag property as a binding proxy to the DataGridLargeTextColumn:
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Tag="{Binding Path=PlacementTarget.Column, RelativeSource={x:Static RelativeSource.Self}}">
<TextBlock
Text="{Binding SomeBinding}"
Width="{Binding Tag.ToolTipWidth, RelativeSource={RelativeSource AncestorType=ToolTip}}" />
</ToolTip>
</Setter.Value>
</Setter>
I have a custom control based on a button, and I put an image inside. I can set the source of the image in the xaml, but if I try and bind it, it doesn't work.
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControl">
<Style TargetType="{x:Type local:MyCustomControl}" BasedOn = "{StaticResource {x:Type Button}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyCustomControl}">
<Grid x:Name="InnerGrid">
<Image Source="pathname"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
This works just fine, however if I replace the <Image Source="pathname"/> with <Image Source={Binding MyImage, RelativeSource={RelativeSource Self}}"/>, and reference a Delegate Property in the class, it breaks.
MyCustomControl.cs
public class MyCustomControl : Button
{
static DependencyProperty m_myimage = null;
private DependencyProperty MyImageProperty
{
get
{
return m_myimage;
}
}
public BitmapImage MyImage
{
get
{
return (BitmapImage)GetValue(MyImageProperty);
}
set
{
SetValue(MyImageProperty, value);
}
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
MyImage = new BitmapImage(new Uri(pathname));
}
private static void RegisterDependencyProperties()
{
if (m_myimage == null)
{
m_myimage = DependencyProperty.Register("MyImage",
typeof(BitmapImage), typeof(MyCustomControl), null);
}
}
static MyCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl),
new FrameworkPropertyMetadata(typeof(MyCustomControl)));
RegisterDependencyProperties();
}
}
How can I get it to work?
Figured it out myself after about 2 hours. The xaml binding should look like,
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyCustomControl}">
<Grid x:Name="InnerGrid">
<Image Source="{Binding MyImage, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
Note that the binding relative resource went from RelativeSource={RelativeSource Self} to RelativeSource={RelativeSource TemplatedParent}
How do I switch UserControls based on a property setting in my ViewModel?
If Vm.View = "A"
<Window>
<local:UserControlA/>
</Window>
If Vm.View = "B"
<Window>
<local:UserControlB/>
</Window>
Vm.View is an enum that someday may allow for C, D, and so on. Both UserControls are bound to the same Vm, but they present the data radically different based on the user's input. So a DataTemplate based on type doesn't really work here.
Thoughts?
Add ContentControl inside Window and based on View value you can set it's ContentTemplate using DataTriggers.
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<local:UserControlA/>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding View}" Value="B">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<local:UserControlB/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
You might leverage DataTemplate's DataType property and let the binding engine take care of the rest...
XAML
<Window.Resources>
<DataTemplate DataType="localEnums:ProduceType.Apples">
<local:ApplesView />
</DataTemplate>
<DataTemplate DataType="localEnums:ProduceType.Oranges">
<local:OrangesView />
</DataTemplate>
</Window.Resources>
<StackPanel>
<ContentPresenter Content="{Binding ProduceType}" />
<Button Content="Change Produce" Click="Button_Click"/>
</StackPanel>
View Model
public class ProduceViewModel : ViewModel
{
public ProduceViewModel()
{
this.ProduceType = ProduceType.Apples;
}
private ProduceType _produceType;
public ProduceType ProduceType
{
get
{
return _produceType;
}
set
{
if (_produceType != value)
{
_produceType = value;
RaisePropertyChanged();
}
}
}
}
Button Click Handler (Violates pure MVVM but just to demonstrate the DataTemplate switching)
private void Button_Click(object sender, RoutedEventArgs e)
{
(this.DataContext as ProduceViewModel).ProduceType = ProduceType.Oranges;
}
I've got nested custom ContentControls, and I'm having difficulty getting the inner control to render inside of the outer control. Here's an example of how the two controls are composed:
<Window ...>
<StackPanel>
<local:Outer> <!-- Nothing in here gets displayed -->
<local:Inner>
<TextBlock>Fahrvergnügen</TextBlock>
</local:Inner>
</local:Outer>
<local:Inner> <!-- This is displayed just fine -->
<TextBlock>some text</TextBlock>
</local:Inner>
</StackPanel>
</Window>
Inner and Outer's styles are defined as follows:
<ResourceDictionary ...>
<Style TargetType="{x:Type local:Outer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Outer}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:Inner}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Inner}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
An added wrinkle is that Outer is using a ContentPropertyAttribute that points to a List:
[ContentPropertyAttribute("InnerItems")]
public class Outer : ContentControl
{
private List<Inner> innerItems = new List<Inner>();
static Outer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Outer), new FrameworkPropertyMetadata(typeof(Outer)));
}
public List<Inner> InnerItems { get { return this.innerItems; } }
}
For completeness, here's Inner's definition, which is trivial:
public class Inner : ContentControl
{
static Inner()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Inner), new FrameworkPropertyMetadata(typeof(Inner)));
}
}
I'm guessing the problem is that Outer's content cannot be displayed with a simple <ContentPresenter /> but I'm not sure what to replace it with. Suggestions?