简体   繁体   English

如何使ControlTemplate不覆盖DataTemplate?

[英]How to get ControlTemplate not to override DataTemplate?

Similar to gmail's Select button, I wanted to create a ComboBox for the ListView which allows the user to quickly select entries of their choosing (ex. All, None, Read, Unread). 与gmail的“选择”按钮类似,我想为ListView创建一个ComboBox ,它允许用户快速选择其选择的条目(例如,全部,无,已读,未读)。 However, the selected value would display a tri-state CheckBox equivalent to All, Some, or None of the entries being selected. 但是,选定的值将显示一个三态CheckBox相当于所有选定条目的全部,部分或无。 I succeeded in doing so. 我成功地做到了。 Below is the xaml for an example Window utilizing this feature ( * ) : 以下是使用此功能 * 的示例窗口的xaml:

<Window x:Class="WPFTest.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfTest="clr-namespace:WPFTest.ViewModels"
        xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Mvvm;assembly=Microsoft.Practices.Prism.Mvvm.Desktop"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:WPFTest.Models"
        mc:Ignorable="d" Title="WPF Test" Height="221.256" Width="605"
        d:DataContext="{d:DesignInstance wpfTest:MainWindowViewModel, IsDesignTimeCreatable=True}"
        prism:ViewModelLocator.AutoWireViewModel="True" WindowStartupLocation="CenterScreen">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary
                    Source="/WPFTest;Component/Resources/Resources.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <ListView 
            ItemsSource="{Binding Entries}"
            SelectedValue="{Binding SelectedEntry}"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            ScrollViewer.CanContentScroll="True"
            SelectionMode="Single"
            Margin="10">

            <ListView.View>
                <GridView>
                    <GridViewColumn Width="Auto">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox 
                                    IsChecked="{Binding Selected}" 
                                    Command="{Binding DataContext.RowSelectedCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
                                    HorizontalAlignment="Center"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                        <GridViewColumnHeader>
                            <ComboBox 
                                ItemsSource="{Binding Options.Items}"
                                SelectedValue="{Binding Options.SelectedItem}"
                                ItemTemplateSelector="{DynamicResource itemTemplateSelector}"
                                HorizontalAlignment="Stretch"
                                Margin="0,0,0,0"
                                VerticalAlignment="Stretch"
                                Width="44" 
                                Height="34"
                                FontSize="20"
                                VerticalContentAlignment="Top"
                                HorizontalContentAlignment="Left">
                                <ComboBox.Resources>
                                    <DataTemplate x:Key="selectedTemplate">
                                        <TextBlock 
                                            x:Name="displayText"
                                            Text="{Binding DataContext.Options.SelectedDisplay, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
                                            FontSize="20"
                                            Height="22"/>
                                    </DataTemplate>
                                    <DataTemplate x:Key="dropDownTemplate">
                                        <TextBlock Text="{Binding}" FontSize="12"/>
                                    </DataTemplate>
                                    <local:ComboBoxItemTemplateSelector
                                        x:Key="itemTemplateSelector"
                                        SelectedTemplate="{StaticResource selectedTemplate}"
                                        DropDownTemplate="{StaticResource dropDownTemplate}"/>
                                </ComboBox.Resources>
                            </ComboBox>
                        </GridViewColumnHeader>
                    </GridViewColumn>
                    <GridViewColumn
                        Width="Auto"
                        DisplayMemberBinding="{Binding Type, Mode=OneWay}"
                        Header="Type"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

演示组合选择选项

Recently I was asked to make a style for every ComboBox on our screens - changing their backgrounds. 最近,有人要求我为屏幕上的每个ComboBox制作样式-更改其背景。 Because I'm on Windows8, setting the Background alone isn't enough. 因为我在Windows8上,仅设置背景是不够的。 Using this tutorial I was able to create the ControlTemplate to get the correct behavior, with one minor error fix: 使用本教程,我能够创建ControlTemplate以获得正确的行为,但有一个小错误修复:

<MultiTrigger.Conditions>
    <Condition Property="IsGrouping" Value="True"/>
    <!-- Comment out the following, it throws an error. -->
    <!--<Condition>
            <Condition.Value>
                <sys:Boolean>False</sys:Boolean>
            </Condition.Value>
        </Condition>-->
</MultiTrigger.Conditions>

And usage: 和用法:

<Style
    TargetType="{x:Type ComboBox}">
    ...
    <Setter
        Property="Template"
        Value="{StaticResource ComboBoxStyle1}" />
</Style>

This successfully styles the ComboBox Background. 这样可以成功设置ComboBox背景的样式。 However, revisiting the former screen, I noticed that this breaks my gmail-like display. 但是,在重新访问前一个屏幕时,我注意到这会破坏我的gmail类显示。

背景色,但显示错误

How can I get this ControlTemplate and the dynamic DataTemplate to cooperate? 如何获得此ControlTemplate和动态DataTemplate进行协作?

( * ) ViewModels and Models can be provided if necessary for a solution. * 如果需要解决方案,可以提供ViewModels和Models。 Or see full working example . 或查看完整的工作示例

I'm not sure why you doing so complicated ComboBox - you defined ItemTemplateSelector twice... 我不确定为什么您要做如此复杂的ComboBox您两次定义了ItemTemplateSelector ...

Ok - here is my 2 cents: ComboBox is lookless control. 好的-这是我的2美分: ComboBox是无外观控件。 It based on ControlTemplate target type = ComboBox. 它基于ControlTemplate目标类型= ComboBox。 Inside ComboBox ControlTemplate you will find ContentPresenter . ComboBox ControlTemplate内部,您将找到ContentPresenter Whatever coming into Content of ContentPresenter could be styled with DataTemplate . ContentPresenter Content的任何Content都可以使用DataTemplate设置样式。 Generally - when you define DataTemplate it wrap only ContentPresenter or ItemsPresenter for range based controls - not the whole ControlTemplate obviously. 通常-当您定义DataTemplate它仅包装 ContentPresenterItemsPresenter用于基于范围的控件-显然不是整个ControlTemplate

