Binden der Sichtbarkeit einer Schaltfläche an einen Bool-Wert in ViewModel


122

Wie binde ich die Sichtbarkeit einer Schaltfläche an einen Bool-Wert in meinem ViewModel?

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

Antworten:


204

Angenommen, a AdvancedFormatist bool, müssen Sie Folgendes deklarieren und verwenden 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}}"/>

Beachten Sie die hinzugefügten Converter={StaticResource BoolToVis}.

Dies ist ein sehr häufiges Muster bei der Arbeit mit MVVM. Theoretisch Sie die Konvertierung selbst auf der Ansichtsmodell Eigenschaft tun könnten (dh macht nur die Eigenschaft , selbst vom Typ Visibility) , obwohl ich das nicht tun würde es vorziehen, da jetzt Sie sind Messing mit der Trennung von Bedenken. Die Sichtbarkeit eines Gegenstands sollte wirklich der Ansicht entsprechen.


2
@ raym0nd Sicher. Das ViewModel gibt nur einen Booleschen Wert zurück, der eine Bedingung angibt. Wenn Ihre Ansicht diesen Booleschen Wert so interpretiert, dass etwas angezeigt wird oder nicht, liegt dies an der Ansicht. Beachten Sie, dass eine andere Ansicht sie immer noch anders interpretieren kann.
Dlev

2
Ja, da dies nur eine Hilfsklasse ist, die einen Wert massiert. Das Ansichtsmodell befindet sich weiterhin zwischen Ihrem Modell und Ihrer Ansicht.
CodeWarrior

2
Denken Sie auch daran, dass MVVM ein Entwurfsmuster ist und Sie daher Ihre eigenen Regeln bezüglich seiner Implementierung durchsetzen müssen. Darüber hinaus wird es Zeiten geben, in denen die einzige Möglichkeit, etwas zu erreichen, außerhalb des Modells, des ViewModel oder des XAML-Teils der Ansicht liegt. Es ist keine Sünde, etwas in den Codebehind zu setzen. Es entspricht nur mehr dem MVVM-Muster, wenn möglich, es in das ViewModel einzufügen.
CodeWarrior

3
Persönlich macht es mir nichts aus, eine Eigenschaft vom Typ Sichtbarkeit in meine ViewModels einzufügen. Ich weiß, dass das ein Ketzer von mir ist, aber für mich gibt dies einer Ansicht mehr Flexibilität, nicht weniger. Wenn eine Ansicht sie nicht verwenden möchte, muss sie nicht verwendet werden, und wenn dies der Fall ist, wird der Schmerz verringert, mit Konvertern oder Stilauslösern spielen zu müssen. Ja, diese Beziehungen meines Ansichtsmodelles zu einer Präsentationstechnik (WPF vs. ASP.Net MVC, zum Beispiel) ein bisschen, aber ich mußte selten diese Technologien mischten und Refactoring , wenn ich jemals tue mir keine Angst, viel.
Jacob Proffitt

1
BooleanToVisibilityConverter ist derzeit nicht für Windows Phone-Benutzeroberflächen verfügbar. Diese Antwort lieferte jedoch eine Implementierung stackoverflow.com/a/20344739/595473
CosworthTC

97

Es gibt einen dritten Weg, der keinen Konverter oder eine Änderung Ihres Ansichtsmodells erfordert: Verwenden Sie einen Stil:

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

Ich bevorzuge diese Technik, weil ich sie in vielen Fällen verwende, in denen das, woran ich bin, nicht boolesch ist - z. B. das Anzeigen eines Elements nur, wenn DataContextes nicht null ist, oder das Implementieren von Mehrzustandsanzeigen, bei denen unterschiedliche Layouts basierend auf dem angezeigt werden Einstellung einer Aufzählung im Ansichtsmodell.


