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.


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.


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>

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>

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>

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>

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

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>

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

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

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.


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/


1

Tuliskan petobatmu sendiri.

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

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

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>


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.


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


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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.