Bagaimana cara membalikkan BooleanToVisibilityConverter?

143

Saya menggunakan BooleanToVisibilityConverterWPF untuk mengikat Visibilityproperti dari kontrol ke Boolean. Ini bekerja dengan baik, tapi aku ingin salah satu kontrol untuk menyembunyikan jika boolean adalah true, dan menunjukkan jika itu false.

Ruben Bartelink
sumber
catatan: pada beta 4 - silverlight tidak termasuk BooleanToVisibility - jadi Anda harus menerapkannya sendiri
Simon_Weaver
Menambahkan saran suara pengguna untuk mendapatkan invert yang didukung visualstudio.uservoice.com/forums/121579-visual-studio-2015/…
Thraka
Saya tidak percaya mereka tidak menerapkan beberapa parameter konverter untuk melakukan hal-hal seperti itu.
Kamil

Jawaban:

250

Alih-alih membalikkan, Anda dapat mencapai tujuan yang sama dengan menggunakan IValueConverterimplementasi generik yang dapat mengonversi nilai Boolean ke nilai target yang dapat dikonfigurasi untuk true dan false. Di bawah ini adalah salah satu implementasinya:

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

Berikutnya, subclass itu di mana Tadalah Visibility:

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

Akhirnya, ini adalah bagaimana Anda bisa menggunakan BooleanToVisibilityConverterXAML di atas dan mengkonfigurasinya untuk, misalnya, gunakan Collapseduntuk true dan Visiblefalse:

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

Pembalikan ini berguna ketika Anda ingin mengikat ke properti Boolean dengan nama yang IsHiddenditentang IsVisible.

Atif Aziz
sumber
Saya mungkin kehilangan sesuatu, tetapi bukankah Anda hanya perlu properti yang dinegasikan? stackoverflow.com/questions/534575/…
OscarRyz
9
@OscarRyz: Dengan UI yang lebih kompleks, yang mulai menambah banyak kekacauan yang sangat menjengkelkan pada model tampilan, belum lagi properti lain yang secara teoritis harus Anda uji unit untuk mempertahankan cakupan kode. Lihat model tidak harus mendapatkan yang dekat dengan rincian pelaksanaan pandangan, jika tidak, anda mungkin juga hanya memiliki Visibilityproperti di model tampilan Anda.
Aaronaught
Ini sangat sederhana, tetapi sangat membantu. @AtifAziz terima kasih.
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;
    }
}

dan kemudian berikan benar atau salah sebagai ConverterParameter

       <Grid.Visibility>
                <Binding Path="IsYesNoButtonSetVisible" Converter="{StaticResource booleanToVisibilityConverter}" ConverterParameter="true"/>
        </Grid.Visibility>
Simon
sumber
4
Pada else if (value is bool?)bagian itu, ReSharper memberi tahu saya "Ekspresi selalu salah". Juga, if (flag)bagian itu dapat ditulis ulang dengan lebih ringkas return flag ? Visibility.Visible : Visibility.Collapsed;.
Danilo Bargen
1
Saya mungkin kehilangan sesuatu, tetapi bukankah Anda hanya perlu properti yang dinegasikan? stackoverflow.com/questions/534575/…
OscarRyz
1
var nullable = (bool?)value; flag = nullable.GetValueOrDefault();dapat dibuat lebih pendek dan sederhana:flag = (bool?)value ?? false;
ANeves
45

Menulis sendiri adalah solusi terbaik untuk saat ini. Berikut adalah contoh Konverter yang dapat melakukan kedua cara Normal dan Terbalik. Jika Anda memiliki masalah dengan ini tanyakan saja.

[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
sumber
2
Hanya ingin tahu satu hal. Kode xaml "Binding IsRunning", di mana kode sumber atau nilai untuk objek "IsRunning"?
What'sUP
IsRunning adalah properti di viewmodel saya. Konteks kode ini panjang tetapi singkatnya adalah saya perlu menyembunyikan sesuatu ketika saya menjalankan beberapa perhitungan dan hal-hal lain tidak disembunyikan. Saya membuat konverter ini untuk membuatnya jadi saya tidak perlu memiliki beberapa properti di viewmodel saya.
Michael Hohlios
2
Anda dapat menjadikannya pengganti drop-in untuk normal BooleanToVisibilityConverterdengan memeriksa parameter untuk null:Parameter direction = Parameter.Normal; if (parameter != null) direction = (Parameter)Enum.Parse(typeof(Parameter), (string)parameter);
JCH2k
20

Ada juga proyek WPF Converters di Codeplex. Dalam dokumentasi mereka, mereka mengatakan Anda dapat menggunakan MapConverter mereka untuk mengkonversi dari pencacahan Visibilitas ke 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>
Cameron MacFarland
sumber
1
WPF Converters sekarang termasuk BooleanToVisibilityConverter yang dapat dibalik.
vinod
17

Satu lagi cara untuk Mengikat ViewModel Nilai Boolean (IsButtonVisible) dengan Properti Visibilitas Kontrol xaml. Tanpa kode, Tanpa konversi, hanya gaya.

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

Atau cara pria malas sejati, cukup gunakan apa yang sudah ada dan balikkan:

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

Jika Anda tidak suka menulis konverter khusus, Anda dapat menggunakan pemicu data untuk menyelesaikan ini:

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

Saya hanya melakukan posting tentang ini. Saya menggunakan ide yang sama seperti Michael Hohlios. Hanya saja, saya menggunakan Properties alih-alih menggunakan "parameter objek".

Mengikat Visibilitas ke nilai bool di WPF

Menggunakan Properties membuatnya lebih mudah dibaca, menurut pendapat saya.

<local:BoolToVisibleOrHidden x:Key="BoolToVisConverter" Collapse="True" Reverse="True" />
Rhyous
sumber
Hanya tindak lanjut atas komentar saya sendiri. Jika Anda menggunakan Properties, Anda harus membuat objek yang terpisah jika Anda ingin membuat ke konverter, yang Reverse dan yang tidak. Jika Anda menggunakan parameter, Anda bisa menggunakan satu objek untuk banyak item, tetapi bisa membingungkan jika Anda tidak memperhatikan. Jadi ada pro dan kontra untuk keduanya.
Rhyous
Saya menemukan ini sangat membantu dalam mewujudkan konverter Boolean ke Warna. Terima kasih
Federinik
3

Inilah yang saya tulis dan gunakan banyak. Ia menggunakan parameter konverter boolean yang menunjukkan apakah akan membalikkan nilai dan kemudian menggunakan XOR untuk melakukan negasi:

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

Inilah tabel kebenaran XOR untuk referensi:

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

Saya mencari jawaban yang lebih umum, tetapi tidak dapat menemukannya. Saya menulis konverter yang dapat membantu orang lain.

Ini didasarkan pada kenyataan bahwa kita perlu membedakan enam kasus yang berbeda:

  • Benar 2 Terlihat, Salah 2 Tersembunyi
  • Benar 2 Terlihat, Salah 2 Runtuh
  • Benar 2 Tersembunyi, Salah 2 Terlihat
  • Benar 2 Runtuh, Salah 2 Terlihat
  • True 2 Hidden, False 2 Runtuh
  • True 2 Collapsed, False 2 Hidden

Inilah implementasi saya untuk 4 kasus pertama:

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

contoh:

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

Saya pikir parameternya mudah diingat.

Semoga ini bisa membantu seseorang.

Ron
sumber
2

Anda dapat menggunakan QuickConverter .

Dengan QuickConverter Anda dapat menulis logika konverter sejajar dengan BindingExpression Anda

Berikut ini adalah konverter BooleanToVisibility terbalik:

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

Anda dapat menambahkan QuickConverter melalui NuGet. Lihatlah dokumentasi untuk pengaturan. Tautan: https://quickconverter.codeplex.com/

Felix Keil
sumber
1

Tuliskan petobatmu sendiri.

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

Versi satu arah sederhana yang dapat digunakan seperti ini:

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

dapat diimplementasikan seperti ini:

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

Konversikan semuanya menjadi semuanya (bool, string, enum, dll):

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

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

Ali Yousefi
sumber
0

Daripada menulis kode Anda sendiri / menciptakan kembali, pertimbangkan untuk menggunakan 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 juga cukup berguna untuk banyak skenario lainnya.

UuDdLrLrSs
sumber
-2

Saya tahu ini tanggal, tetapi, Anda tidak perlu mengimplementasikan kembali apa pun.

Apa yang saya lakukan adalah meniadakan nilai pada properti seperti ini:

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

Dan itu bekerja dengan baik!

Apakah saya melewatkan sesuatu?

OscarRyz
sumber
7
Anda pikir ini adalah solusi yang lebih mudah, dan untuk satu properti bahkan ini mungkin terjadi (itu tidak dapat digunakan kembali untuk beberapa properti, Anda harus menerapkannya untuk setiap properti). Saya merasa ini adalah tempat yang salah untuk implementasi, karena tidak ada hubungannya dengan viewmodel / codeBehind dan semuanya dengan view.
Mike Fuchs