2010-05-25 7 views
8

Buongiorno!Un ComboBox WPF può visualizzare testo alternativo quando la sua selezione è nulla?

Desidero che il mio WPF ComboBox visualizzi del testo alternativo quando la sua selezione con associazione ai dati è null.

Il modello vista ha le proprietà attese:

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 
    } 

    // ... 

} 

La vista è vincolante XAML al modello vista nel modo atteso:

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

Il ComboBoxItem incuneato nella parte superiore è un modo per ottenere un oggetto in più nella parte superiore. È puro al cromo: il modello di vista rimane puro e semplice. C'è solo un problema: gli utenti vogliono "Seleziona una cosa" visualizzato ogni volta che la selezione del ComboBox è nullo.

Gli utenti fanno non vogliono un oggetto selezionato per impostazione predefinita. Vogliono vedere un messaggio che dice loro di selezionare un thingo.

vorrei evitare di dover inquinare il ViewModel con una classe ThingoWrapper con un metodo ToString ritorno "Seleziona una thingo" se la sua proprietà .ActualThingo è nullo, avvolgendo ogni Thingo come Io popolo Thingos, e capire un modo per impedire all'utente di selezionare il valore annullato Thingo.

C'è un modo per visualizzare "Seleziona una cosa" entro i limiti di ComboBox utilizzando XAML puro o XAML puro e alcune righe di codice nella classe code-behind della vista?

+0

FWIW: Ho finito per attuare il ThingoWrapper, modificando il ThingoSelectionViewModel per far fronte selezione del valore nullo avvolto, e trovare il modo di selezionare automaticamente gli oggetti Whatsy e Fadoozamy quindi non ho dovuto avvolgerli, anche. –

risposta

3

Il percorso di minor resistenza qui che ho trovato è quello di utilizzare il Null Object Pattern Per un esempio di utilizzo di questo modello nel .NET Framework, si consideri il valore statico Double.NaN se si crea un oggetto nullo per il vostro Thingo, nel tuo modello di vista puoi aggiungerlo in primo piano per indicare che "nulla è selezionato". Crea un DataTemplate per la classe Thingo che ha un DataTrigger per l'istanza Null Object che mostra "Select a Value".

Potrei fornire un esempio di codice ma è passato il tempo del mio letto.

3

Modifica: Sembra che l'idea di innesco sia un no. Ho aggiunto il seguente al modello di controllo di una casella di prova combinata inutilmente:

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

Inoltre, quando si cerca di modificare il modello di controllo in Blend (Modifica corrente) io sono rimasto con una casella combinata informe, senza colori, solo un brutto pulsante (ma c'è un dropdown senza bordi). Prova qualcuno suggerimento Elses (Mike Brown forse).

originale:

è possibile utilizzare un trigger nel modello di controllo. Ecco un esempio utilizzando un ListBox da un'app a cui sto lavorando.

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

Quanto sopra ControlTemplate ha un trigger che controlla i HasItems immobile. Se False, un blocco di testo che dice "Nessun elemento" viene visualizzato nel mezzo del ListBox. Se ci sono articoli, vengono visualizzati.

Nel tuo caso modificare il trigger per verificare se ItemSelected è x: Null e impostare la proprietà Text su "Nothing Selected".

+0

L'utente chiede come avere un valore "nulla selezionato" nella casella combinata, per non avere un aspetto diverso per una casella combinata vuota. –

+0

Lo so. Possono impostare un trigger nel modello di controllo che controlla lo stato degli Elementi selezionati e, se è nullo, imposta il valore del testo della casella su "Nulla Selezionato". Speravo che l'utente potesse dedurre che dall'esempio dato. Aggiornato la mia risposta per adattarsi meglio. – CodeWarrior

+0

@ Mike Brown: ho modificato la mia risposta, quindi sarei grato se potessi remotare il downvote. – CodeWarrior

4

Non è possibile utilizzare un modello di controllo di innesco, ma è possibile impostare un modello di elemento semplice per la casella combinata:

<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. Dovrò controllare anche questo. –

8

Come rigoroso è il vostro requisito MVVM? Puoi avere un piccolo code-behind nella visualizzazione?

Forse si potrebbe contenere il ComboBox in una griglia, qualcosa di simile:

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

Poi, nel code-behind, inserire una logica in un gestore di eventi:

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 

Impostazione IsHitTestVisible="False" DependencyProperty su TextBlock consente agli eventi del mouse di passare in modo da poter fare clic sul ComboBox e impostare la visibilità su Hidden nel code-behind mantiene il layout di un aspetto di un ComboBox predefinito da saltare quando il prompt il testo è nascosto.

+1

Anche se si desidera eseguire questa operazione, non è necessario interrompere MVVM. Basta usare un convertitore per convertire la selezione in visibilità. – Ben

1

So che questo è un thread vecchio, ma ecco come lo faccio. Dopo aver recuperato la collezione Thingos, inserisco semplicemente un nuovo Thingo con un valore ID fasullo e un valore di visualizzazione di "Select a 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); 
     } 

Ora, quando il ComboBox è databound, la prima voce è "Selezionare un thingo." Quindi, quando viene selezionato un Thingo, eseguo il test dell'ID del SelectedThingo e agisco di conseguenza.

+0

Questo è in pratica il modello oggetto nullo. A volte uso una proprietà statica della classe per esporre l'oggetto Null in modo che le persone possano controllare il loro thingo contro Thingo.NotSpecified. –

+0

Figure .... Spesso mi viene chiesto se faccio o uso "tale e così" una metodologia o un processo, e penso che la risposta sia "No". Solo per scoprire che la risposta è "Sì", ma semplicemente non sapevo cosa si chiamava ufficialmente. Grazie. –

0

So che sto resuscitando un vecchio post, ma questo è stato il primo a comparire nella mia ricerca su google. In Visual Studio, è possibile scegliere di impostare la selezione predefinita su 0, anziché su -1, e avere la prima selezione come testo predefinito.

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

Un'altra opzione:

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