我可以为WPF组合框中的选定项目使用与下拉部分中的项目不同的模板吗?

我有一个WPF组合框,里面装有客户对象。我有一个DataTemplate:


<DataTemplate DataType="{x:Type MyAssembly:Customer}">

    <StackPanel>

        <TextBlock Text="{Binding Name}" />

        <TextBlock Text="{Binding Address}" />

    </StackPanel>

</DataTemplate>

这样,当我打开组合框时,可以看到不同的客户及其名称,然后在其下方显示地址。


但是,当我选择一个客户时,我只想在组合框中显示名称。就像是:


<DataTemplate DataType="{x:Type MyAssembly:Customer}">

    <StackPanel>

        <TextBlock Text="{Binding Name}" />

    </StackPanel>

</DataTemplate>

我可以为组合框中的选定项目选择另一个模板吗?



在答案的帮助下,我这样解决了它:


<UserControl.Resources>

    <ControlTemplate x:Key="SimpleTemplate">

        <StackPanel>

            <TextBlock Text="{Binding Name}" />

        </StackPanel>

    </ControlTemplate>

    <ControlTemplate x:Key="ExtendedTemplate">

        <StackPanel>

            <TextBlock Text="{Binding Name}" />

            <TextBlock Text="{Binding Address}" />

        </StackPanel>

    </ControlTemplate>

    <DataTemplate x:Key="CustomerTemplate">

        <Control x:Name="theControl" Focusable="False" Template="{StaticResource ExtendedTemplate}" />

        <DataTemplate.Triggers>

            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">

                <Setter TargetName="theControl" Property="Template" Value="{StaticResource SimpleTemplate}" />

            </DataTrigger>

        </DataTemplate.Triggers>

    </DataTemplate>

</UserControl.Resources>

然后,我的ComboBox:


<ComboBox ItemsSource="{Binding Customers}" 

                SelectedItem="{Binding SelectedCustomer}"

                ItemTemplate="{StaticResource CustomerTemplate}" />

使它起作用的重要部分是Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}"(值应为x:Null,而不是True的部分)。


当年话下
浏览 499回答 3
3回答

神不在的星期二