5
Im Allgemeinen denke ich, dass Konverter ein Hack sind und ich sie nicht mag. Ich denke, dies ist eher eine Frage meines verrückten persönlichen Geschmacks als eine nüchterne Einschätzung der Vor- und Nachteile unter technischen Gesichtspunkten, aber ich vermeide sie.
Robert Rossney

1
Ich kann nicht sagen, dass ich sie auch so oft benutze. Sie neigen dazu, etwas pingelig zu sein (sic?). Nach Ihrem Beitrag erinnerte ich mich, dass ich in früheren Projekten einige Stile / Trigger verwendet habe ...
CodeWarrior

Ich hatte eine TextBlock, der TextWrapping="Wrap"gegeben wurde. Jetzt ist diese Wrapping-Eigenschaft nicht mehr festgelegt.
Amit Jha

10

2-Wege-Konvertierung in c # von Boolesch in Sichtbarkeit

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
Wie bereits erwähnt, ist bereits eine in WPF integriert. Sie müssen nicht Ihre eigenen machen.
Schuh

4

Im Allgemeinen gibt es zwei Möglichkeiten: eine Konverterklasse oder eine Eigenschaft im Ansichtsmodell, die den Wert im Wesentlichen für Sie konvertiert.

Ich tendiere dazu, den Immobilienansatz zu verwenden, wenn es sich um eine einmalige Konvertierung handelt. Wenn Sie es wiederverwenden möchten, verwenden Sie den Konverter. Unten finden Sie ein Beispiel für den Konverter:

<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

Eine ViewModel-Eigenschaftsmethode überprüft lediglich den booleschen Eigenschaftswert und gibt eine darauf basierende Sichtbarkeit zurück. Stellen Sie sicher, dass Sie INotifyPropertyChanged implementieren, und rufen Sie es in den Eigenschaften Boolean und Visibility auf, um es ordnungsgemäß zu aktualisieren.


12
WPF hat bereits einen BooleanToVisibilityConverter eingebaut.
CodeNaked

Das hatte ich nicht bemerkt. Dieser war eigentlich etwas anderes, das ich bearbeitet habe, um diesem Szenario zu entsprechen. Umso besser, wenn es einen vorgefertigten gibt.
CodeWarrior

3

Dies kann auf sehr einfache Weise erreicht werden. 1. Schreiben Sie dies in die Ansicht.

<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. Das Folgende ist die Boolesche Eigenschaft, die den Wert true / false enthält. Das Folgende ist das Code-Snippet. In meinem Beispiel befindet sich diese Eigenschaft in der UserNote-Klasse.

    public bool _isHide = false;
    
    public bool IsHide
    {
    
    get { return _isHide; }
    
    set
        {
            _isHide = value;
                OnPropertyChanged("IsHide");
        }
    } 
  2. Auf diese Weise erhält die IsHide- Eigenschaft den Wert.

    userNote.IsHide = userNote.IsNoteDeleted;

2

Im Hinblick auf:

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

In Ansicht Modell:

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

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

Sie müssen ein Ereignis mit geänderter Eigenschaft haben

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

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

So verwenden sie Model-View-View-Modell

Da Sie jedoch möchten, dass es an einen Booleschen Wert gebunden ist, benötigen Sie einen Konverter. Eine andere Möglichkeit besteht darin, einen Booleschen Wert außerhalb festzulegen. Wenn Sie auf diese Schaltfläche klicken, setzen Sie die Eigenschaft_advancedFormat auf die gewünschte Sichtbarkeit.


private Visibility _advancedFormat = Visibility.visibleDas funktioniert gut, UWPdanke.
rubStackOverflow

1

Seit Windows 10 15063 aufwärts

Seit Windows 10 Build 15063 gibt es eine neue Funktion namens "Implizite Sichtbarkeitskonvertierung", die die Sichtbarkeit nativ an den Bool-Wert bindet. Es ist kein Konverter mehr erforderlich.

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

Mein Code (der voraussetzt, dass MVVM verwendet wird, und auch Vorlage 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(); }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.