WPF ComboBox может отобразить альтернативный текст, когда его выбор является пустым?

Хороший день!

Я хочу свой 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 втиснутый в вершину способ получить дополнительный объект наверху. Это - чистый хром: модель представления остается чистой и простой. Существует всего одна проблема: пользователи хотят "Выбор thingo", отображенный каждый раз, когда ComboBox' выбор является пустым.

Пользователи не хотят thingo, выбранный по умолчанию. Они хотят видеть, что сообщение говорит им выбирать thingo.

Я хотел бы избежать необходимости загрязнять viewmodel a ThingoWrapper класс с a ToString метод возвращая "Выбор thingo", если .ActualThingo свойство является пустым, перенося каждого Thingo поскольку я заполняю Thingos, и выяснение некоторого способа препятствовать тому, чтобы пользователь выбрал обнуленный Thingo.

Есть ли способ отобразить "Выбор thingo" в ComboBox'границы с помощью чистого XAML, или чистого XAML и нескольких строк кода в классе с фоновым кодом представления?

10
задан Garth Kidd 25 May 2010 в 02:04
поделиться

4 ответа

Путь наименьшего сопротивления здесь, который я нашел, это использование Null Object Pattern Для примера использования этого паттерна в .NET Framework рассмотрим статическое значение Double.NaN Если вы создадите Null Object для вашего Thingo, в вашей модели представления вы можете добавить его к передней части списка, чтобы обозначить "ничего не выбрано". Создайте DataTemplate для класса Thingo, который имеет DataTrigger для экземпляра Null Object, который показывает "Select a Value".

Я мог бы привести пример кода, но мне уже пора спать.

3
ответ дан 3 December 2019 в 20:03
поделиться

Изменить: Похоже, идея триггера не подходит.Я добавил следующее в шаблон элемента управления тестового поля со списком, но безрезультатно:

    <Trigger Property="SelectedItem" Value="{x:Null}">
        <Setter Property="Text" Value="No Item Selected"/>
    </Trigger>

Кроме того, при попытке отредактировать шаблон элемента управления в Blend (Edit Current) у меня остается невыразительное поле со списком, без цветов, просто уродливая кнопка (но есть раскрывающийся список без полей). Попробуйте другое предложение (возможно, Майк Браун).

Оригинал:

В шаблоне управления можно использовать триггер. Вот пример использования 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, текстовый блок с надписью «Нет элементов» отображается в середине ListBox. Если есть Предметы, они отображаются.

В вашем случае измените триггер, чтобы проверить, является ли ItemSelected равным x: Null, и установите для свойства Text значение «Nothing Selected».

3
ответ дан 3 December 2019 в 20:03
поделиться

Вы не можете использовать триггер шаблона элемента управления, но вы можете настроить простой шаблон элемента для поля со списком:

<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>
4
ответ дан 3 December 2019 в 20:03
поделиться

Насколько строги ваши требования к MVVM? Можете ли вы иметь немного code-behind в представлении?

Возможно, вы могли бы разместить 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>

Затем в code-behind вставьте некоторую логику в обработчик событий:

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 в code-behind удерживает макет внешнего вида ComboBox по умолчанию от прыжков, когда текст подсказки скрыт.

8
ответ дан 3 December 2019 в 20:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: