在 WPF C# 中绑定可见性转换器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13720559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:28:52  来源:igfitidea点击:

Binding Visibility Converter in WPF C#

c#wpfxamlbindingconverter

提问by manav inder

I have a dependency property of type collection, when its callback fires based on the count I need to set the visibility of some of the controls on the screen.

我有一个类型集合的依赖属性,当它的回调基于计数触发时,我需要设置屏幕上某些控件的可见性。

But the controls remains Collapsed all the time. As per the code, one control remains visible all the time.

但是控件始终处于折叠状态。根据代码,一个控件始终保持可见。

XAML binding is

XAML 绑定是

   <TextBlock Text="106 search results for 'a'" Margin="5,0,100,0" Visibility="{Binding CountLabelVisibleReverse, Converter={StaticResource VisibilityConverter}}"/>
 <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,90,0"  
                            Visibility="{Binding CountLabelVisible, Converter={StaticResource VisibilityConverter}}">
 <TextBlock Text="Sort By"  />
 <ComboBox Style="{StaticResource ComboBoxStyle1}" Width="100" x:Name="ComboBoxSorting" ItemsSource="{Binding SortBy}" />
   </StackPanel>

My two properties are

我的两个属性是

    public bool CountLabelVisible { get; set; }

    public bool CountLabelVisibleReverse { get; set; }

Dependency property callback

依赖属性回调

   private static void ItemsCollectionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
    {
        var listingUserControl = (obj as ListingUserControl);

        var itemsResult = (eventArgs.NewValue as List<ItemsResult>);
        if (listingUserControl != null && itemsResult != null)
        {
            listingUserControl.CountLabelVisible = itemsResult.Count > 0;
            listingUserControl.CountLabelVisibleReverse =itemsResult.Count <= 0;
        }
    }

Converter code is

转换器代码是

 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (parameter == null)
            return (bool)value == false ? Visibility.Collapsed : Visibility.Visible;

        return (bool)value ? Visibility.Collapsed : Visibility.Visible;
    }

采纳答案by slugster

You have made the classic mistake of binding to auto properties that are valid for binding, but don't notify upon change, which means the binding subsystem cannot detect changes and update the binding targets.

您犯了一个典型的错误,即绑定到对绑定有效的自动属性,但在更改时不通知,这意味着绑定子系统无法检测更改并更新绑定目标。

To fix this, implement INotifyPropertyChangedon your viewmodel, and then ensure that you notify the property change from the properties.

要解决此问题,请在您的视图模型上实现INotifyPropertyChanged,然后确保从属性通知属性更改。

As an example, I have the following in the base class for my viewmodels:

例如,我的视图模型的基类中有以下内容:

public abstract class BaseViewModel : INotifyPropertyChanged
{

    /// <summary>
    /// Helper method to set the value of a property and notify if the value has changed.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="newValue">The value to set the property to.</param>
    /// <param name="currentValue">The current value of the property.</param>
    /// <param name="notify">Flag indicating whether there should be notification if the value has changed.</param>
    /// <param name="notifications">The property names to notify that have been changed.</param>
    protected bool SetProperty<T>(ref T newValue, ref T currentValue, bool notify, params string[] notifications)
    {
        if (EqualityComparer<T>.Default.Equals(newValue, currentValue))
            return false;

        currentValue = newValue;
        if (notify && notifications.Length > 0)
            foreach (string propertyName in notifications)
                OnPropertyChanged(propertyName);

        return true;
    }

    /// <summary>
    /// Raises the <see cref="E:PropertyChanged"/> event.
    /// </summary>
    /// <param name="propertyName">The name of the property that changed.</param>
    protected void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    /// <summary>
    /// Occurs when a property value changes.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

}

then in your regular viewmodel:

然后在您的常规视图模型中:

public class MyViewModel : BaseViewModel
{
    private bool _countLabelVisible;

    public bool CountLabelVisible
    {
        get { return _countLabelVisible; }
        set { SetProperty(ref value, ref _countLabelVisible, true, "CountLabelVisible", "CountLabelVisibleReverse"); }
    }

    public bool CountLabelVisibleReverse { get { return !_countLabelVisible; }} 
}

