2010-05-25 11 views
8

G'day!Czy można wyświetlić tekst alternatywny WPF ComboBox, gdy jego wybór jest zerowy?

Chcę, aby mój WPF ComboBox wyświetlał jakiś tekst alternatywny, gdy jego wybór związany z danymi to null.

Widok modelu ma oczekiwanych właściwości:

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 
    } 

    // ... 

} 

się pogląd XAML wiążących Widok modelu oczekiwanym sposób:

<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 wciśnięta do górnej jest sposobem dostać dodatkowy przedmiot na górze. To czysty chrom: model widoku pozostaje czysty i prosty. Jest tylko jeden problem: użytkownicy chcą wyświetlać "Wybierz coś", gdy wybór ComboBox "jest zerowy".

Użytkownicy robią , a nie chcą, aby domyślnie wybrano element. Chcą zobaczyć komunikat z informacją, aby wybrać coś.

chciałbym uniknąć konieczności zanieczyszczają ViewModel z klasą ThingoWrapper z metodą ToString powrocie „Wybierz thingo” jeśli jego .ActualThingo właściwość ma wartość null, owijając każdą Thingo jak zapełnić Thingos, i dowiedzieć się, w pewien sposób uniemożliwić użytkownikowi wybranie wartości nulled Thingo.

Czy istnieje sposób wyświetlania "Wybierz coś" w granicach ComboBox 'przy użyciu czystego XAML lub czystego XAML i kilku linii kodu w klasie kodu z widoku?

+0

FWIW: skończyło się na wdrażaniu ThingoWrapper, modyfikując ThingoSelectionViewModel poradzić sobie z wyborem zawiniętego wartości zerowej, a znalezienie sposobów, aby automatycznie wybrać obiekty Whatsy i Fadoozamy, więc nie musiałem ich również owijać. –

Odpowiedz

3

Ścieżka najmniejszego oporu, którą tu znalazłem, to użycie Null Object Pattern Aby zobaczyć przykład użycia tego wzorca w .NET Framework, weź pod uwagę wartość statyczną Double.NaN, jeśli utworzysz obiekt Null dla Thingo, w modelu widoku możesz dodać go do początku listy, aby zaznaczyć "nic nie zostało wybrane". Utwórz DataTemplate dla klasy Thingo, która ma DataTrigger dla instancji obiektu Null, która pokazuje "Wybierz wartość".

Mogę podać próbkę kodu, ale minęło już czas mojego łóżka.

3

Edytuj: Wygląda na to, że idea wyzwalacza nie działa. I dodaje następujące do szablonu sterowania skrzyni Test kombi bezskutecznie:

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

Dodatkowo, podczas próby edytowania szablonu kontroli w Blend (Edit Current) ja zostaję z bezkształtnym combobox, ma kolorów, po prostu brzydki przycisk (ale nie ma ramki bez obramowania). Wypróbuj sugestię kogoś innego (może Mike Brown).

oryginalny:

Można użyć wyzwalacza w szablonie sterowania. Oto przykład użycia ListBox z aplikacji, nad którą pracuję.

<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> 

Powyższy ControlTemplate ma wyzwalacz, który sprawdza Hasła Hasła. Jeśli Fałsz, w środku ListBox wyświetla się blok tekstu z napisem "Brak elementów". Jeśli są przedmioty, są one wyświetlane.

W twoim przypadku zmień spust, aby sprawdzić, czy ItemSelected ma wartość x: Null, i ustaw właściwość Text na "Nic wybrana".

+0

Użytkownik pyta, jak mieć wartość "nic nie wybrano" w combobox, aby nie mieć innego wyglądu pustego combobox. –

+0

Wiem. Mogą ustawić wyzwalacz w szablonie kontrolnym, który sprawdza stan wybranych elementów, a jeśli jest on zerowy, ustaw wartość tekstu tego pola na "Nic wybrana". Miałem nadzieję, że użytkownik może to wywnioskować z podanego przykładu. Zaktualizowano moją odpowiedź, by lepiej pasować. – CodeWarrior

+0

@Mike Brown: Edytowałem swoją odpowiedź, więc byłbym wdzięczny, gdyby udało ci się zdalnie przeprowadzić test. – CodeWarrior

4

nie można użyć sterowania szablonu spust, ale można założyć prostego szablonu elementu do 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> 
+0

Hmm. Też muszę to sprawdzić. –

8

Jak ścisłe to wymóg MVVM? Czy możesz mieć trochę kodu w widoku?

Może ty zawierać ComboBox w siatce, coś takiego:

<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> 

następnie w kod z opóźnieniem, włóż trochę logiki obsługi zdarzeń:

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 

Ustawianie IsHitTestVisible="False" DependencyProperty na TextBlock umożliwia przechodzenie zdarzeń myszy, dzięki czemu można kliknąć na ComboBox, a ustawienie widoczności na Hidden w kodzie z tyłu utrzymuje układ domyślnego wyglądu ComboBox z przeskakiwania, gdy monit tekst jest ukryty.

+1

Nawet jeśli chcesz to zrobić w ten sposób, nie musisz łamać swojej MVVM. Wystarczy użyć konwertera, aby przekonwertować zaznaczenie na widoczność. – Ben

1

Wiem, że to stara nitka, ale oto jak to robię. Po pobraniu kolekcji Thingos po prostu wstawiam nowe Thingo z fałszywą wartością identyfikatora i wartością wyświetlania "Wybierz coś".

public ThingoSelectionViewModel(IProvideThingos) { 
      this.Thingos = IProvideThingos.GetThingos(); 
      Thingo newThingo = new Thingo(); 
      newThingo.ThingoID = -1; 
      newThingo.ThingoDisplayName = "Select a thingo"; 
      this.Thingos.Insert(0, newThingo); 
     } 

Teraz, gdy ComboBox jest databoundem, pierwszy element to "Wybierz coś". Następnie, po wybraniu Thingo, testuję identyfikator SelectedThingo i odpowiednio go stosuję.

+0

To w zasadzie wzór obiektu zerowego. Czasami używam statycznej właściwości klasy, aby ujawnić obiekt Null, aby ludzie mogli sprawdzić swoje rzeczy przeciwko Thingo.NotSpecified. –

+0

Dane ... Często mnie pytają, czy robię lub używam "takiej i takiej" metodologii lub procesu i myślę, że odpowiedź brzmi "Nie". Tylko po to, aby dowiedzieć się, że odpowiedź brzmi "tak", ale po prostu nie wiedziałem, jak to się nazywa. Dzięki. –

0

Wiem, że wskrzeszam stary post, ale to był pierwszy, który pojawił się w mojej wyszukiwarce Google. W Visual Studio możesz ustawić Domyślny wybór na 0, zamiast na -1 i po prostu twój pierwszy wybór będzie tekstem domyślnym.

<ComboBox x:name="ThingoSelector" SelectedIndex="0"> 
    <ComboBoxItem IsEnabled="False">Choose Thingo</ComboBoxItem> 
    <ComboBoxItem>Thingo 1</ComboBoxItem> 
</ComboBox> 
0

Inna opcja:

<ComboBox> 
 
    <ComboBoxItem Visibility="Collapsed" IsSelected="True"> 
 
    <TextBlock Text="Choose item" /> 
 
    </ComboBoxItem> 
 
    <ComboBoxItem> 
 
    <TextBlock Text="Item 1" /> 
 
    </ComboBoxItem> 
 
    <ComboBoxItem> 
 
    <TextBlock Text="Item 2" /> 
 
    </ComboBoxItem> 
 
</ComboBox>