Associazione della visibilità di un pulsante a un valore bool in ViewModel


122

Come associo la visibilità di un pulsante a un valore bool nel mio ViewModel?

<Button Height="50" Width="50" Style="{StaticResource MyButtonStyle}"
    Command="{Binding SmallDisp}" CommandParameter="{Binding}" Cursor="Hand"
    Visibility="{Binding Path=AdvancedFormat}" />

Dai un'occhiata a CalcBinding
VivekDev

Risposte:


204

Supponendo che AdvancedFormatsia a bool, è necessario dichiarare e utilizzare a BooleanToVisibilityConverter:

<!-- In your resources section of the XAML -->
<BooleanToVisibilityConverter x:Key="BoolToVis" />

<!-- In your Button declaration -->
<Button
 Height="50" Width="50"
 Style="{StaticResource MyButtonStyle}"
 Command="{Binding SmallDisp}" CommandParameter="{Binding}" 
Cursor="Hand" Visibility="{Binding Path=AdvancedFormat, Converter={StaticResource BoolToVis}}"/>

Notare l'aggiunta Converter={StaticResource BoolToVis}.

Questo è un modello molto comune quando si lavora con MVVM. In teoria si potrebbe fare la conversione da soli sulla proprietà ViewModel (vale a dire solo fare immobiliare di tipo Visibility) anche se io preferirei non farlo, dal momento che ora si sta scherzi con la separazione degli interessi. La visibilità di un oggetto dovrebbe davvero essere all'altezza della vista.


2
@ raym0nd Certo. ViewModel restituisce solo un valore booleano, che indica una condizione. Se la tua vista interpreta quel booleano come se mostrare o meno qualcosa, dipende dalla vista. Nota che un'altra vista può ancora interpretarlo in modo diverso.
dlev

2
Sì, poiché questa è solo una classe di supporto che massaggia un valore. Il viewmodel rimarrà comunque tra il tuo modello e la tua vista.
CodeWarrior

2
Inoltre, tieni presente che MVVM è un modello di progettazione e quindi devi applicare le tue regole per la sua implementazione. Inoltre, ci saranno momenti in cui l'unico modo per eseguire qualcosa sarà al di fuori del Model, del ViewModel o della parte XAML della View. Non è un peccato mettere qualcosa nel Codebehind. È solo più in linea con il modello MVVM metterlo nel ViewModel, se possibile.
CodeWarrior

3
Personalmente, non mi dispiace mettere una proprietà di tipo Visibility nei miei ViewModels. So che è eretico da parte mia, ma per me questo dà a una Vista più flessibilità, non meno. Se una vista non vuole usarlo, non deve e se lo fa, elimina il dolore di dover giocare con convertitori o trigger di stile. Sì, questo lega un po 'il mio ViewModel a una tecnologia di presentazione (WPF vs. ASP.Net MVC, ad esempio), ma raramente ho bisogno di mescolare queste tecnologie e il refactoring se mai lo faccio non mi spaventa, molto.
Jacob Proffitt

1
BooleanToVisibilityConverter non è attualmente disponibile per le interfacce utente di Windows Phone, tuttavia questa risposta ha fornito un'implementazione stackoverflow.com/a/20344739/595473
CosworthTC

97

C'è un terzo modo che non richiede un convertitore o una modifica al modello di visualizzazione: usa uno stile:

<Style TargetType="Button">
   <Setter Property="Visibility" Value="Collapsed"/>
   <Style.Triggers>
      <DataTrigger Binding="{Binding IsVisible}" Value="True">
         <Setter Property="Visibility" Value="Visible"/>
      </DataTrigger>
   </Style.Triggers>
</Style>

Tendo a preferire questa tecnica perché la uso in molti casi in cui ciò a cui mi sto legando è associo non booleano, ad esempio la visualizzazione di un elemento solo se DataContextnon è nullo o l'implementazione di display a più stati in cui compaiono layout diversi in base al impostazione di un enum nel modello di visualizzazione.


5
In generale, mi sento come se i convertitori fossero un hack e non mi piacciono. Penso che sia una questione di mio gusto personale irritabile piuttosto che una valutazione sobria dei pro e dei contro da un punto di vista ingegneristico, ma li evito.
Robert Rossney

1
Non posso nemmeno dire di usarli spesso. Tendono ad essere un po 'schizzinosi (sic?). Dopo il tuo post, mi sono ricordato che ho usato alcuni stili / trigger in progetti precedenti ...
CodeWarrior

Ho avuto un TextBlocka cui è TextWrapping="Wrap"stato dato. Ora quella proprietà di wrapping non è impostata in esso.
amit jha

10

Conversione bidirezionale in c # da booleano a visibilità

using System;
using System.Windows;
using System.Windows.Data;

namespace FaceTheWall.converters
{
    class BooleanToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is Boolean && (bool)value)
            {
                return Visibility.Visible;
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is Visibility && (Visibility)value == Visibility.Visible)
            {
                return true;
            }
            return false;
        }
    }
}

