--> The codebehind: public class ViewModel { public ObservableCollection List { get; set; } = new ObservableCollection(); public ListCollectionView Lcv { get; set; } public ViewModel() { List devices = new List(); devices.Add(new AudioDevice() { Name = "MP4 Audio1", Direction = "direction1" }); devices.Add(new AudioDevice() { Name = "MP4 Audio2", Direction = "direction1" }); devices.Add(new AudioDevice() { Name = "MP4 Audio3", Direction = "direction2" }); devices.Add(new AudioDevice() { Name = "MP4 Audio4", Direction = "direction2" }); devices.Add(new AudioDevice() { Name = "MP4 Audio5", Direction = "direction1" }); Lcv = new ListCollectionView(devices); Lcv.GroupDescriptions.Add(new PropertyGroupDescription("Direction")); } private int _selected; public int Selected { get { return _selected; } set { _selected = value; OnPropertyChanged("Selected"); } } public event PropertyChangedEventHandler PropertyChanged; internal void OnPropertyChanged([CallerMemberName] string propName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } } public class CustomTextBlock : TextBlock { public new string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); } // Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc... public static new readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(CustomTextBlock), new PropertyMetadata(null, (d, ea) => { if (d is TextBlock textBlock) { textBlock.Inlines.Clear(); if (ea.NewValue is string value) { foreach (char c in value) { textBlock.Inlines.Add(new Run { FontSize = GetFontSize(c), Text = c.ToString() }); } } } })); private static double GetFontSize(char c) { // You can add your other logic here /*if (c == '#') { return 5; } if (char.IsNumber(c)) { return 22; }*/ if (char.IsUpper(c)) { return 18; } return 10; } } public static class FocusExtension { public static bool GetIsFocused(DependencyObject obj) { return (bool)obj.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject obj, bool value) { obj.SetValue(IsFocusedProperty, value); } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached( "IsFocused", typeof(bool), typeof(FocusExtension), new UIPropertyMetadata(false, OnIsFocusedPropertyChanged)); private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var uie = (UIElement)d; if ((bool)e.NewValue) { if (uie.IsMouseOver) { uie.SetValue(IsFocusedProperty, false); } else { uie.Focus(); } } } } public class AudioDevice { public string Name { get; set; } public string Direction { get; set; } public string Id { get; set; } public bool Default { get; set; } public override string ToString() { return Name; } } public class Converter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { ComboBoxItem item = value as ComboBoxItem; ComboBox comboBox = ItemsControl.ItemsControlFromItemContainer(item) as ComboBox; int index = comboBox.ItemContainerGenerator.IndexFromContainer(item); if (index == comboBox.Items.Count - 1) { return "IsLastItem"; } else return "IsLastItem_No"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class DebugBindingExtension : MarkupExtension { public override object ProvideValue(System.IServiceProvider serviceProvider) { return new Converter(); } }