使用上述DataTrigger / Binding解决方案存在两个问题。首先,您实际上会收到一条绑定警告,提示您找不到所选项目的相对来源。但是,更大的问题是您已经弄乱了数据模板,并使它们特定于ComboBox。我更好地介绍的解决方案遵循WPF设计,因为它使用DataTemplateSelector,您可以在其上使用SelectedItemTemplate和DropDownItemsTemplate属性以及两者的“选择器”变体来指定单独的模板。public class ComboBoxTemplateSelector : DataTemplateSelector{&nbsp; &nbsp; public DataTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SelectedItemTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { get; set; }&nbsp; &nbsp; public DataTemplateSelector SelectedItemTemplateSelector&nbsp; { get; set; }&nbsp; &nbsp; public DataTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DropdownItemsTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ get; set; }&nbsp; &nbsp; public DataTemplateSelector DropdownItemsTemplateSelector { get; set; }&nbsp; &nbsp; public override DataTemplate SelectTemplate(object item, DependencyObject container)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var itemToCheck = container;&nbsp; &nbsp; &nbsp; &nbsp; // Search up the visual tree, stopping at either a ComboBox or&nbsp; &nbsp; &nbsp; &nbsp; // a ComboBoxItem (or null). This will determine which template to use&nbsp; &nbsp; &nbsp; &nbsp; while(itemToCheck != null && !(itemToCheck is ComboBoxItem) && !(itemToCheck is ComboBox))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; itemToCheck = VisualTreeHelper.GetParent(itemToCheck);&nbsp; &nbsp; &nbsp; &nbsp; // If you stopped at a ComboBoxItem, you're in the dropdown&nbsp; &nbsp; &nbsp; &nbsp; var inDropDown = (itemToCheck is ComboBoxItem);&nbsp; &nbsp; &nbsp; &nbsp; return inDropDown&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? DropdownItemsTemplate ?? DropdownItemsTemplateSelector?.SelectTemplate(item, container)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : SelectedItemTemplate&nbsp; ?? SelectedItemTemplateSelector?.SelectTemplate(item, container);&nbsp;&nbsp; &nbsp; }}注意:为简单起见,我的示例代码在此处使用新的“?”。C#6(VS 2015)的功能。如果您使用的是旧版本,只需删除“?” 并在调用上面的“ SelectTemplate”之前显式检查null,否则返回null,如下所示:return inDropDown&nbsp; &nbsp; ? DropdownItemsTemplate ??&nbsp; &nbsp; &nbsp; &nbsp; ((DropdownItemsTemplateSelector != null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? DropdownItemsTemplateSelector.SelectTemplate(item, container)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : null)&nbsp; &nbsp; : SelectedItemTemplate ??&nbsp; &nbsp; &nbsp; &nbsp; ((SelectedItemTemplateSelector != null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? SelectedItemTemplateSelector.SelectTemplate(item, container)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : null)为了方便在XAML中使用,我还包括一个标记扩展,该扩展仅创建并返回上述类。public class ComboBoxTemplateSelectorExtension : MarkupExtension{&nbsp; &nbsp; public DataTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SelectedItemTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { get; set; }&nbsp; &nbsp; public DataTemplateSelector SelectedItemTemplateSelector&nbsp; { get; set; }&nbsp; &nbsp; public DataTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DropdownItemsTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ get; set; }&nbsp; &nbsp; public DataTemplateSelector DropdownItemsTemplateSelector { get; set; }&nbsp; &nbsp; public override object ProvideValue(IServiceProvider serviceProvider)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return new ComboBoxTemplateSelector(){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SelectedItemTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = SelectedItemTemplate,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SelectedItemTemplateSelector&nbsp; = SelectedItemTemplateSelector,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DropdownItemsTemplate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= DropdownItemsTemplate,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DropdownItemsTemplateSelector = DropdownItemsTemplateSelector&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }}这就是您的使用方式。干净,整洁,美观,模板保持“纯净”注意:“是:”这是我在代码中放置类的位置的xmlns映射。确保导入您自己的名称空间,并根据需要更改“ is:”。<ComboBox x:Name="MyComboBox"&nbsp; &nbsp; ItemsSource="{Binding Items}"&nbsp; &nbsp; ItemTemplateSelector="{is:ComboBoxTemplateSelector&nbsp; &nbsp; &nbsp; &nbsp; SelectedItemTemplate={StaticResource MySelectedItemTemplate},&nbsp; &nbsp; &nbsp; &nbsp; DropdownItemsTemplate={StaticResource MyDropDownItemTemplate}}" />如果您愿意,也可以使用DataTemplateSelectors。<ComboBox x:Name="MyComboBox"&nbsp; &nbsp; ItemsSource="{Binding Items}"&nbsp; &nbsp; ItemTemplateSelector="{is:ComboBoxTemplateSelector&nbsp; &nbsp; &nbsp; &nbsp; SelectedItemTemplateSelector={StaticResource MySelectedItemTemplateSelector},&nbsp; &nbsp; &nbsp; &nbsp; DropdownItemsTemplateSelector={StaticResource MyDropDownItemTemplateSelector}}" />或混合搭配!在这里,我为所选项目使用模板,但为DropDown项目使用模板选择器。<ComboBox x:Name="MyComboBox"&nbsp; &nbsp; ItemsSource="{Binding Items}"&nbsp; &nbsp; ItemTemplateSelector="{is:ComboBoxTemplateSelector&nbsp; &nbsp; &nbsp; &nbsp; SelectedItemTemplate={StaticResource MySelectedItemTemplate},&nbsp; &nbsp; &nbsp; &nbsp; DropdownItemsTemplateSelector={StaticResource MyDropDownItemTemplateSelector}}" />另外,如果您没有为选定的项目或下拉菜单项指定Template或TemplateSelector,它又会像您期望的那样退回到基于数据类型的常规数据模板解析。因此,例如,在以下情况下,所选项目的显式设置已明确设置,但下拉菜单将继承适用于数据上下文中对象的DataType的任何数据模板。<ComboBox x:Name="MyComboBox"&nbsp; &nbsp; ItemsSource="{Binding Items}"&nbsp; &nbsp; ItemTemplateSelector="{is:ComboBoxTemplateSelector&nbsp; &nbsp; &nbsp; &nbsp; SelectedItemTemplate={StaticResource MyTemplate} />请享用!

