显示Silverlight的组合框标题 [英] Show ComboBox group header for Silverlight
问题描述
我想在Silverlight中显示 ComboBox
与 OPTGROUP
样式标题。
例如:
我发现的每个网站(包括SO的问题)都会将此链接拖放到过时的链接, / p>>
那么我该如何做呢?
它不坏,应该足够灵活 - 虽然它有弱点,需要一个扩展的集合类(不能使用CollectionViewSource)。
步骤1 ComboBoxGroupHeader对象
这起到了@NiteshChordiya提到的虚拟条目的作用。
public class ComboBoxGroupHeader
{
public ComboBoxGroupHeader(object header)
{
Header = header;
}
public object Header {get;保护集; }
}
第2步 / em>
这将覆盖 PrepareContainerForItemOverride
,以便修改虚拟项目的容器。它还提供(可选)HeaderTemplate。
public class GroupedComboBox:ComboBox
{
public DataTemplate HeaderTemplate
{
get {return(DataTemplate)GetValue(HeaderTemplateProperty); }
set {SetValue(HeaderTemplateProperty,value); }
}
public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.Register(HeaderTemplate,typeof(DataTemplate),typeof(GroupedComboBox),new PropertyMetadata(null));
protected override void PrepareContainerForItemOverride(DependencyObject元素,对象项)
{
base.PrepareContainerForItemOverride(element,item);
var container = element as ComboBoxItem;
if(container!= null&& item is ComboBoxGroupHeader)
{
//防止选择
container.IsHitTestVisible = false;
//调整容器以显示标题内容
container.ContentTemplate = HeaderTemplate
container.Content =((ComboBoxGroupHeader)item).Header;
}
}
}
/ strong> 扩展集合类
这样做了分组,并添加了ComboBoxGroupHeader虚拟条目。这个实现基本上是只读的(如果你试图添加新项目,分组将会中断),但它将直接支持像Add,Insert等操作。
public class GroupedCollection< T,TGroup> :ObservableCollection< object>
{
private Func< T,TGroup> _grouping;
public IEnumerable< T> BaseItems
{
get {return base.Items.OfType< T>(); }
}
public GroupedCollection(IEnumerable< T> initial,Func< T,TGroup> grouping)
:base(GetGroupedItems(initial,
_grouping = grouping;
}
private static IEnumerable< object> GetGroupedItems(IEnumerable< T> items,Func< T,TGroup> grouping)
{
return item
.GroupBy(grouping)
.SelectMany(grp =>
new object [] {new ComboBoxGroupHeader(grp.Key)}
.Union(grp.OfType< object>())
);
}
}
使用 >
它像一个普通的 ComboBox
,可选的 HeaderTemplate
< local:GroupedComboBox ItemsSource ={Binding Source}>
< local:GroupedComboBox.HeaderTemplate>
< TextBlock FontSize =9TextDecorations =UnderlineForeground =DarkGray
Text ={Binding}/>
< / local:GroupedComboBox.HeaderTemplate>
< / local:GroupedComboBox>
要使分组生效,源必须使用上述GroupedCollection伪标题项。示例:
public class Item
{
public string Name {get;组; }
public string Category {get;组; }
public Item(string name,string category)
{
Name = name;
Category = category;
}
}
public class Item:GroupedCollection< Item,string>
{
public Items(IEnumerable< Item> items)
:base(items,item => item.Category){}
}
public class ViewModel
{
public IEnumerable< Item>源{get;私人集}
public ViewModel()
{
Source = new Items(new Item [] {
new Item(Apples,Fruits),
new Item(Carrots,Vegetables),
new Item(Bananas,Fruits),
new Item(Lettuce,Vegetables),
新项目(Oranges,Fruits)
});
}
}
I want to show a ComboBox
with OPTGROUP
style header gruopings in Silverlight. Every website I find (including questions on SO) that sovle this link to an outdated link and, handily, show no code snippets for me to work from.
E.g.:
So how do I do this?
Here is one generalized approach. It's not bad, and should be flexible enough -- although it has the weakness of requiring an extended collection class (cannot make use of CollectionViewSource).
Step 1 ComboBoxGroupHeader object
This plays the role of "dummy entry" mentioned by @NiteshChordiya.
public class ComboBoxGroupHeader
{
public ComboBoxGroupHeader(object header)
{
Header = header;
}
public object Header { get; protected set; }
}
Step 2 Extended ComboBox
This overrides PrepareContainerForItemOverride
, in order to tinker with the dummy items' containers. It also provides an (optional) "HeaderTemplate".
public class GroupedComboBox : ComboBox
{
public DataTemplate HeaderTemplate
{
get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
set { SetValue(HeaderTemplateProperty, value); }
}
public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(GroupedComboBox), new PropertyMetadata(null));
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var container = element as ComboBoxItem;
if (container != null && item is ComboBoxGroupHeader)
{
// prevent selection
container.IsHitTestVisible = false;
// adjust the container to display the header content
container.ContentTemplate = HeaderTemplate
container.Content = ((ComboBoxGroupHeader)item).Header;
}
}
}
Step 3 Extended collection class
This does the grouping, and adds the dummy "ComboBoxGroupHeader" entries. This implementation is essentially read-only (groupings would break if you tried to add new items), but it would be straight-forward to support operations like "Add", "Insert", etc.
public class GroupedCollection<T, TGroup> : ObservableCollection<object>
{
private Func<T, TGroup> _grouping;
public IEnumerable<T> BaseItems
{
get { return base.Items.OfType<T>(); }
}
public GroupedCollection(IEnumerable<T> initial, Func<T, TGroup> grouping)
: base(GetGroupedItems(initial, grouping))
{
_grouping = grouping;
}
private static IEnumerable<object> GetGroupedItems(IEnumerable<T> items, Func<T, TGroup> grouping)
{
return items
.GroupBy(grouping)
.SelectMany(grp =>
new object[] { new ComboBoxGroupHeader(grp.Key) }
.Union(grp.OfType<object>())
);
}
}
Usage
It works like a normal ComboBox
, with the optional HeaderTemplate
:
<local:GroupedComboBox ItemsSource="{Binding Source}">
<local:GroupedComboBox.HeaderTemplate>
<TextBlock FontSize="9" TextDecorations="Underline" Foreground="DarkGray"
Text="{Binding}" />
</local:GroupedComboBox.HeaderTemplate>
</local:GroupedComboBox>
For the grouped to take effect, the source must use the "GroupedCollection" above, so as to include the dummy header items. Example:
public class Item
{
public string Name { get; set; }
public string Category { get; set; }
public Item(string name, string category)
{
Name = name;
Category = category;
}
}
public class Items : GroupedCollection<Item, string>
{
public Items(IEnumerable<Item> items)
: base(items, item => item.Category) { }
}
public class ViewModel
{
public IEnumerable<Item> Source { get; private set; }
public ViewModel()
{
Source = new Items(new Item[] {
new Item("Apples", "Fruits"),
new Item("Carrots", "Vegetables"),
new Item("Bananas", "Fruits"),
new Item("Lettuce", "Vegetables"),
new Item("Oranges", "Fruits")
});
}
}
这篇关于显示Silverlight的组合框标题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!