Reputation: 3
Can someone help me with such task. I have resource template and trying to decrease amount of duplicate code in it
<ControlTemplate x:Key="PlanAssetValue" TargetType="ContentControl">
<ContentControl Template="{StaticResource Period}">
<StackPanel Height="Auto" Width="Auto" x:Name="MainPanel">
<DockPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Height="Auto"
Margin="10">
<TextBlock Text="{Binding Path=Paramprompt[IsMarket]}" DockPanel.Dock="Left" Width="160" Margin="0,2,0,0"/>
<ComboBox DockPanel.Dock="Left" Margin="5,0,0,0" Width="Auto"
ItemsSource="{Binding Path=ParamDetails[IsMarket]}"
DisplayMemberPath="Name"
VerticalAlignment="Top"
StaysOpenOnEdit="True"
SelectedValue="{Binding Path=ParamValues[IsMarket]}" SelectedValuePath="Code">
</ComboBox>
</DockPanel>
<DockPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Height="Auto"
Margin="10">
<TextBlock Text="{Binding Path=Paramprompt[Currency]}" DockPanel.Dock="Left" Width="160" Margin="0,2,0,0"/>
<ComboBox DockPanel.Dock="Left" Margin="5,0,0,0" Width="Auto"
ItemsSource="{Binding Path=ParamDetails[Currency]}"
DisplayMemberPath="Name"
VerticalAlignment="Top"
StaysOpenOnEdit="True"
SelectedValue="{Binding Path=ParamValues[Currency]}" SelectedValuePath="Code">
</ComboBox>
</DockPanel>
</StackPanel>
</ContentControl>
</ControlTemplate>
I want to declare some text as template with parameter to set instead of field IsMarket
<ControlTemplate x:Key="ParamCombobox" TargetType="ContentControl">
<DockPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Height="Auto"
Margin="10">
<TextBlock Text="{Binding Path=Paramprompt[IsMarket]}" DockPanel.Dock="Left" Width="160" Margin="0,2,0,0"/>
<ComboBox DockPanel.Dock="Left" Margin="5,0,0,0" Width="Auto"
ItemsSource="{Binding Path=ParamDetails[IsMarket]}"
DisplayMemberPath="Name"
VerticalAlignment="Top"
StaysOpenOnEdit="True"
SelectedValue="{Binding Path=ParamValues[IsMarket]}" SelectedValuePath="Code">
</ComboBox>
</DockPanel>
</ControlTemplate>
Upvotes: 1
Views: 2631
Reputation: 6491
ControleTemplate its presentation of a logic control. the ContentControl logic its present one content. It has a property named Content and you can use this "Parameter" in the template via TemplateBinding: {TemplateBinding Content}.
You want a control that represents more than single information. So create it!
Example:
class MyUiControl : Control
{
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(MyUiControl), new PropertyMetadata(null));
public IEnumerable ItemsCombo
{
get { return (IEnumerable)GetValue(ItemsComboProperty); }
set { SetValue(ItemsComboProperty, value); }
}
public static readonly DependencyProperty ItemsComboProperty =
DependencyProperty.Register("ItemsCombo", typeof(IEnumerable), typeof(MyUiControl), new PropertyMetadata(null));
public object Value
{
get { return (IEnumerable)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(MyUiControl), new PropertyMetadata(null));
}
and now the template:
<ControlTemplate x:Key="ParamCombobox" TargetType="local:MyUiControl">
<DockPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Height="Auto"
Margin="10">
<TextBlock Text="{TemplateBinding Header}" DockPanel.Dock="Left" Width="160" Margin="0,2,0,0"/>
<ComboBox DockPanel.Dock="Left" Margin="5,0,0,0" Width="Auto"
ItemsSource="{TemplateBinding ItemsCombo}"
DisplayMemberPath="Name"
VerticalAlignment="Top"
StaysOpenOnEdit="True"
SelectedValue="{TemplateBinding Value}" SelectedValuePath="Code">
</ComboBox>
</DockPanel>
</ControlTemplate>
and the control:
<local:MyUiControl Header="{Binding paramA}"
ItemsCombo="{Binding paramB}"
Value="{Binding paramC}" />
BUT, you don't really need special logic. your business it's simply a set of a label with a control. for this, i think you can use a simple HeaderedContentControl with your Template:
<Style TargetType="HeaderedContentControl">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="HeaderedContentControl">
<DockPanel>
<TextBlock Text="{TemplateBinding Header}" DockPanel.Dock="Left" Width="160" Margin="0,2,0,0"/>
<ContentPresenter DockPanel.Dock="Left" Margin="5,0,0,0" Width="Auto" VerticalAlignment="Top" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
the control:
<HeaderedContentControl Header="{Binding paramA}">
<ComboBox ItemsSource="{Binding paramB}"
DisplayMemberPath="Name"
StaysOpenOnEdit="True"
SelectedValue="{Binding paramC}" SelectedValuePath="Code" />
</HeaderedContentControl>
Upvotes: 2
Reputation: 13898
Wrap those 3 related objects in a class e.g.
N.B. I have omitted INotifyPropertyChanged
implementations for brevity
public class ParamViewModel : INotifyPropertyChanged
{
public string Prompt { get; set; }
public ObservableCollection<string> Details { get; set;}
public string SelectedValue { get; set; }
}
Then have your control template DataContext bind to the correct object in your parent VM:
<ContentControl Template="{StaticResource Period}">
<StackPanel Height="Auto" Width="Auto" x:Name="MainPanel">
<ContentControl DataContext="{Binding Params[IsMarket]}"
Template="{StaticResource ParamTemplate}" />
<ContentControl DataContext="{Binding Params[Currency]}"
Template="{StaticResource ParamTemplate}" />
</StackPanel>
</ContentControl>
And your parent VM could be something like:
public class ParentViewModel : INotifyPropertyChanged
{
public Dictionary<string, Param> Params { get; set;}
}
<ControlTemplate x:Key="ParamTemplate" TargetType="ContentControl">
<DockPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Height="Auto"
Margin="10">
<TextBlock Text="{Binding Path=Prompt}" DockPanel.Dock="Left" Width="160" Margin="0,2,0,0"/>
<ComboBox DockPanel.Dock="Left" Margin="5,0,0,0" Width="Auto"
ItemsSource="{Binding Path=Details}"
DisplayMemberPath="Name"
VerticalAlignment="Top"
StaysOpenOnEdit="True"
SelectedValue="{Binding SelectedValue}" SelectedValuePath="Code">
</ComboBox>
</DockPanel>
</ControlTemplate>
Upvotes: 2