拉莫斯之舞

我用了下一种方法&nbsp;<UserControl.Resources>&nbsp; &nbsp; <DataTemplate x:Key="SelectedItemTemplate" DataType="{x:Type statusBar:OffsetItem}">&nbsp; &nbsp; &nbsp; &nbsp; <TextBlock Text="{Binding Path=ShortName}" />&nbsp; &nbsp; </DataTemplate></UserControl.Resources><StackPanel Orientation="Horizontal">&nbsp; &nbsp; <ComboBox DisplayMemberPath="FullName"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ItemsSource="{Binding Path=Offsets}"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; behaviors:SelectedItemTemplateBehavior.SelectedItemDataTemplate="{StaticResource SelectedItemTemplate}"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SelectedItem="{Binding Path=Selected}" />&nbsp; &nbsp; <TextBlock Text="User Time" />&nbsp; &nbsp; <TextBlock Text="" /></StackPanel>和行为public static class SelectedItemTemplateBehavior{&nbsp; &nbsp; public static readonly DependencyProperty SelectedItemDataTemplateProperty =&nbsp; &nbsp; &nbsp; &nbsp; DependencyProperty.RegisterAttached("SelectedItemDataTemplate", typeof(DataTemplate), typeof(SelectedItemTemplateBehavior), new PropertyMetadata(default(DataTemplate), PropertyChangedCallback));&nbsp; &nbsp; public static void SetSelectedItemDataTemplate(this UIElement element, DataTemplate value)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; element.SetValue(SelectedItemDataTemplateProperty, value);&nbsp; &nbsp; }&nbsp; &nbsp; public static DataTemplate GetSelectedItemDataTemplate(this ComboBox element)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return (DataTemplate)element.GetValue(SelectedItemDataTemplateProperty);&nbsp; &nbsp; }&nbsp; &nbsp; private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var uiElement = d as ComboBox;&nbsp; &nbsp; &nbsp; &nbsp; if (e.Property == SelectedItemDataTemplateProperty && uiElement != null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uiElement.Loaded -= UiElementLoaded;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UpdateSelectionTemplate(uiElement);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uiElement.Loaded += UiElementLoaded;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; static void UiElementLoaded(object sender, RoutedEventArgs e)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; UpdateSelectionTemplate((ComboBox)sender);&nbsp; &nbsp; }&nbsp; &nbsp; private static void UpdateSelectionTemplate(ComboBox uiElement)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var contentPresenter = GetChildOfType<ContentPresenter>(uiElement);&nbsp; &nbsp; &nbsp; &nbsp; if (contentPresenter == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; var template = uiElement.GetSelectedItemDataTemplate();&nbsp; &nbsp; &nbsp; &nbsp; contentPresenter.ContentTemplate = template;&nbsp; &nbsp; }&nbsp; &nbsp; public static T GetChildOfType<T>(DependencyObject depObj)&nbsp; &nbsp; &nbsp; &nbsp; where T : DependencyObject&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (depObj == null) return null;&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var child = VisualTreeHelper.GetChild(depObj, i);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var result = (child as T) ?? GetChildOfType<T>(child);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (result != null) return result;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; }}像魅力一样运作。这里不太喜欢Loaded事件,但是您可以根据需要进行修复
打开App,查看更多内容
随时随地看视频慕课网APP