Wie invertiere ich BooleanToVisibilityConverter?

143

Ich verwende ein BooleanToVisibilityConverterin WPF, um die VisibilityEigenschaft eines Steuerelements an ein zu binden Boolean. Dies funktioniert gut, aber ich möchte, dass eines der Steuerelemente ausgeblendet wird true, wenn der Boolesche Wert vorliegt , und zeigt, ob dies der Fall ist false.

Ruben Bartelink
quelle
Hinweis: Ab Beta 4 - Silverlight enthält BooleanToVisibility nicht - Sie müssen es also trotzdem selbst implementieren
Simon_Weaver
Es wurde ein Vorschlag für eine Benutzerstimme hinzugefügt, um die Unterstützung von invert
Thraka
Ich kann nicht glauben, dass sie einige Konverterparameter nicht implementiert haben, um solche Dinge zu tun.
Kamil

Antworten:

250

Anstatt zu invertieren, können Sie dasselbe Ziel erreichen, indem Sie eine generische IValueConverterImplementierung verwenden, die einen Booleschen Wert in konfigurierbare Zielwerte für true und false konvertieren kann . Unten ist eine solche Implementierung:

public class BooleanConverter<T> : IValueConverter
{
    public BooleanConverter(T trueValue, T falseValue)
    {
        True = trueValue;
        False = falseValue;
    }

    public T True { get; set; }
    public T False { get; set; }

    public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is bool && ((bool) value) ? True : False;
    }

    public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is T && EqualityComparer<T>.Default.Equals((T) value, True);
    }
}

Als nächstes unterklassifizieren Sie es, wo Tist Visibility:

public sealed class BooleanToVisibilityConverter : BooleanConverter<Visibility>
{
    public BooleanToVisibilityConverter() : 
        base(Visibility.Visible, Visibility.Collapsed) {}
}

Schließlich können Sie dies BooleanToVisibilityConverteroben in XAML verwenden und so konfigurieren, dass es beispielsweise Collapsedfür true und Visiblefür false verwendet wird:

<Application.Resources>
    <app:BooleanToVisibilityConverter 
        x:Key="BooleanToVisibilityConverter" 
        True="Collapsed" 
        False="Visible" />
</Application.Resources>

Diese Inversion ist nützlich, wenn Sie an eine Boolesche Eigenschaft mit dem Namen " IsHiddenGegenteil" binden möchten IsVisible.

Atif Aziz
quelle
Ich vermisse vielleicht etwas, aber brauchst du nicht einfach eine negierte Immobilie? stackoverflow.com/questions/534575/…
OscarRyz
9
@OscarRyz: Bei komplexeren Benutzeroberflächen wird den Ansichtsmodellen eine Menge wirklich nerviger Unordnung hinzugefügt, ganz zu schweigen von einer weiteren Eigenschaft, die Sie theoretisch einem Unit-Test unterziehen müssen, um die Codeabdeckung aufrechtzuerhalten. Ansicht Modelle sollten nicht bekommen müssen , dass die Nähe zu den Implementierungsdetails der Ansicht, sonst könnte man genausogut hat VisibilityEigenschaften Ihrer Ansicht nach Modell.
Aaronaught
Das ist so einfach, aber sehr hilfreich. Vielen Dank, dass Sie @AtifAziz.
TheLastGIS
48
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

public sealed class BooleanToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var flag = false;
        if (value is bool)
        {
            flag = (bool)value;
        }
        else if (value is bool?)
        {
            var nullable = (bool?)value;
            flag = nullable.GetValueOrDefault();
        }
        if (parameter != null)
        {
            if (bool.Parse((string)parameter))
            {
                flag = !flag;
            }
        }
        if (flag)
        {
            return Visibility.Visible;
        }
        else
        {
            return Visibility.Collapsed;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var back = ((value is Visibility) && (((Visibility)value) == Visibility.Visible));
        if (parameter != null)
        {
            if ((bool)parameter)
            {
                back = !back;
            }
        }
        return back;
    }
}

und übergeben Sie dann ein wahr oder falsch als ConverterParameter

       <Grid.Visibility>
                <Binding Path="IsYesNoButtonSetVisible" Converter="{StaticResource booleanToVisibilityConverter}" ConverterParameter="true"/>
        </Grid.Visibility>
Simon
quelle
4
In dem else if (value is bool?)Teil sagt mir ReSharper "Ausdruck ist immer falsch". Außerdem kann der if (flag)Teil präziser umgeschrieben werden als return flag ? Visibility.Visible : Visibility.Collapsed;.
Danilo Bargen
1
Ich vermisse vielleicht etwas, aber brauchst du nicht einfach eine negierte Immobilie? stackoverflow.com/questions/534575/…
OscarRyz
1
var nullable = (bool?)value; flag = nullable.GetValueOrDefault();kann viel kürzer und einfacher gemacht werden:flag = (bool?)value ?? false;
ANeves
45

Schreiben Sie Ihre eigenen ist die beste Lösung für jetzt. Hier ist ein Beispiel eines Konverters, der sowohl normal als auch invertiert arbeiten kann. Wenn Sie irgendwelche Probleme damit haben, fragen Sie einfach.

[ValueConversion(typeof(bool), typeof(Visibility))]
public class InvertableBooleanToVisibilityConverter : IValueConverter
{
    enum Parameters
    {
        Normal, Inverted
    }

    public object Convert(object value, Type targetType,
                          object parameter, CultureInfo culture)
    {
        var boolValue = (bool)value;
        var direction = (Parameters)Enum.Parse(typeof(Parameters), (string)parameter);

        if(direction == Parameters.Inverted)
            return !boolValue? Visibility.Visible : Visibility.Collapsed;

        return boolValue? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        return null;
    }
}
<UserControl.Resources>
  <Converters:InvertableBooleanToVisibilityConverter x:Key="_Converter"/>
</UserControl.Resources>

<Button Visibility="{Binding IsRunning, Converter={StaticResource _Converter}, ConverterParameter=Inverted}">Start</Button>
Michael Hohlios
quelle
2
Ich wundere mich nur über eine Sache. Der xaml-Code "Binding IsRunning", wo ist der Sourcode oder der Wert für das Objekt "IsRunning"?
What'sUP
IsRunning ist eine Eigenschaft in meinem Ansichtsmodell. Der Kontext dieses Codes ist lang, aber kurz gesagt, ich musste etwas versteckt haben, als ich einige Berechnungen durchführte, und andere Dinge, die nicht versteckt waren. Ich habe diesen Konverter erstellt, damit er nicht mehrere Eigenschaften in meinem Ansichtsmodell haben muss.
Michael Hohlios
2
Sie können es zu einem Drop-In-Ersatz für das Normale machen, BooleanToVisibilityConverterindem Sie den Parameter auf null prüfen:Parameter direction = Parameter.Normal; if (parameter != null) direction = (Parameter)Enum.Parse(typeof(Parameter), (string)parameter);
JCH2k
20

Es gibt auch das WPF Converters- Projekt auf Codeplex. In ihrer Dokumentation heißt es, dass Sie ihren MapConverter verwenden können , um von der Sichtbarkeitsaufzählung in bool zu konvertieren

<Label>
    <Label.Visible>
        <Binding Path="IsVisible">
            <Binding.Converter>
                <con:MapConverter>
                    <con:Mapping From="True" To="{x:Static Visibility.Visible}"/>
                    <con:Mapping From="False" To="{x:Static Visibility.Hidden}"/>
                </con:MapConverter>
            </Binding.Converter>
        </Binding>
    </Label.Visible>
</Label>
Cameron MacFarland
quelle
1
WPF-Konverter enthalten jetzt einen BooleanToVisibilityConverter, der umgekehrt werden kann.
Vinod
17

Eine weitere Möglichkeit, den booleschen Wert von ViewModel (IsButtonVisible) mit der Sichtbarkeitseigenschaft xaml Control zu binden. Keine Codierung, keine Konvertierung, nur Styling.

<Style TargetType={x:Type Button} x:Key="HideShow">
   <Style.Triggers>
      <DataTrigger Binding="{Binding IsButtonVisible}" Value="False">
          <Setter Property="Visibility" Value="Hidden"/>
      </DataTrigger>
   </Style.Triggers>
</Style>

<Button Style="{StaticResource HideShow}">Hello</Button>
Marat Batalandabad
quelle
15

Oder auf die Art des faulen Mannes, nutzen Sie einfach das, was bereits vorhanden ist, und drehen Sie es um:

public class InverseBooleanToVisibilityConverter : IValueConverter
{
    private BooleanToVisibilityConverter _converter = new BooleanToVisibilityConverter();

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var result = _converter.Convert(value, targetType, parameter, culture) as Visibility?;
        return result == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var result = _converter.ConvertBack(value, targetType, parameter, culture) as bool?;
        return result == true ? false : true;
    }
}
Ross Oliver
quelle
5

Wenn Sie keinen benutzerdefinierten Konverter schreiben möchten, können Sie dies mithilfe von Datenauslösern lösen:

<Style.Triggers>
        <DataTrigger Binding="{Binding YourBinaryOption}" Value="True">
                 <Setter Property="Visibility" Value="Visible" />
        </DataTrigger>
        <DataTrigger Binding="{Binding YourBinaryOption}" Value="False">
                 <Setter Property="Visibility" Value="Collapsed" />
        </DataTrigger>
</Style.Triggers>
Haim Bendanan
quelle
3

Ich habe gerade einen Beitrag dazu geschrieben. Ich habe eine ähnliche Idee verwendet wie Michael Hohlios. Nur habe ich Eigenschaften verwendet, anstatt den "Objektparameter" zu verwenden.

Das Binden der Sichtbarkeit an einen Bool-Wert in WPF

mithilfe von Eigenschaften macht ihn meiner Meinung nach besser lesbar.

<local:BoolToVisibleOrHidden x:Key="BoolToVisConverter" Collapse="True" Reverse="True" />
Rhyous
quelle
Nur eine Fortsetzung meines eigenen Kommentars. Wenn Sie Eigenschaften verwenden, müssen Sie ein separates Objekt erstellen, wenn Sie Konverter erstellen möchten, eines, das umgekehrt ist, und eines, das nicht umgekehrt ist. Wenn Sie Parameter verwenden, können Sie ein Objekt für mehrere Elemente verwenden. Es kann jedoch verwirrend sein, wenn Sie nicht darauf achten. Beide haben also Vor- und Nachteile.
Rhyous
Ich fand dies sehr hilfreich bei der Realisierung von Booleschen zu Farbkonvertern. Vielen Dank
Federinik
3

Hier ist eine, die ich geschrieben und viel benutzt habe. Es verwendet einen booleschen Konverterparameter, der angibt, ob der Wert invertiert werden soll oder nicht, und verwendet dann XOR, um die Negation durchzuführen:

[ValueConversion(typeof(bool), typeof(System.Windows.Visibility))]
public class BooleanVisibilityConverter : IValueConverter
{
    System.Windows.Visibility _visibilityWhenFalse = System.Windows.Visibility.Collapsed;

    /// <summary>
    /// Gets or sets the <see cref="System.Windows.Visibility"/> value to use when the value is false. Defaults to collapsed.
    /// </summary>
    public System.Windows.Visibility VisibilityWhenFalse
    {
        get { return _visibilityWhenFalse; }
        set { _visibilityWhenFalse = value; }
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool negateValue;
        Boolean.TryParse(parameter as string, out negateValue);

        bool val = negateValue ^ System.Convert.ToBoolean(value); //Negate the value when negateValue is true using XOR
        return val ? System.Windows.Visibility.Visible : _visibilityWhenFalse;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool negateValue;
        Boolean.TryParse(parameter as string, out negateValue);

        if ((System.Windows.Visibility)value == System.Windows.Visibility.Visible)
            return true ^ negateValue;
        else
            return false ^ negateValue;
    }
}

Hier ist eine XOR-Wahrheitstabelle als Referenz:

        XOR
        x  y  XOR
        ---------
        0  0  0
        0  1  1
        1  0  1
        1  1  0
xr280xr
quelle
2

Ich suchte nach einer allgemeineren Antwort, konnte sie aber nicht finden. Ich habe einen Konverter geschrieben, der anderen helfen könnte.

Es basiert auf der Tatsache, dass wir sechs verschiedene Fälle unterscheiden müssen:

  • Richtig 2 Sichtbar, Falsch 2 Versteckt
  • Richtig 2 Sichtbar, Falsch 2 Zusammengebrochen
  • Richtig 2 Versteckt, Falsch 2 Sichtbar
  • Richtig 2 Zusammengebrochen, Falsch 2 Sichtbar
  • Richtig 2 Versteckt, Falsch 2 Zusammengebrochen
  • True 2 Collapsed, False 2 Hidden

Hier ist meine Implementierung für die ersten 4 Fälle:

[ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleanToVisibilityConverter : IValueConverter
{
    enum Types
    {
        /// <summary>
        /// True to Visible, False to Collapsed
        /// </summary>
        t2v_f2c,
        /// <summary>
        /// True to Visible, False to Hidden
        /// </summary>
        t2v_f2h,
        /// <summary>
        /// True to Collapsed, False to Visible
        /// </summary>
        t2c_f2v,
        /// <summary>
        /// True to Hidden, False to Visible
        /// </summary>
        t2h_f2v,
    }
    public object Convert(object value, Type targetType,
                          object parameter, CultureInfo culture)
    {
        var b = (bool)value;
        string p = (string)parameter;
        var type = (Types)Enum.Parse(typeof(Types), (string)parameter);
        switch (type)
        {
            case Types.t2v_f2c:
                return b ? Visibility.Visible : Visibility.Collapsed; 
            case Types.t2v_f2h:
                return b ? Visibility.Visible : Visibility.Hidden; 
            case Types.t2c_f2v:
                return b ? Visibility.Collapsed : Visibility.Visible; 
            case Types.t2h_f2v:
                return b ? Visibility.Hidden : Visibility.Visible; 
        }
        throw new NotImplementedException();
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        var v = (Visibility)value;
        string p = (string)parameter;
        var type = (Types)Enum.Parse(typeof(Types), (string)parameter);
        switch (type)
        {
            case Types.t2v_f2c:
                if (v == Visibility.Visible)
                    return true;
                else if (v == Visibility.Collapsed)
                    return false;
                break;
            case Types.t2v_f2h:
                if (v == Visibility.Visible)
                    return true;
                else if (v == Visibility.Hidden)
                    return false;
                break;
            case Types.t2c_f2v:
                if (v == Visibility.Visible)
                    return false;
                else if (v == Visibility.Collapsed)
                    return true;
                break;
            case Types.t2h_f2v:
                if (v == Visibility.Visible)
                    return false;
                else if (v == Visibility.Hidden)
                    return true;
                break;
        }
        throw new InvalidOperationException();
    }
}

Beispiel:

Visibility="{Binding HasItems, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter='t2v_f2c'}"

Ich denke, die Parameter sind leicht zu merken.

Hoffe es hilft jemandem.

Ron
quelle
2

Sie können QuickConverter verwenden .

Mit QuickConverter können Sie die Konverterlogik inline mit Ihrer BindingExpression schreiben

Hier ist ein invertierter BooleanToVisibility-Konverter:

Visibility="{qc:Binding '!$P ? Visibility.Visible : Visibility.Collapsed', P={Binding Example}}"

Sie können QuickConverter über NuGet hinzufügen. Schauen Sie sich die Dokumentation zur Einrichtung an. Link: https://quickconverter.codeplex.com/

Felix Keil
quelle
1

Schreiben Sie Ihren eigenen Konvertiten.

public class ReverseBooleanToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
       // your converter code here
   }
}
Muad'Dib
quelle
0

Eine einfache Einwegversion, die wie folgt verwendet werden kann:

Visibility="{Binding IsHidden, Converter={x:Static Ui:Converters.BooleanToVisibility}, ConverterParameter=true}

kann wie folgt implementiert werden:

public class BooleanToVisibilityConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    var invert = false;

    if (parameter != null)
    {
      invert = Boolean.Parse(parameter.ToString());
    }

    var booleanValue = (bool) value;

    return ((booleanValue && !invert) || (!booleanValue && invert)) 
      ? Visibility.Visible : Visibility.Collapsed;
  }

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
    throw new NotImplementedException();
  }
}
Gregor Slavec
quelle
0

Konvertieren Sie alles in alles (Bool, String, Enum usw.):

public class EverythingConverterValue
{
    public object ConditionValue { get; set; }
    public object ResultValue { get; set; }
}

public class EverythingConverterList : List<EverythingConverterValue>
{

}

public class EverythingConverter : IValueConverter
{
    public EverythingConverterList Conditions { get; set; } = new EverythingConverterList();

    public object NullResultValue { get; set; }
    public object NullBackValue { get; set; }

    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        return Conditions.Where(x => x.ConditionValue.Equals(value)).Select(x => x.ResultValue).FirstOrDefault() ?? NullResultValue;
    }
    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        return Conditions.Where(x => x.ResultValue.Equals(value)).Select(x => x.ConditionValue).FirstOrDefault() ?? NullBackValue;
    }
}

XAML-Beispiele:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:conv="clr-namespace:MvvmGo.Converters;assembly=MvvmGo.WindowsWPF"
                xmlns:sys="clr-namespace:System;assembly=mscorlib">

<conv:EverythingConverter x:Key="BooleanToVisibilityConverter">
    <conv:EverythingConverter.Conditions>
        <conv:EverythingConverterValue ResultValue="{x:Static Visibility.Visible}">
            <conv:EverythingConverterValue.ConditionValue>
                <sys:Boolean>True</sys:Boolean>
            </conv:EverythingConverterValue.ConditionValue>
        </conv:EverythingConverterValue>
        <conv:EverythingConverterValue ResultValue="{x:Static Visibility.Collapsed}">
            <conv:EverythingConverterValue.ConditionValue>
                <sys:Boolean>False</sys:Boolean>
            </conv:EverythingConverterValue.ConditionValue>
        </conv:EverythingConverterValue>
    </conv:EverythingConverter.Conditions>

</conv:EverythingConverter>

<conv:EverythingConverter x:Key="InvertBooleanToVisibilityConverter">
    <conv:EverythingConverter.Conditions>
        <conv:EverythingConverterValue ResultValue="{x:Static Visibility.Visible}">
            <conv:EverythingConverterValue.ConditionValue>
                <sys:Boolean>False</sys:Boolean>
            </conv:EverythingConverterValue.ConditionValue>
        </conv:EverythingConverterValue>
        <conv:EverythingConverterValue ResultValue="{x:Static Visibility.Collapsed}">
            <conv:EverythingConverterValue.ConditionValue>
                <sys:Boolean>True</sys:Boolean>
            </conv:EverythingConverterValue.ConditionValue>
        </conv:EverythingConverterValue>
    </conv:EverythingConverter.Conditions>
</conv:EverythingConverter>

<conv:EverythingConverter x:Key="MarriedConverter" NullResultValue="Single">
    <conv:EverythingConverter.Conditions>
        <conv:EverythingConverterValue ResultValue="Married">
            <conv:EverythingConverterValue.ConditionValue>
                <sys:Boolean>True</sys:Boolean>
            </conv:EverythingConverterValue.ConditionValue>
        </conv:EverythingConverterValue>
        <conv:EverythingConverterValue ResultValue="Single">
            <conv:EverythingConverterValue.ConditionValue>
                <sys:Boolean>False</sys:Boolean>
            </conv:EverythingConverterValue.ConditionValue>
        </conv:EverythingConverterValue>
    </conv:EverythingConverter.Conditions>
    <conv:EverythingConverter.NullBackValue>
        <sys:Boolean>False</sys:Boolean>
    </conv:EverythingConverter.NullBackValue>
</conv:EverythingConverter>

Ali Yousefi
quelle
0

Anstatt Ihren eigenen Code zu schreiben / neu zu erfinden, sollten Sie CalcBinding verwenden :

Automatic two way convertion of bool expression to Visibility and back if target property has such type: description

    <Button Visibility="{c:Binding !IsChecked}" /> 
    <Button Visibility="{c:Binding IsChecked, FalseToVisibility=Hidden}" />

CalcBinding ist auch für zahlreiche andere Szenarien sehr nützlich.

UuDdLrLrSs
quelle
-2

Ich weiß, dass dies veraltet ist, aber Sie müssen nichts erneut implementieren.

Was ich getan habe, war, den Wert auf dem Grundstück wie folgt zu negieren:

<!-- XAML code -->
<StackPanel Name="x"  Visibility="{Binding    Path=Specials, ElementName=MyWindow, Converter={StaticResource BooleanToVisibilityConverter}}"></StackPanel>    
<StackPanel Name="y"  Visibility="{Binding Path=NotSpecials, ElementName=MyWindow, Converter={StaticResource BooleanToVisibilityConverter}}"></StackPanel>        

....

//Code behind
public bool Specials
{
    get { return (bool) GetValue(SpecialsProperty); }
    set
    {
        NotSpecials= !value; 
        SetValue(SpecialsProperty, value);
    }
}

public bool NotSpecials
{
    get { return (bool) GetValue(NotSpecialsProperty); }
    set { SetValue(NotSpecialsProperty, value); }
}

Und es funktioniert gut!

Vermisse ich etwas

OscarRyz
quelle
7
Sie denken, dies ist eine einfachere Lösung, und für eine einzelne Eigenschaft kann dies sogar der Fall sein (es ist nicht für mehrere Eigenschaften wiederverwendbar, Sie müssen es für jede einzelne implementieren). Ich denke, dies ist der falsche Ort für die Implementierung, da dies nichts mit dem Ansichtsmodell / CodeBehind und allem mit der Ansicht zu tun hat.
Mike Fuchs