c# - Mostrar el encabezado del grupo ComboBox para Silverlight
xaml optgroup (3)
Quiero mostrar un ComboBox
con OPTGROUP
encabezado de estilo OPTGROUP en Silverlight. Cada sitio web que encuentro (incluidas las preguntas sobre SO) que sovle este enlace a un enlace obsoleto y, de forma práctica, no muestran fragmentos de código para que pueda trabajar.
P.ej:
Entonces, ¿cómo hago esto?
Aquí hay un enfoque generalizado. No está mal, y debe ser lo suficientemente flexible, aunque tiene la debilidad de requerir una clase de colección extendida (no puede hacer uso de CollectionViewSource).
Paso 1 Objeto ComboBoxGroupHeader
Esto cumple la función de "entrada ficticia" mencionada por @NiteshChordiya.
public class ComboBoxGroupHeader
{
public ComboBoxGroupHeader(object header)
{
Header = header;
}
public object Header { get; protected set; }
}
Paso 2 Extended ComboBox
Esto anula PrepareContainerForItemOverride
, para jugar con los contenedores de los elementos ficticios. También proporciona un (opcional) "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;
}
}
}
Paso 3 Clase de colección extendida
Esto hace la agrupación y agrega las entradas ficticias "ComboBoxGroupHeader". Esta implementación es esencialmente de solo lectura (las agrupaciones se romperían si trataba de agregar nuevos elementos), pero sería sencillo admitir operaciones como "Agregar", "Insertar", 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>())
);
}
}
Uso
Funciona como un ComboBox
normal, con el HeaderTemplate
opcional:
<local:GroupedComboBox ItemsSource="{Binding Source}">
<local:GroupedComboBox.HeaderTemplate>
<TextBlock FontSize="9" TextDecorations="Underline" Foreground="DarkGray"
Text="{Binding}" />
</local:GroupedComboBox.HeaderTemplate>
</local:GroupedComboBox>
Para que el agrupamiento surta efecto, la fuente debe usar la "Agrupación de Recolección" arriba, para incluir los elementos del encabezado ficticio. Ejemplo:
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")
});
}
}
El encabezado de grupo no es compatible con ComboBox. Manera alternativa para implementarlo con DataGrid o usar TreeView para mostrar datos agrupados.
Sin embargo, puedes probar algo como esto,
Ver mi pregunta similar: ¿Cómo mostrar el encabezado de grupo para los elementos en el combobox de Silverlight? Puse entradas ficticias en el origen de la colección para indicar el encabezado del grupo y luego modifiqué DataTemplate para mostrar los encabezados del grupo de manera diferente y las entradas normales de manera separada.