Может ли WPF ComboBox отображать альтернативный текст, если его выбор пуст?
G'day!
Я хочу свой WPF ComboBox
отображать какой-то альтернативный текст, когда его выборка с привязкой к данным null
,
Модель представления обладает ожидаемыми свойствами:
public ThingoSelectionViewModel : INotifyPropertyChanged {
public ThingoSelectionViewModel(IProvideThingos) {
this.Thingos = IProvideThingos.GetThingos();
}
public ObservableCollection<Thingo> Thingos { get; set; }
public Thingo SelectedThingo {
get { return this.selectedThingo; }
set { // set this.selectedThingo and raise the property change notification
}
// ...
}
Представление имеет XAML-привязку к модели представления ожидаемым образом:
<ComboBox x:Name="ComboboxDrive" SelectedItem="{Binding Path=SelectedThingo}"
IsEditable="false" HorizontalAlignment="Left" MinWidth="100"
IsReadOnly="false" Style="{StaticResource ComboboxStyle}"
Grid.Column="1" Grid.Row="1" Margin="5" SelectedIndex="0">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem IsEnabled="False">Select a thingo</ComboBoxItem>
<CollectionContainer
Collection="{Binding Source={StaticResource Thingos}}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
ComboBoxItem
вклинивается в верх это способ получить дополнительный предмет в верху. Это чистый хром: модель представления остается чистой и простой. Есть только одна проблема: пользователи хотят, чтобы "Выберите вещь" отображалось всякий раз, когда выбор ComboBox равен нулю.
Пользователи не хотят, чтобы по умолчанию была выбрана вещь. Они хотят видеть сообщение о том, что нужно выбрать вещь.
Я хотел бы избежать загрязнения модели представления ThingoWrapper
класс с ToString
метод, возвращающий "Выберите вещь", если его .ActualThingo
свойство равно нулю, оборачивая каждый Thingo
как я населяю Thingos
и выяснить какой-то способ, чтобы пользователь не мог выбрать nulled Thingo
,
Есть ли способ отобразить "Выберите вещь" в пределах ComboBox
границы, использующие чистый XAML или чистый XAML и несколько строк кода в классе code-behind представления?
7 ответов
Путь наименьшего сопротивления, который я здесь нашел, состоит в использовании шаблона нулевого объекта. В качестве примера использования этого шаблона в.NET Framework рассмотрите статическое значение Double.NaN, если вы создаете нулевой объект для своего Thingo в просмотреть модель вы можете добавить его в начало списка, чтобы обозначить "ничего не выбрано". Создайте DataTemplate для класса Thingo, в котором есть DataTrigger для экземпляра Null Object, в котором отображается "Выберите значение".
Я мог бы дать пример кода, но он уже не спит.
Насколько строги ваши требования к MVVM? Можете ли вы иметь немного кода в представлении?
Возможно, вы могли бы содержать ComboBox в сетке, что-то вроде этого:
<Grid>
<ComboBox x:Name="ComboBoxControl"
SelectionChanged="ComboBoxControl_SelectionChanged"
HorizontalAlignment="Left" VerticalAlignment="Top"
MinWidth="{Binding ElementName=UnselectedText, Path=ActualWidth}">
<ComboBoxItem>One</ComboBoxItem>
<ComboBoxItem>Two</ComboBoxItem>
<ComboBoxItem>Three</ComboBoxItem>
</ComboBox>
<TextBlock IsHitTestVisible="False"
x:Name="UnselectedText"
HorizontalAlignment="Left"
Text="Select an option..."
VerticalAlignment="Top" Margin="4"
Padding="0,0,30,0" />
</Grid>
Затем в коде вставьте некоторую логику в обработчик событий:
Private Sub ComboBoxControl_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs)
If ComboBoxControl.SelectedIndex = -1 Then
UnselectedText.Visibility = Windows.Visibility.Visible
Else
UnselectedText.Visibility = Windows.Visibility.Hidden
End If
End Sub
Настройка IsHitTestVisible="False"
DependencyProperty для TextBlock пропускает события мыши, так что вы можете щелкнуть ComboBox и установить видимость в Hidden
в коде сзади компоновка внешнего вида ComboBox по умолчанию не будет прыгать, когда текст подсказки скрыт.
Вы не можете использовать триггер шаблона элемента управления, но вы можете настроить простой шаблон элемента для комбинированного списка:
<ComboBox ItemsSource="{Binding}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="displayText" Text="{Binding}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter TargetName="displayText" Property="Text" Value="Default Value" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Изменить: Похоже, идея триггера не идет. Я добавил следующее к контрольному шаблону тестового поля со списком безрезультатно:
<Trigger Property="SelectedItem" Value="{x:Null}">
<Setter Property="Text" Value="No Item Selected"/>
</Trigger>
Кроме того, при попытке отредактировать шаблон элемента управления в Blend (Edit Current) у меня остался безобъектный комбинированный список, без цветов, просто уродливая кнопка (но есть выпадающий список без полей). Попробуйте кто-нибудь еще предложение (Майк Браун, возможно).
Оригинал:
Вы можете использовать Trigger в шаблоне Control. Вот пример использования ListBox из приложения, над которым я работаю.
<ControlTemplate x:Key="SnazzyFormListBoxTemplate" TargetType="{x:Type ListBox}">
<Microsoft_Windows_Themes:ClassicBorderDecorator x:Name="Bd" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderStyle="Sunken" BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Padding="{TemplateBinding Padding}" Focusable="False" Template="{DynamicResource SnazzyScrollViewerControlTemplate}">
<Grid>
<TextBlock x:Name="textBlock" Text="No Items" FontFamily="Arial" FontWeight="Bold" FontSize="13.333" Foreground="#4D000000" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10"/>
<ItemsPresenter x:Name="itemsPresenter" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ScrollViewer>
</Microsoft_Windows_Themes:ClassicBorderDecorator>
<ControlTemplate.Triggers>
<Trigger Property="Selector.IsSelected" Value="True"/>
<Trigger Property="HasItems" Value="False">
<Setter Property="Visibility" TargetName="textBlock" Value="Visible"/>
<Setter Property="Visibility" TargetName="itemsPresenter" Value="Collapsed"/>
</Trigger>
<Trigger Property="HasItems" Value="True">
<Setter Property="Visibility" TargetName="textBlock" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="itemsPresenter" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Приведенный выше ControlTemplate имеет триггер, который проверяет свойство HasItems. Если False, текстовое поле с надписью "Нет элементов" отображается в середине списка. Если есть Предметы, они отображаются.
В вашем случае измените триггер, чтобы проверить, является ли ItemSelected x:Null, и установите для свойства Text значение "Ничего не выбрано".
Я знаю, что это старая тема, но вот как я это делаю. После получения коллекции Thingos я просто вставляю новый Thingo со значением фиктивного идентификатора и отображаемым значением "Выберите вещь".
public ThingoSelectionViewModel(IProvideThingos) {
this.Thingos = IProvideThingos.GetThingos();
Thingo newThingo = new Thingo();
newThingo.ThingoID = -1;
newThingo.ThingoDisplayName = "Select a thingo";
this.Thingos.Insert(0, newThingo);
}
Теперь, когда ComboBox привязан к базе данных, первый пункт - "Выбрать вещь". Затем, когда выбран Thingo, я проверяю идентификатор SelectedThingo и действую соответствующим образом.
Другой вариант:
<ComboBox>
<ComboBoxItem Visibility="Collapsed" IsSelected="True">
<TextBlock Text="Choose item" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="Item 1" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="Item 2" />
</ComboBoxItem>
</ComboBox>
Я знаю, что я воскрешаю старый пост, но это было первое, что появилось в моем поиске в Google. В Visual Studio вы можете выбрать для параметра "Выбор по умолчанию" значение 0, а не "-1", и просто первым текстом выбора будет текст по умолчанию.
<ComboBox x:name="ThingoSelector" SelectedIndex="0">
<ComboBoxItem IsEnabled="False">Choose Thingo</ComboBoxItem>
<ComboBoxItem>Thingo 1</ComboBoxItem>
</ComboBox>