Pet*_*ter 61 wpf templates combobox
我有一个WPF组合框,它充满了,例如,客户对象.我有一个DataTemplate:
<DataTemplate DataType="{x:Type MyAssembly:Customer}">
<StackPanel>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Address}" />
</StackPanel>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)
这样,当我打开我的ComboBox时,我可以看到不同的客户的姓名,以及下面的地址.
但是当我选择一个Customer时,我只想在ComboBox中显示Name.就像是:
<DataTemplate DataType="{x:Type MyAssembly:Customer}">
<StackPanel>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)
我可以为ComboBox中的所选项目选择另一个模板吗?
解
在答案的帮助下,我解决了这个问题:
<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>
Run Code Online (Sandbox Code Playgroud)
然后,我的ComboBox:
<ComboBox ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer}"
ItemTemplate="{StaticResource CustomerTemplate}" />
Run Code Online (Sandbox Code Playgroud)
让它工作的重要部分是Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}"(值应为x的部分:Null,而不是True).
Mar*_*eIV 58
使用上面提到的DataTrigger/Binding解决方案的问题是双重的.第一个是你实际上最终得到一个绑定警告,你找不到所选项目的相对来源.然而,更大的问题是你的数据模板混乱,并使它们特定于ComboBox.
我提出的解决方案遵循WPF设计更好,因为它使用DataTemplateSelector,您可以使用SelectedItemTemplate和DropDownItemsTemplate属性以及两者的选择器指定单独的模板.
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 != null && !(itemToCheck is ComboBoxItem) && !(itemToCheck is ComboBox))
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);
}
}
Run Code Online (Sandbox Code Playgroud)
注意:为简单起见,我的示例代码使用了新的"?".C#6(VS 2015)的特点.如果您使用的是旧版本,只需删除"?" 并在上面调用'SelectTemplate'之前显式检查null并返回null,否则如下:
return inDropDown
? DropdownItemsTemplate ??
((DropdownItemsTemplateSelector != null)
? DropdownItemsTemplateSelector.SelectTemplate(item, container)
: null)
: SelectedItemTemplate ??
((SelectedItemTemplateSelector != null)
? SelectedItemTemplateSelector.SelectTemplate(item, container)
: null)
Run Code Online (Sandbox Code Playgroud)
我还添加了一个标记扩展,它简单地创建并返回上面的类,以方便XAML.
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)
{
return new ComboBoxTemplateSelector(){
SelectedItemTemplate = SelectedItemTemplate,
SelectedItemTemplateSelector = SelectedItemTemplateSelector,
DropdownItemsTemplate = DropdownItemsTemplate,
DropdownItemsTemplateSelector = DropdownItemsTemplateSelector
};
}
}
Run Code Online (Sandbox Code Playgroud)
这就是你如何使用它.漂亮,干净,清晰,模板保持"纯净"
注意:'是:'这是我的xmlns映射,用于将类放在代码中.确保导入您自己的命名空间并根据需要更改"is:".
<ComboBox x:Name="MyComboBox"
ItemsSource="{Binding Items}"
ItemTemplateSelector="{is:ComboBoxTemplateSelector
SelectedItemTemplate={StaticResource MySelectedItemTemplate},
DropdownItemsTemplate={StaticResource MyDropDownItemTemplate}}" />
Run Code Online (Sandbox Code Playgroud)
如果您愿意,也可以使用DataTemplateSelectors ...
<ComboBox x:Name="MyComboBox"
ItemsSource="{Binding Items}"
ItemTemplateSelector="{is:ComboBoxTemplateSelector
SelectedItemTemplateSelector={StaticResource MySelectedItemTemplateSelector},
DropdownItemsTemplateSelector={StaticResource MyDropDownItemTemplateSelector}}" />
Run Code Online (Sandbox Code Playgroud)
或者混搭!这里我使用的是所选项目的模板,但是DropDown项目的模板选择器.
<ComboBox x:Name="MyComboBox"
ItemsSource="{Binding Items}"
ItemTemplateSelector="{is:ComboBoxTemplateSelector
SelectedItemTemplate={StaticResource MySelectedItemTemplate},
DropdownItemsTemplateSelector={StaticResource MyDropDownItemTemplateSelector}}" />
Run Code Online (Sandbox Code Playgroud)
此外,如果您没有为选定项或下拉项指定模板或TemplateSelector,它只会再次回到基于数据类型的数据模板的常规解析,如您所料.因此,例如,在下面的情况中,所选项目的模板显式设置,但下拉列表将继承适用于数据上下文中对象的DataType的数据模板.
<ComboBox x:Name="MyComboBox"
ItemsSource="{Binding Items}"
ItemTemplateSelector="{is:ComboBoxTemplateSelector
SelectedItemTemplate={StaticResource MyTemplate} />
Run Code Online (Sandbox Code Playgroud)
请享用!
H.B*_*.B. 31
简单方案:
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Address}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ComboBoxItem}}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)
(注意,在框中选择并显示的元素而不是列表中的元素不在其中,ComboBoxItem因此触发器上Null)
如果您想要切换整个模板,您也可以使用触发器来执行此操作,例如将不同的ContentTemplate应用于aContentControl.DataType如果您只是更改此选择案例的模板,这也允许您保留基于默认的模板选择,例如:
<ComboBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ComboBoxItem}}"
Value="{x:Null}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<!-- ... -->
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ComboBox.ItemTemplate>
Run Code Online (Sandbox Code Playgroud)
请注意,此方法将导致绑定错误,因为找不到所选项的相对源.对于另一种方法,请参阅MarqueIV的答案.