7
Come già accennato, ce n'è uno già integrato in WPF. Non hai bisogno di crearne uno tuo.
Scarpa

4

In genere ci sono due modi per farlo, una classe convertitore o una proprietà nel Viewmodel che essenzialmente converte il valore per te.

Tendo a utilizzare l'approccio della proprietà se si tratta di una conversione una tantum. Se vuoi riutilizzarlo, usa il convertitore. Di seguito, trova un esempio del convertitore:

<ValueConversion(GetType(Boolean), GetType(Visibility))> _
Public Class BoolToVisibilityConverter
    Implements IValueConverter

    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert

        If value IsNot Nothing Then
            If value = True Then 
                Return Visibility.Visible
            Else
                Return Visibility.Collapsed
            End If
        Else
            Return Visibility.Collapsed
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Throw New NotImplementedException
    End Function
End Class

Un metodo di proprietà ViewModel controllerebbe semplicemente il valore della proprietà booleana e restituirebbe una visibilità basata su quello. Assicurati di implementare INotifyPropertyChanged e di chiamarlo sulle proprietà Boolean e Visibility per aggiornarlo correttamente.


12
WPF dispone già di un BooleanToVisibilityConverter integrato.
CodeNaked

Non l'avevo capito. Questo era in realtà qualcos'altro che ho modificato per adattarsi a questo scenario. Tanto meglio se ce n'è uno precostruito.
CodeWarrior

3

Ciò può essere ottenuto in un modo molto semplice 1. Scrivilo nella vista.

<Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="50" Height="30">
<Button.Style>
        <Style TargetType="Button">
                <Setter Property="Visibility" Value="Collapsed"/>
                        <Style.Triggers>
                                <DataTrigger Binding="{Binding IsHide}" Value="True">
                                        <Setter Property="Visibility" Value="Visible"/>
                                    </DataTrigger>
                            </Style.Triggers>
            </Style>
    </Button.Style>

  1. La seguente è la proprietà booleana che contiene il valore vero / falso. Di seguito è riportato lo snippet di codice. Nel mio esempio questa proprietà è nella classe UserNote.

    public bool _isHide = false;
    
    public bool IsHide
    {
    
    get { return _isHide; }
    
    set
        {
            _isHide = value;
                OnPropertyChanged("IsHide");
        }
    } 
  2. Questo è il modo in cui la proprietà IsHide ottiene il valore.

    userNote.IsHide = userNote.IsNoteDeleted;

2

In vista:

<Button
 Height="50" Width="50"
 Style="{StaticResource MyButtonStyle}"
 Command="{Binding SmallDisp}" CommandParameter="{Binding}" 
Cursor="Hand" Visibility="{Binding Path=AdvancedFormat}"/>

Modello in vista:

public _advancedFormat = Visibility.visible (whatever you start with)

public Visibility AdvancedFormat
{
 get{return _advancedFormat;}
 set{
   _advancedFormat = value;
   //raise property changed here
}

Avrai bisogno di un evento di modifica della proprietà

 protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
        PropertyChanged.Raise(this, e); 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
    } 

Questo è il modo in cui usano Model-view-viewmodel

Ma poiché vuoi che sia legato a un booleano, avrai bisogno di un convertitore. Un altro modo è impostare un valore booleano esterno e quando si fa clic su quel pulsante, impostare property_advancedFormat sulla visibilità desiderata.


private Visibility _advancedFormat = Visibility.visibleFunziona bene UWPgrazie.
rubStackOverflow

1

Da Windows 10 15063 in poi

A partire dalla build 15063 di Windows 10, è disponibile una nuova funzionalità chiamata "Conversione della visibilità implicita" che associa Visibility al valore bool in modo nativo: non è più necessario utilizzare un convertitore.

(vedere https://social.technet.microsoft.com/wiki/contents/articles/34846.uwp-compiled-binding-windows-10-anniversary-update.aspx#Implicit_Visibility_conversion ).

Il mio codice (che suppone che venga utilizzato MVVM e anche il modello 10):

<!-- In XAML -->
<StackPanel x:Name="Msg_StackPanel" Visibility="{x:Bind ViewModel.ShowInlineHelp}" Orientation="Horizontal" Margin="0,24,0,0">
    <TextBlock Text="Frosty the snowman was a jolly happy soul" Margin="0,0,8,0"/>
    <SymbolIcon Symbol="OutlineStar "/>
    <TextBlock Text="With a corncob pipe and a button nose" Margin="8,0,0,0"/>
</StackPanel>

<!-- in companion View-Model -->
public bool ShowInlineHelp // using T10 SettingsService
{ 
    get { return (_settings.ShowInlineHelp); }
    set { _settings.ShowInlineHelp = !value; base.RaisePropertyChanged(); }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.