-->

WPF:绑定到的ObservableCollection在控件模板没有更新(WPF: Binding

2019-09-27 16:53发布

我创建了一个ControlTemplate为我的自定义控件MyControl

MyControl从派生System.Windows.Controls.Control和定义了以下属性public ObservableCollection<MyControl> Children{ get; protected set; } public ObservableCollection<MyControl> Children{ get; protected set; } public ObservableCollection<MyControl> Children{ get; protected set; }

要显示我使用的嵌套子控件ItemsControlStackPanel其由包围) GroupBox 。 如果没有子控件,我想隐藏的GroupBox

一切正常,在应用程序启动罚款:该组框和子控件显示,如果儿童属性最初包含至少一个元素。 在其他情况下,它是隐藏的。

当用户添加一个子控件为空集的问题开始。 该GroupBox的知名度还是崩溃了。 当最后一个子控件从集合中删除出现同样的问题。 该GroupBox仍是可见的。 另一个症状是HideEmptyEnumerationConverter转换器不会被调用。 添加/删除子控件非空的集合按预期工作。

哪些错误下面的结合? 显然,它的工作一次,但没有得到更新,虽然我绑定到集合的类型为ObservableCollection

<!-- Converter for hiding empty enumerations -->
<Common:HideEmptyEnumerationConverter x:Key="hideEmptyEnumerationConverter"/>
<!--- ... --->

<ControlTemplate TargetType="{x:Type MyControl}">
  <!-- ... other stuff that works ... -->
  <!-- Child components -->
  <GroupBox Header="Children"
            Visibility="{Binding RelativeSource={RelativeSource TemplatedParent},
              Path=Children, Converter={StaticResource hideEmptyEnumerationConverter}}">
    <ItemsControl ItemsSource="{TemplateBinding Children}"/>
  </GroupBox>
</ControlTemplate>

[ValueConversion(typeof (IEnumerable), typeof (Visibility))]
public class HideEmptyEnumerationConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int itemCount = ((IEnumerable) value).Cast<object>().Count();
        return itemCount == 0 ? Visibility.Collapsed : Visibility.Visible;
    }

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

    #endregion
}

另外,更普遍的问题:你们如何调试的绑定? 发现这个( http://bea.stollnitz.com/blog/?p=52 ),但我仍然觉得很难做到。

我很高兴的任何帮助或建议。

Answer 1:

问题是,你的Children财产本身不会改变,只是它的内容。 由于属性值不改变,结合不重新评估。 你需要做的是绑定到该Count集合的性质。 你可以做到这一点,最简单的方法是使用一个DataTrigger在您的模板:

<ControlTemplate TargetType="{x:Type MyControl}">
  <!-- ... other stuff that works ... -->
  <!-- Child components -->
  <GroupBox x:Name="gb" Header="Children">
    <ItemsControl ItemsSource="{TemplateBinding Children}"/>
  </GroupBox>
  <ControlTemplate.Triggers>
      <DataTrigger Binding="{Binding Path=Children.Count, RelativeSource={RelativeSource TemplatedParent}}"
                   Value="0">
        <Setter TargetName="gb" Property="Visibility" Value="Collapsed" />
      </DataTrigger>
  </ControlTemplate.Triggers>
</ControlTemplate>


Answer 2:

您需要通知每当您的孩子们的属性更改项目的数量。 你可以做到这一点通过实现INotifyPropertyChanged接口,注册儿童收集的CollectionChanged事件,并从那里筹集的PropertyChanged。

例:

public class MyControl : Control, INotifyPropertyChanged
{
    static MyControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
    }

    public ObservableCollection<UIElement> Children
    {
        get { return (ObservableCollection<UIElement>)GetValue(ChildrenProperty); }
        set { SetValue(ChildrenProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Children.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ChildrenProperty =
        DependencyProperty.Register("Children", typeof(ObservableCollection<UIElement>), typeof(MyControl), new UIPropertyMetadata(0));

    public MyControl()
    {
        Children = new ObservableCollection<UIElement>();
        Children.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Children_CollectionChanged);
    }

    void Children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        RaisePropertyChanged("Children");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


文章来源: WPF: Binding to ObservableCollection in ControlTemplate is not updated