Reputation: 2469
Is there any way I can add a seprator into a WPF combobox that is databound? ie in my xaml, the combobox's ItemsSource="{Binding TheList}". The list is an observable collection of objects, one of i want separated from the rest. This list is also generated from sql, so its not hard-coded or anything. I wouldn't want the seaprator to be selectable, either. Thanks!
Upvotes: 4
Views: 10551
Reputation: 137
All you need to do is separate your ComboBox items from your data items. You can do this by creating a property that builds the vstructure from a getter, and returns a collection of objects. Just make sure when your data has changed, trigger the PropertyChanged event for ComboItems property as well.
Here is a little example that creates a ComboBox that contains a collection of Versions, with a label and separator control at the top.
You can set the type of SelectedComboItem
to the same as your data type, but it will invalidate and display the invalid style if the selected item's type doesn't match.
// Header Label and Separator to display at top of ComboBox
private object[] _defaultComboItems = new object[] { new Label() { Content = "Versions"}, new Separator() };
// Property that builds the structure for the ComboBox.
public IEnumerable<object>? ComboItems
=> Versions == null
? _defaultComboItems
: _defaultComboItems.Concat(Versions);
// Observable collection for the data items
private ObservableCollection<Version> _versions;
public ObservableCollection<Version> Versions
{
get => _versions;
set
{
if (_versions != value)
{
if (_versions != null)
{
_versions.CollectionChanged -= signalComboItemsChanged;
}
// Notify that Versions and ComboItems are changing.
OnPropertyChanging(nameof(ComboItems));
OnPropertyChanging(nameof(Versions));
_versions = value;
// Notify that Versions and ComboItems have changed.
OnPropertyChanged(nameof(Versions));
OnPropertyChanged(nameof(ComboItems));
if (value != null)
{
// Subscribe to CollectionChanged to rebuild ComboItems when Versions changes.
value.CollectionChanged += signalComboItemsChanged;
}
}
// Callback to signal ComboItems changes.
void signalComboItemsChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged(nameof(ComboItems));
}
}
}
// Selected item in the ComboBox, which can be a control or data item.
private object? _selectedComboItem;
public object? SelectedComboItem
{
get => _selectedComboItem;
set
{
if (_selectedComboItem != value)
{
OnPropertyChanging(nameof(SelectedComboItem));
_selectedComboItem = value;
OnPropertyChanged(nameof(SelectedComboItem));
}
}
}
// Property to retrieve selected data item.
public Version? SelectedVersion
=> SelectedComboItem as Version;
<ComboBox ItemsSource="{Binding ComboItems}"
SelectedItem="{Binding SelectedComboItem}"/>
Upvotes: 0
Reputation: 89
XAML only solution for every item. You could probably add triggers based on ItemsControl
AlternationCount
if it was always the same list of items.
This is the result.
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="BorderBrush" Value="DarkGray" />
<Setter Property="BorderThickness" Value="0,1,0,0" />
</Style>
</ComboBox.ItemContainerStyle>
Upvotes: 1
Reputation: 76
I was building my combo box within the .cs file dynamically and without the use of Bindings, but I believe it could help you. The separators can't be clicked on and selected.
ComboBox frameColor = new ComboBox()
{
Width = 200,
Margin = new Thickness(180, -780, 0, 0),
VerticalAlignment = VerticalAlignment.Center,
IsEditable = false,
Items =
{
new ComboBoxItem(){...},
new Separator(),
new ComboBoxItem(){...},
new ComboBoxItem(){...},
new ComboBoxItem(){...},
new Separator(),
new ComboBoxItem(){...},
new ComboBoxItem(){...},
new ComboBoxItem(){...},
new ComboBoxItem(){...},
new ComboBoxItem(){...},
}
Upvotes: 3
Reputation: 1
If you want to do the same in C# code:
Cbx.Items.Add("ABC");
Cbx.Items.Add("DEF");
ComboBoxItem item = new ComboBoxItem();
item.Content = "GHI";
item.BorderBrush = Brushes.Black;
item.BorderThickness = new Thickness(0, 0, 0, 2);
Cbx.Items.Add(item);
Cbx.Items.Add("KLM");
Cbx.Items.Add("NOP");
Upvotes: 0
Reputation: 398
Although my ComboxBox
(at the moment) is not DataBound
I achieved the concept of a separator by adding a bottom border to an element. In this example two lines before and two lines after the separator.
<ComboBox x:Name="Cbx" SelectionChanged="Cbx_SelectionChanged">
<ComboBoxItem Content="select one..." Foreground="DarkGray" IsSelected="True" /
<ComboBoxItem Content="ABC" />
<ComboBoxItem Content="DEF" />
<ComboBoxItem Content="GHI" BorderBrush="Black" BorderThickness="0,0,0,2" />
<ComboBoxItem Content="KLM" />
<ComboBoxItem Content="NOP" />
</ComboBox>
Upvotes: 1
Reputation: 126
you need to use a ComboBox.ItemTemplate to draw your itens
http://www.silverlightshow.net/items/Silverlight-ComboBox.aspx
Upvotes: 0