【问题标题】:Binding Visibility Converter in WPF C#在 WPF C# 中绑定可见性转换器
【发布时间】:2012-11-23 02:54:19
【问题描述】:

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

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

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>

我的两个属性是

    public bool CountLabelVisible { get; set; }

    public bool CountLabelVisibleReverse { get; set; }

依赖属性回调

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

转换器代码是

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

【问题讨论】:

  • 你的班级是否实现了 INotifyPropertyChanged?
  • @Harry 这是我的用户控件,我在某处读到从 INOtifyPropertyChanged 实现用户控件不是正确的做法。如果是,请提出建议。
  • @MSingh 这是不正确的 - INotifyPropertyChanged 是一个简单的接口 - 仅此而已 - 应该由任何想要通知属性已更改的东西来实现 - 这意味着用户控件、数据对象等。你没有去实现它,但它确实有帮助。

标签: c# wpf xaml binding converter


【解决方案1】:

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

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

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

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;

}

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

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

这样,当CountLabelVisible 发生更改时,它也会通知CountLabelVisibleReverse 属性,而CountLabelVisibleReverse 属性仅包含一个getter - 因为它始终是CountLabelVisible 的倒数。

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

  • 创建一个反向可见性转换器作为单独的转换器
  • 通过在绑定上传递可选参数来创建多功能可见性转换器
  • 堆叠多个转换器,其中一个转换器的输出通过管道传输到下一个转换器的输入

【讨论】:

  • 我喜欢“经典错误”这个词。这将帮助我记住这个错误和解决方案。十分感谢。一个赞成票
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    您需要通知更改:

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

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

    【讨论】:

      【解决方案4】:

      布尔到可见性转换器类

          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 更改以显示可见性转换器类的使用。 此处使用组框来显示可见性。 更改单选按钮选择组框将可见/隐藏。

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

      在 ViewModel 中使用 invokepropertychange 不仅仅是您将在您的 xaml 上获得可见性更改。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-26
        • 1970-01-01
        • 2017-11-09
        • 1970-01-01
        • 1970-01-01
        • 2014-03-31
        • 2012-05-01
        相关资源
        最近更新 更多