So if you want to change 'Selected' template for ComboBox is ok but all other data should be defined via DataTemplate for this type {x:Type local:SomeType} that will be used by ComboBox . 因此,如果您想更改ComboBox “选定”模板是可以的,但所有其他数据都应通过DataTemplate定义为ComboBox将使用的{x:Type local:SomeType}

Also - consider using @galakt suggestion: use Style with TargetType - it easy to read, refactor, find, understand... 另外-考虑使用@galakt建议:将StyleTargetType一起使用-易于阅读,重构,查找,理解...

Color the Background 为背景上色

As per the OP, following this tutorial , you generate the ControlTemplate . 按照OP,在本教程之后 ,您将生成ControlTemplate

To do this, you can right-click on the ComboBox element in design mode in Visual Studio 2012 or 2013 and select the “Edit template” option and then the “Edit a copy…” option. 为此,您可以在Visual Studio 2012或2013中的设计模式下右键单击ComboBox元素,然后选择“编辑模板”选项,然后选择“编辑副本...”选项。

Again note the bug fix from the OP. 再次注意OP中的错误修复。 Changing the background can then be done by: 然后可以通过以下方式更改背景:

<Border 
    x:Name="templateRoot"
    BorderBrush="#FFACACAC"
    BorderThickness="{TemplateBinding BorderThickness}"
    SnapsToDevicePixels="True"
    Background="{StaticResource MyComboBackgroundBrush}"> <!-- option 1 -->

    <!-- <Border.Background> -->

         <!-- option 2 -->
         <!-- <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                  <GradientStop Color="#FFF0F0F0" Offset="0"/>
                  <GradientStop Color="#FFE5E5E5" Offset="1"/>
              </LinearGradientBrush>-->

         <!-- option 3 -->                     
         <!-- <SolidColorBrush Color="Yellow"/> -->

    <!-- </Border.Background>
         <Border x:Name="splitBorder" BorderBrush="Transparent" BorderThickness="1" HorizontalAlignment="Right" Margin="0" SnapsToDevicePixels="True" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
             <Path x:Name="Arrow" Data="F1M0,0L2.667,2.66665 5.3334,0 5.3334,-1.78168 2.6667,0.88501 0,-1.78168 0,0z" Fill="#FF606060" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center"/>
         </Border> -->
</Border>

Interact with the DataTemplate 与DataTemplate交互

  1. In the resource file, following the above instructions, you declared: 在资源文件中,按照上述说明进行了声明:

     <ControlTemplate x:Key="ComboBoxControlTemplateBasic" TargetType="{x:Type ComboBox}"> ... <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ... /> ... </ControlTemplate> 

    Create a copy of it with the following change, where selectedTemplate is the key of the DataTemplate you want to cooperate with the ControlTemplate : 通过以下更改创建它的副本,其中selectedTemplate是要与ControlTemplate合作的DataTemplatekey

     <ControlTemplate x:Key="ComboBoxControlTemplateHeader" TargetType="{x:Type ComboBox}"> ... <ContentPresenter x:Name="contentPresenter" ContentTemplate="{DynamicResource selectedTemplate}" ... /> ... </ControlTemplate> 
  2. Declare the appropriate styles: 声明适当的样式:

     <Style TargetType="{x:Type ComboBox}"> <Setter Property="Template" Value="{StaticResource ComboBoxControlTemplateBasic}" /> <!-- other generic style setters --> </Style> <Style x:Key="ComboBoxHeader" x:Name="ComboBoxHeader" TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}"> <Setter Property="Template" Value="{StaticResource ComboBoxControlTemplateHeader}" /> <Setter Property="ItemTemplateSelector" Value="{DynamicResource itemTemplateSelector}"/> <!-- other specific style setters --> </Style> 

Results 结果

  • Every ComboBox shares the same look. 每个ComboBox具有相同的外观。
  • The dynamic use of DataTemplate selectedTemplate allows each ListView header gmail-like ComboBox to have the same look with unique binding values. 动态使用DataTemplate selectedTemplate允许每个ListView标头类似gmail的ComboBox具有唯一绑定值的相同外观。

Take for example the OP ComboBox header plus the following ComboBox with the same item source: 例如,OP ComboBox标头以及具有相同项目源的以下ComboBox

<ComboBox 
    HorizontalAlignment="Left" 
    Margin="10,152,0,0" 
    VerticalAlignment="Top" 
    Width="120"
    ItemsSource="{Binding Options.Items}"
    SelectedValue="{Binding Options.SelectedItem}"/>

<GridViewColumnHeader>
    <ComboBox 
        ItemsSource="{Binding Options.Items}"
        SelectedValue="{Binding Options.SelectedItem}"
        Style="{StaticResource ComboBoxHeader}">
        <ComboBox.Resources>
            <DataTemplate x:Key="selectedTemplate">
                <TextBlock 
                    x:Name="displayText"
                    Text="{Binding DataContext.Options.SelectedDisplay, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
                    FontSize="20"
                    Height="22"/>
            </DataTemplate>

            <DataTemplate x:Key="dropDownTemplate">
                <TextBlock Text="{Binding}" FontSize="12"/>
            </DataTemplate>

            <local:ComboBoxItemTemplateSelector
                x:Key="itemTemplateSelector"
                SelectedTemplate="{StaticResource selectedTemplate}"
                DropDownTemplate="{StaticResource dropDownTemplate}"/>
        </ComboBox.Resources>
    </ComboBox>
</GridViewColumnHeader>

工作实例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM