Come invertire BooleanToVisibilityConverter?


143

Sto usando a BooleanToVisibilityConverterin WPF per associare la Visibilityproprietà di un controllo a Boolean. Funziona bene, ma vorrei che uno dei controlli si nascondesse se il booleano è true, e mostra se lo è false.


nota: dalla beta 4 - silverlight non include BooleanToVisibility - quindi dovrai implementarlo da solo
Simon_Weaver,

Aggiunto un suggerimento vocale dell'utente per invertire supportato visualstudio.uservoice.com/forums/121579-visual-studio-2015/…
Thraka

Non riesco a credere che non abbiano implementato alcuni parametri del convertitore per fare queste cose.
Kamil,

Risposte:



250

Invece di invertire, è possibile raggiungere lo stesso obiettivo utilizzando IValueConverterun'implementazione generica in grado di convertire un valore booleano in valori target configurabili per true e false. Di seguito una di queste implementazioni:

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);
    }
}

Successivamente, esegui la sottoclasse dove si Ttrova Visibility:

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

Infine, ecco come è possibile utilizzare BooleanToVisibilityConvertersopra in XAML e configurarlo per, ad esempio, Collapsedper usare true e Visiblefalse:

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

Questa inversione è utile quando si desidera associare una proprietà booleana denominata IsHiddenal contrario IsVisible.


Potrei mancare qualcosa, ma non hai solo bisogno di una proprietà negata? stackoverflow.com/questions/534575/…
OscarRyz il

9
@OscarRyz: con interfacce utente più complesse, che iniziano ad aggiungere un sacco di disordine davvero fastidioso ai modelli di vista, per non parlare di un'altra proprietà che teoricamente devi testare l'unità per mantenere la copertura del codice. Visualizza i modelli non devono avere per ottenere che vicino i dettagli di implementazione della vista, altrimenti si potrebbe anche semplicemente avere Visibilityproprietà nel modello di vista.
Aaronaught il

Questo è così semplice, ma significativamente utile. Grazie @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;
    }
}

e quindi passa un vero o falso come ConverterParameter

       <Grid.Visibility>
                <Binding Path="IsYesNoButtonSetVisible" Converter="{StaticResource booleanToVisibilityConverter}" ConverterParameter="true"/>
        </Grid.Visibility>

4
A else if (value is bool?)parte, ReSharper mi dice "L'espressione è sempre falsa". Inoltre, la if (flag)parte può essere riscritta in modo più conciso come return flag ? Visibility.Visible : Visibility.Collapsed;.
Danilo Bargen,

1
Potrei mancare qualcosa, ma non hai solo bisogno di una proprietà negata? stackoverflow.com/questions/534575/…
OscarRyz

1
var nullable = (bool?)value; flag = nullable.GetValueOrDefault();può essere reso molto più breve e semplice:flag = (bool?)value ?? false;
ANeves

45

Scrivi la tua è la soluzione migliore per ora. Ecco un esempio di un convertitore che può fare sia normale che invertito. Se hai problemi con questo, basta chiedere.

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

2
Mi chiedo solo una cosa. Il codice xaml "Binding IsRunning", dov'è il codice sorgente o il valore per l'oggetto "IsRunning"?
succede il

IsRunning è una proprietà sul mio modello di visualizzazione. Il contesto di questo codice è lungo ma il punto è che avevo bisogno di avere qualcosa nascosto quando stavo eseguendo alcuni calcoli e altre cose non nascoste. Ho creato questo convertitore per farlo in modo che non avrei dovuto avere più proprietà sul mio modello di visualizzazione.
Michael Hohlios,

2
Puoi renderlo un rimpiazzo sostitutivo per il normale BooleanToVisibilityConvertercontrollando il parametro per null:Parameter direction = Parameter.Normal; if (parameter != null) direction = (Parameter)Enum.Parse(typeof(Parameter), (string)parameter);
JCH2k

20

C'è anche il progetto WPF Converters su Codeplex. Nella loro documentazione dicono che puoi usare il loro MapConverter per convertire da enumerazione Visibilità a bool

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

1
I convertitori WPF ora includono un convertitore BooleanToVisibility che può essere invertito.
vinod,

17

Un altro modo per associare il valore booleano ViewModel (IsButtonVisible) con la proprietà di visibilità del controllo xaml. Nessuna codifica, nessuna conversione, solo stile.

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

15

O il vero modo pigro dell'uomo, basta usare quello che c'è già e capovolgerlo:

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

5

Se non ti piace scrivere un convertitore personalizzato, puoi utilizzare i trigger di dati per risolvere questo problema:

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

3

Ho appena scritto un post su questo. Ho usato un'idea simile a quella di Michael Hohlios. Solo, ho usato Proprietà invece di usare il "parametro oggetto".

A

mio avviso, la visibilità vincolante su un valore booleare in WPF L' utilizzo delle proprietà lo rende più leggibile.

<local:BoolToVisibleOrHidden x:Key="BoolToVisConverter" Collapse="True" Reverse="True" />

Solo un follow-up sul mio commento. Se si utilizza Proprietà, è necessario creare un oggetto separato se si desidera creare convertitori, uno inverso e l'altro no. Se si utilizzano parametri, è possibile utilizzare un oggetto per più elementi, ma può essere fonte di confusione se non si presta attenzione. Quindi ci sono pro e contro per entrambi.
Rhyous,

Ho trovato molto utile la realizzazione di convertitori da Booleano a Colori. Grazie
Federinik,

3

Eccone uno che ho scritto e che uso molto. Utilizza un parametro del convertitore booleano che indica se invertire il valore o meno e quindi utilizza XOR per eseguire la negazione:

[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;
    }
}

Ecco una tabella di verità XOR come riferimento:

        XOR
        x  y  XOR
        ---------
        0  0  0
        0  1  1
        1  0  1
        1  1  0

2

Stavo cercando una risposta più generale, ma non sono riuscito a trovarla. Ho scritto un convertitore che potrebbe aiutare gli altri.

Si basa sul fatto che dobbiamo distinguere sei casi diversi:

  • True 2 Visible, False 2 Hidden
  • True 2 Visible, False 2 Collaps
  • True 2 Hidden, False 2 Visible
  • Vero 2 Compresso, Falso 2 Visibile
  • True 2 Hidden, False 2 Collaps
  • True 2 Collapsed, False 2 Hidden

Ecco la mia implementazione per i primi 4 casi:

[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();
    }
}

esempio:

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

Penso che i parametri siano facili da ricordare.

Spero che aiuti qualcuno.


2

È possibile utilizzare QuickConverter .

Con QuickConverter puoi scrivere la logica del convertitore in linea con BindingExpression

Ecco un convertitore invertito BooleanToVisibility:

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

È possibile aggiungere QuickConverter tramite NuGet. Dai un'occhiata alla documentazione per l'installazione. Link: https://quickconverter.codeplex.com/


1

Scrivi la tua conversione.

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

0

Una semplice versione a senso unico che può essere utilizzata in questo modo:

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

può essere implementato in questo modo:

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();
  }
}

0

Converti tutto in tutto (bool, string, enum, ecc.):

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

Esempi XAML:

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


0

Invece di scrivere il tuo codice / reinventare, considera l'utilizzo di CalcBinding :

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 è anche abbastanza utile per numerosi altri scenari.


-2

So che è datato, ma non è necessario implementare nuovamente nulla.

Quello che ho fatto è stato quello di negare il valore sulla proprietà in questo modo:

<!-- 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); }
}

E funziona benissimo!

Mi sto perdendo qualcosa?


7
Pensi che questa sia una soluzione più semplice, e per una singola proprietà potrebbe anche essere così (non è riutilizzabile per più proprietà, devi implementarla per ognuna). Ritengo che questo sia il posto sbagliato per l'implementazione, poiché non ha nulla a che fare con il viewmodel / codeBehind e tutto con la vista.
Mike Fuchs,
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.