WPF将参数传递给ControlTemplate

时间:2017-11-07 15:14:16

标签: c# wpf xaml

有人可以帮我完成这样的任务。我有资源模板并试图减少其中重复代码的数量

<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>

我想将一些文本声明为带有参数的模板,而不是字段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>

2 个答案:

答案 0 :(得分:2)

ControleTemplate其逻辑控件的表示。 ContentControl逻辑其当前的一个内容。它有一个名为Content的属性,你可以通过TemplateBinding在模板中使用这个“参数”:{TemplateBinding Content}。

您想要一个代表单个信息的控件。所以创造它!

示例:

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));
}

现在是模板:

<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>

和控件:

<local:MyUiControl Header="{Binding paramA}"
                   ItemsCombo="{Binding paramB}"
                   Value="{Binding paramC}" />

但是,你真的不需要特殊的逻辑。您的业​​务只是一组带控件的标签。为此,我认为您可以在模板中使用简单的HeaderedContentControl:

<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>

控件:

<HeaderedContentControl Header="{Binding paramA}">
    <ComboBox ItemsSource="{Binding paramB}"
                DisplayMemberPath="Name" 
                StaysOpenOnEdit="True" 
                SelectedValue="{Binding paramC}" SelectedValuePath="Code" />
</HeaderedContentControl>

答案 1 :(得分:1)

将这3个相关对象包裹在一个类中,例如

N.B。为简洁起见,我省略了INotifyPropertyChanged个实现

public class ParamViewModel : INotifyPropertyChanged
{
    public string Prompt { get; set; }
    public ObservableCollection<string> Details { get; set;}
    public string SelectedValue { get; set; }
}

然后让您的控件模板DataContext绑定到父虚拟机中的正确对象:

<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>

您的父虚拟机可能类似于:

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>