[英]How to bind a canvas' children to a collection?
我在其中一个控件中有一个画布,随着集合的增长/缩小,我想向其中添加/删除子级。
我知道我可以这样做:
<Canvas>
<Canvas.Children>
<Rectangle/>
<TextBox/>
</Canvas.Children>
</Canvas>
但是这些元素是静态定义的。 我设想这样的事情:
<Canvas>
<Canvas.Children ItemsSource={Binding Path="ItemCollection", Converter="{StaticResource VisualConverter}}/>
</Canvas>
有没有类似于我上面的代码的东西,实际上可以工作吗? 我知道其他帖子,例如本篇和本篇,但是我看到这些答案(出于我的目的)的一个问题是,您失去了命名画布并在后面的代码中访问它的能力:这是模板中的一个元素,因此超出范围。
在显示项目集合(并支持Binding)时,您应该考虑ItemsControl
。 在这种情况下,您可以将其ItemsPanel
设置为一些包含Canvas
ItemsPanelTemplate
,如下所示:
<ItemsControl ItemsSource="{Binding ItemCollection,
Converter={StaticResource VisualConverter}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
现在, ItemsControl
就像Canvas
其中包含一些动态子级集合。
更新 :
我怀疑您使用的是错误的方法。 不确定这些方法的必要性,以便您必须创建自定义Canvas并要求在代码隐藏中轻松访问它。 使用标准的Canvas将无法为Children
属性设置某些Binding,因为它是只读的。 在这里,我为支持绑定的附加属性而不是标准的非附加Children属性介绍一个简单的实现:
public static class CanvasService
{
public static readonly DependencyProperty ChildrenProperty = DependencyProperty.RegisterAttached("Children", typeof(IEnumerable<UIElement>), typeof(CanvasService), new UIPropertyMetadata(childrenChanged));
private static Dictionary<INotifyCollectionChanged, Canvas> references = new Dictionary<INotifyCollectionChanged, Canvas>();
public static IEnumerable<UIElement> GetChildren(Canvas cv)
{
return cv.GetValue(ChildrenProperty) as IEnumerable<UIElement>;
}
public static void SetChildren(Canvas cv, IEnumerable<UIElement> children)
{
cv.SetValue(ChildrenProperty, children);
}
private static void childrenChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
var canvas = target as Canvas;
repopulateChildren(canvas);
var be = canvas.GetBindingExpression(ChildrenProperty);
if (be != null)
{
var elements = (be.ResolvedSourcePropertyName == null ? be.ResolvedSource : be.ResolvedSource.GetType().GetProperty(be.ResolvedSourcePropertyName).GetValue(be.ResolvedSource)) as INotifyCollectionChanged;
if (elements != null)
{
var cv = references.FirstOrDefault(i => i.Value == canvas);
if (!cv.Equals(default(KeyValuePair<INotifyCollectionChanged,Canvas>)))
references.Remove(cv.Key);
references[elements] = canvas;
elements.CollectionChanged -= collectionChangedHandler;
elements.CollectionChanged += collectionChangedHandler;
}
} else references.Clear();
}
private static void collectionChangedHandler(object sender, NotifyCollectionChangedEventArgs e)
{
Canvas cv;
if (references.TryGetValue(sender as INotifyCollectionChanged, out cv))
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var item in e.NewItems) cv.Children.Add(item as UIElement);
break;
case NotifyCollectionChangedAction.Remove:
foreach (var item in e.OldItems) cv.Children.Remove(item as UIElement);
break;
case NotifyCollectionChangedAction.Reset:
repopulateChildren(cv);
break;
}
}
}
private static void repopulateChildren(Canvas cv)
{
cv.Children.Clear();
var elements = GetChildren(cv);
foreach (UIElement elem in elements){
cv.Children.Add(elem);
}
}
}
在XAML中的用法 :
<Canvas local:CanvasService.Children="{Binding ItemCollection,
Converter={StaticResource VisualConverter}}"/>
同样,我认为您应该考虑另一种方法。 您应该在ItemsControl周围有一些解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.