我正在使用ListBox
来覆盖其ItemsPanelTemplate
以使用Canvas
而不是StackPanel
。 ListBoxItems
有一个DataTemplate
,它使用转换器来定义画布上每个ListBoxItem
的外观和位置。当我将一个项添加到ListBox
绑定的集合时,我希望能够将其他UIElement
添加到画布中。我可以在ListBoxItem
转换器之外完成此操作吗?
我的资源部分是这样的:
<Style TargetType="ListBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas x:Key="cnvAwesome">
</Canvas>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ListBoxItem">
<Setter Property="Canvas.Left" Value="{Binding Path=Position.X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Position.Y}" />
</Style>
还有一个ListBox:
<ListBox x:Name="lstAwesome" ItemsSource="{Binding Source={StaticResource someCollection}}"/>
ListBox绑定的集合:
public ObservableCollection<SomeType> someCollection {get; set; }
所以,如果我有一个方法将一个项添加到ListBox lstAwesome所绑定的集合someCollection中:
private void AddItemToDataboundCollection(SomeType someItem)
{
someCollection.Add(someItem)
// I'd like to add a UIElement to the canvas that the ListBox uses to layout items here.
}
那么,我可以通过数据绑定列表框将UIElements添加到用于ItemsPanel的画布吗?以编程方式,当我将项目添加到ListBox绑定的集合时?
我非常感谢任何输入!
答案 0 :(得分:2)
我认为您在问题中已将所有内容添加到Canvas
的{{1}}。我只是使用你问题中的代码组建了一个简单的WPF测试应用程序,它只是起作用。每当我将项目添加到绑定到ListBox
的{{1}}的{{1}}时,WPF将为该对象创建ObservableCollection
,并根据{的样式{1}},ItemsSource
将在正确的位置绘制项目。
您是否无法使上述代码正常工作?如果是这种情况,你得到了什么错误,或者你没想到会出现什么错误?
编辑:再次阅读问题之后,我认为混淆是由于对WPF绑定的工作方式存在误解。将集合绑定到ListBox
的{{1}}时,您需要做的就是将项添加到该集合中(假设集合实现了ListBoxItem
,ListBoxItem
一样)。 WPF订阅该接口提供的事件,并根据对列表所做的更改创建/销毁Canvas
。
编辑2 :虽然为此使用ListBox
会更好,但是当项目添加到集合时会自动添加该行,我不是确定如何获得先前添加的项目的位置,以便该行从正确的位置开始。
可以使用的一个选项是子类ItemsSource
,并将其设置为INotifyCollectionChanged
的{{1}}。我相信它有一个函数,你可以覆盖每当添加一个控件时调用它。在该函数中,您可以获取先前添加的控件的位置(将在ObservableCollection
子类中缓存),然后直接将控件添加到ListBoxItems
的控件。这确实假设DataTemplate
中控件的位置不能改变。如果可以,您可能必须订阅对象的Canvas
事件并相应地更新行。
编辑3 :由于您的要求,绑定似乎不是一个选项,最不好的选择是直接添加子项。您可以使用VisualTreeHelper.GetChild()
搜索可视树来完成此操作ItemsPanelTemplate
像这样使用:
ListBox
此代码以递归方式搜索Canvas
的可视树,以控制指定的类型和名称。最好在Canvas
上使用Canvas
(因为这是PropertyChanged
返回的内容),但private T FindChild<T>(FrameworkElement parent, string name)
where T : FrameworkElement
{
FrameworkElement curObject = null;
T obj = default(T);
int count = VisualTreeHelper.GetChildrenCount(parent);
for(int i = 0; i < count; i++)
{
curObject = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
obj = curObject as T;
if(null != obj && obj.Name.Equals(name))
{
break;
}
obj = FindChild<T>(curObject, name);
if(null != obj)
{
break;
}
}
return obj;
}
仅在Canvas canvas = FindChild<Canvas>(lstAwesome, "cnvAwesome");
上定义。< / p>
如果你想获得幻想,你甚至可以将其作为一种扩展方法。
答案 1 :(得分:1)
您可以通过设置ItemTemplate
来指定展示商品的方式,例如:
<ListBox.ItemTemplate>
<DataTemplate>
<Rectangle Width="{Binding Width}" Height="{Binding Height}" />
</DataTemplate>
</ListBox.ItemTemplate>
如果您希望根据商品更改ItemTemplate
,则可以设置ItemTemplateSelector
并确定以编程方式使用ItemTemplate
。