gpt4 book ai didi

wpf - 我可以为 WPF ComboBox 中的所选项目使用与下拉部分中的项目不同的模板吗?

转载 作者:行者123 更新时间:2023-12-03 02:20:21 26 4
gpt4 key购买 nike

我有一个 WPF 组合框,其中充满了客户对象。我有一个数据模板:

<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 ItemsSource="{Binding Customers}" 
SelectedItem="{Binding SelectedCustomer}"
ItemTemplate="{StaticResource CustomerTemplate}" />

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

最佳答案

使用上述 DataTrigger/Binding 解决方案的问题有两个。第一个是您实际上最终会收到一条绑定(bind)警告,提示您找不到所选项目的相对源。然而,更大的问题是您弄乱了数据模板并使它们特定于 ComboBox。

我提出的解决方案更好地遵循 WPF 设计,因为它使用 DataTemplateSelector,您可以在其中使用 SelectedItemTemplateDropDownItemsTemplate 指定单独的模板属性以及两者的“选择器”变体。

注意:针对 C#9 进行了更新,启用了可空性并在搜索期间使用模式匹配

public class ComboBoxTemplateSelector : DataTemplateSelector {

public DataTemplate? SelectedItemTemplate { get; set; }
public DataTemplateSelector? SelectedItemTemplateSelector { get; set; }
public DataTemplate? DropdownItemsTemplate { get; set; }
public DataTemplateSelector? DropdownItemsTemplateSelector { get; set; }

public override DataTemplate SelectTemplate(object item, DependencyObject container) {

var itemToCheck = container;

// Search up the visual tree, stopping at either a ComboBox or
// a ComboBoxItem (or null). This will determine which template to use
while(itemToCheck is not null
and not ComboBox
and not ComboBoxItem)
itemToCheck = VisualTreeHelper.GetParent(itemToCheck);

// If you stopped at a ComboBoxItem, you're in the dropdown
var inDropDown = itemToCheck is ComboBoxItem;

return inDropDown
? DropdownItemsTemplate ?? DropdownItemsTemplateSelector?.SelectTemplate(item, container)
: SelectedItemTemplate ?? SelectedItemTemplateSelector?.SelectTemplate(item, container);
}
}

为了使其在 XAML 中更易于使用,我还添加了一个标记扩展,该扩展仅在其 ProvideValue 函数中创建并返回上述类。

public class ComboBoxTemplateSelectorExtension : MarkupExtension {

public DataTemplate? SelectedItemTemplate { get; set; }
public DataTemplateSelector? SelectedItemTemplateSelector { get; set; }
public DataTemplate? DropdownItemsTemplate { get; set; }
public DataTemplateSelector? DropdownItemsTemplateSelector { get; set; }

public override object ProvideValue(IServiceProvider serviceProvider)
=> new ComboBoxTemplateSelector(){
SelectedItemTemplate = SelectedItemTemplate,
SelectedItemTemplateSelector = SelectedItemTemplateSelector,
DropdownItemsTemplate = DropdownItemsTemplate,
DropdownItemsTemplateSelector = DropdownItemsTemplateSelector
};
}

这就是你如何使用它。漂亮、干净、清晰,您的模板保持“纯粹”

Note: 'is:' here is my xmlns mapping for where I put the class in code. Make sure to import your own namespace and change 'is:' as appropriate.

<ComboBox x:Name="MyComboBox"
ItemsSource="{Binding Items}"
ItemTemplateSelector="{is:ComboBoxTemplateSelector
SelectedItemTemplate={StaticResource MySelectedItemTemplate},
DropdownItemsTemplate={StaticResource MyDropDownItemTemplate}}" />

如果您愿意,还可以使用 DataTemplateSelectors...

<ComboBox x:Name="MyComboBox"
ItemsSource="{Binding Items}"
ItemTemplateSelector="{is:ComboBoxTemplateSelector
SelectedItemTemplateSelector={StaticResource MySelectedItemTemplateSelector},
DropdownItemsTemplateSelector={StaticResource MyDropDownItemTemplateSelector}}" />

或者混合搭配!在这里,我对所选项目使用模板,但对 DropDown 项目使用模板选择器。

<ComboBox x:Name="MyComboBox"
ItemsSource="{Binding Items}"
ItemTemplateSelector="{is:ComboBoxTemplateSelector
SelectedItemTemplate={StaticResource MySelectedItemTemplate},
DropdownItemsTemplateSelector={StaticResource MyDropDownItemTemplateSelector}}" />

此外,如果您没有为所选或下拉项指定 Template 或 TemplateSelector,它只会退回到基于数据类型的数据模板的常规解析,正如您所期望的那样。因此,例如,在下面的情况下,所选项目显式设置了其模板,但下拉列表将继承适用于数据上下文中对象的数据类型的任何数据模板。

<ComboBox x:Name="MyComboBox"
ItemsSource="{Binding Items}"
ItemTemplateSelector="{is:ComboBoxTemplateSelector
SelectedItemTemplate={StaticResource MyTemplate} />

享受吧!

关于wpf - 我可以为 WPF ComboBox 中的所选项目使用与下拉部分中的项目不同的模板吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4672867/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com