This way, when CountLabelVisiblegets changed it also notifies on the property CountLabelVisibleReverse, and the property CountLabelVisibleReverseconsists of only a getter - because it will always be the inverse of CountLabelVisible.

这样,当CountLabelVisible被更改时,它也会通知属性CountLabelVisibleReverse,并且该属性CountLabelVisibleReverse仅包含一个 getter - 因为它总是与 相反CountLabelVisible

So that fixes your code the way you have it, but the reality is you don't need to keep the CountLabelVisibleReverseproperty, instead you could:

这样就可以按照您拥有的方式修复您的代码,但实际情况是您不需要保留该CountLabelVisibleReverse属性,而是可以:

  • create an inverse visibility converter as a separate converter
  • create a multi function visibility converter by passing an optional parameter on the binding
  • stack multiple converters, where the output from one converter is piped into the input of the next converter
  • 创建一个逆可见性转换器作为单独的转换器
  • 通过在绑定上传递可选参数来创建多功能可见性转换器
  • 堆叠多个转换器,其中一个转换器的输出通过管道传输到下一个转换器的输入

回答by Pramod

Bool to visibility converter class

布尔到可见性转换器类

    public class BoolToVisibilityConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return (bool)value ? Visibility.Visible : Visibility.Hidden;
            }

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

Xaml Changes mentioned below to show use of visibility converter class. A group box is used here to show the visibility. on change of radio button selection group box will be visible/hidden.

下面提到的 Xaml 更改以显示可见性转换器类的使用。此处使用组框来显示可见性。更改单选按钮选择组框将可见/隐藏。

 <Page x:Class="WpfApplication.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:vm="clr-namespace:WpfApplication" HorizontalAlignment="Left" VerticalAlignment="Top"
            Title="Customer"  Loaded="Page_Loaded">
        <Page.Resources>
            <vm:BoolToVisibilityConverter x:Key="converter" 
    </Page.Resources>
<RadioButton Grid.Column="0" x:Name="rdbCustomerDetail"  
    Content="Show Customer" 
    IsChecked="{Binding IsCustomerDetailChecked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
            <GroupBox Header="Customer Details" Visibility="{Binding 

            Path=IsCustomerDetailChecked, 
            UpdateSourceTrigger=PropertyChanged, 
            Converter={StaticResource  converter}}">
    </GroupBox>

In ViewModel use invokepropertychange than only you will get the visibility changes on your xaml.

在 ViewModel 中,使用 invokepropertychange 不仅可以获得 xaml 的可见性更改。

private Boolean isCustomerDetailChecked = false;
    public Boolean IsCustomerDetailChecked
    {
        get
        {
            return isCustomerDetailChecked;
        }
        set
        {
            isCustomerDetailChecked = value;
            InvokePropertyChanged("IsCustomerDetailChecked");
        }
    }

回答by Maxim Zabolotskikh

Do your boolean properties that you bind to inform the view when they are changed? Sth like this:

您绑定的布尔属性是否在更改时通知视图?像这样:

private bool countLabelVisible;
public bool CountLabelVisible
{
  get
  {
    return countLabelVisible;
  }
  set
  {
   if (countLabelVisible != value)
   {
      countLabelVisible = value;
      RaisePropertyChanged(() => CountLabelVisible);
   }
}

For the method RaisePropertyChanged with lambda to be available, your viewodel should inherit from NotificationObject

要使带有 lambda 的 RaisePropertyChanged 方法可用,您的视图模型应从 NotificationObject 继承

回答by AndyC

You need to notify the change:

您需要通知更改:

public event PropertyChangedEventHandler PropertyChanged;
private bool _countLabelVisible = false;

private void RaisePropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}


public bool CountLabelVisible 
{ 
    get
    {
        return _countLabelVisible;
    }
    set
    {
        _countLabelVisible = value;
        RaisePropertyChanged("CountLabelVisible");
    }
}

The binding "framework" needs to be informed that the binding needs refreshing, which is what the Raise... is about. This is pretty quick and dirty (and untested) but should demonstrate what you need to do.

绑定“框架”需要被告知绑定需要刷新,这就是 Raise... 的内容。这非常快速和肮脏(并且未经测试),但应该证明您需要做什么。