На самом деле существует довольно много разных способов достижения этого, но для чего-то такого простого я бы, вероятно, просто использовал DataTemplate с DataTrigger, чтобы изменить текст, когда это пустая строка:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
<ComboBox ItemsSource="{Binding Styles, Mode=OneWay}" SelectedItem="{Binding SelectedStyle}">
<ComboBox.Resources>
<DataTemplate DataType="{x:Type sys:String}">
<TextBlock>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text" Value="{Binding}" />
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="">
<Setter Property="Text" Value="[Discard style]" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ComboBox.Resources>
</ComboBox>
Однако вам нужно будет использовать конвертер, если вы хотите обработать нуль в вашем списке строк.В этом случае проигнорируйте приведенный выше код и примените конвертер к привязке ItemsSource:
<Window.Resources>
<conv:StringConverter x:Key="StringConverter" />
</Window.Resources>
<StackPanel Orientation="Vertical">
<ComboBox ItemsSource="{Binding Styles, Mode=OneWay, Converter={StaticResource StringConverter}}" SelectedItem="{Binding SelectedStyle}" />
</StackPanel>
И тогда ваш конвертер будет выглядеть примерно так:
public class StringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value as IEnumerable<string>).Select(s => String.IsNullOrEmpty(s) ? "[Discard style]" : s);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
ОБНОВЛЕНИЕ: О, хорошо,Я вижу, что ты пытаешься сделать.В этом случае да, вам нужно использовать два преобразователя ... один для фильтрации списка строк, которые модель представления передает в представление, а затем второй для изменения значения, которое распространяется снова.
Прежде чем идти дальше, я должен отметить, что то, что вы пытаетесь сделать, - это действительно очень плохая идея.Весь смысл MVVM в том, что логика выполняется в модели представления.То, что вы действительно пытаетесь сделать, это реализовать логику на уровне представления, и это полностью противоречит всей парадигме MVVM / привязки данных.Вся цель модели представления состоит в том, чтобы подготовить данные в формате, который представление может легко использовать с минимальным количеством изменений;в тот момент, когда вы обнаруживаете, что вводите логику в представление (включая конвертеры, которые также являются частью этого слоя), это очень сильный признак того, что ваша модель представления не выполняет свою работу должным образом.
Чтобы ответить на ваш вопрос, хотя,вам понадобится конвертер в вашем SelectedStyleBinding в дополнение к тому, который я опубликовал выше.Теперь вы также будете вынуждены выполнить эту привязку в одну сторону к источнику, что означает, что вы потеряете возможность программно контролировать текущий выбранный элемент:
<ComboBox ItemsSource="{Binding Styles, Mode=OneWay, Converter={StaticResource StringConverter}}" SelectedItem="{Binding SelectedStyle, Converter={StaticResource SingleStringConverter}, Mode=OneWayToSource}" />
И второй конвертер:
public class SingleStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value?.ToString() == "[Discard style]") ? "" : value?.ToString();
}
}
Если вам нужно сохранить программный выбор элементов, тогда единственный вариант - привязать SelectedIndex вместо SelectedItem, тогда ваша модель представления должна будет отвечать за поиск строки в списке источников.
Но опять же, все это очень плохой код.Правильная вещь, которую нужно сделать здесь, - это изменить свой исходный список, чтобы он стал классом пользовательской модели представления или чем-то еще, с чем ваше представление может более легко работать.