WPF:绑定到的ObservableCollection在控件模板没有更新
-
27-09-2019 - |
题
我创建了一个ControlTemplate
用于我的自定义控制MyControl
。
这MyControl
System.Windows.Controls.Control
导出并定义了以下属性public ObservableCollection<MyControl> Children{ get; protected set; }
。
要显示我使用其由ItemsControl
包围的StackPanel
(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一>),但我仍然觉得很难做到的。
我很高兴的任何帮助或建议。
解决方案
问题是,你的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>
其他提示
您需要通知每当您的孩子们的属性更改项目的数量。你可以做到这一点通过实现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));
}
}
}