ListBox ItemTemplate 对于 CLR 和 UserControl 数据来说是变化无常的
我为我的应用程序编写了一个简单的 UpDown UserControl。我将其呈现在 ListBox 中,以便在添加 UpDown 控件时,它们水平堆叠。
我的 UserControl 有一个 DependencyProperty,它对应于 UpDown 控件内部的数字,称为 NumberProperty。
我通过数据绑定向 ListBox 添加多个 UpDown 控件,其中 ListBox 的 ItemsSource 只是一个名为 NumberGroups
的 ObservableCollection
。每个 NumberGroup
只有一个名为 Number 的成员,我希望在呈现 ListBox 时该数字出现在其各自的 UpDown 控件中。
我的 ListBox 在 XAML 中定义如下:
<ListBox Grid.Row="1" ItemsSource="{Binding NumberGroups}" ItemTemplate="{StaticResource NumberGroupTemplate}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="Auto" Height="Auto" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
ListBox 的 DataTemplate 为:
<DataTemplate x:Key="RackTemplate">
<StackPanel Orientation="Vertical">
<TextBlock>Group</TextBlock>
<updown:UpDown Number="{Binding Number}" />
</StackPanel>
</DataTemplate>
这有点令人困惑,因为我将 UpDown UserControl 中的 DependencyProperty Number
命名为与 NumberGroup 类中的属性相同。 NumberGroup 只是:
public class NumberGroup
{
public int Number { get; set; }
}
当我运行应用程序时,我已经知道它不会工作,因为输出窗口告诉我:
System.Windows.Data Error: 39 : BindingExpression path error: 'Number' property not found on 'object' ''UpDown' (Name='')'. BindingExpression:Path=Number; DataItem='UpDown' (Name=''); target element is 'UpDown' (Name=''); target property is 'Number' (type 'Int32')
好的,所以它绑定到 UserControl 而不是 ListItem...无法写入。因此,作为测试,我从资源和列表框定义中删除了 DataTemplate 并重新运行它。在 ListBox 中,我得到了一堆 NumberGroup
,这正是我所期望的!
那么为什么当我这样做时,它似乎绑定到 ListItem,但是当我定义 ItemTemplate 时它想要绑定到 UpDown 控件呢?任何解释将非常感激。我已经阅读了 Dr. WPF 的文章,但不明白为什么会发生这种情况。
更新
好的,我找到了与我的问题相关的东西。在 UserControl 中,我将 DataContext 设置为自身,以便我可以处理处理向上和向下按钮的 ICommand。但由于某种原因我还不明白,它与 ListItem 的数据绑定混淆了!如果 UserControl 包含在 ListItem 内,为什么会发生这种情况?
I wrote a simple UpDown UserControl for my application. I am rendering it in a ListBox so that as UpDown controls get added, they stack up horizontally.
My UserControl has one DependencyProperty that corresponds to the number inside of the UpDown control, called NumberProperty.
I add multiple UpDown controls to the ListBox via databinding, where the ItemsSource for the ListBox is merely an ObservableCollection<NumberGroup>
called NumberGroups
. Each NumberGroup
just has a member called Number, and I want this number to appear in its respective UpDown control when the ListBox is rendered.
My ListBox is defined in XAML like this:
<ListBox Grid.Row="1" ItemsSource="{Binding NumberGroups}" ItemTemplate="{StaticResource NumberGroupTemplate}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="Auto" Height="Auto" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
and the DataTemplate for the ListBox is:
<DataTemplate x:Key="RackTemplate">
<StackPanel Orientation="Vertical">
<TextBlock>Group</TextBlock>
<updown:UpDown Number="{Binding Number}" />
</StackPanel>
</DataTemplate>
It's a little confusing because I named the DependencyProperty Number
in the UpDown UserControl the same as the property in the NumberGroup class. NumberGroup is merely:
public class NumberGroup
{
public int Number { get; set; }
}
When I run the application, I already know it's not going to work because the Output window tells me:
System.Windows.Data Error: 39 : BindingExpression path error: 'Number' property not found on 'object' ''UpDown' (Name='')'. BindingExpression:Path=Number; DataItem='UpDown' (Name=''); target element is 'UpDown' (Name=''); target property is 'Number' (type 'Int32')
OK, so it's binding to the UserControl instead of the ListItem... that can't be write. So as a test, I removed the DataTemplate from the Resources and ListBox definition and re-ran it. In the ListBox, I got a bunch of NumberGroup
s, which is exactly what I would expect!
So how come when I do this, it seems to bind against the ListItem, but when I define the ItemTemplate it wants to bind to the UpDown control? Any explanation would be really appreciated. I've gone over the Dr. WPF articles and don't see why this would happen.
UPDATE
Ok, I figured out something related to my problem. Within the UserControl, I am setting the DataContext to itself, so that I can process the ICommand
s that deal with the Up and Down buttons. But for some reason I don't yet understand, it messes with the databinding for the ListItem! Why would this happen if the UserControl is contained inside of the ListItem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当您在内部将 UserControl 的 DataContext 设置为自身时,您将获得与执行此操作完全相同的效果:
显然,现在您设置的任何未定义显式 Source 的绑定都将使用 UpDown 控件作为其上下文。因此,当您尝试绑定到 Number 属性时,它会在 UpDown 上查找 Number 属性,而不是 ListBoxItem 的数据。这正是您的错误所告诉您的。
为了避免这种情况,请更改 UserControl 中的 DataContext 设置以应用于控件内的元素,例如带有 x:Name 的根布局网格。
并在代码或 XAML 中设置 DataContext。
When you set the UserControl's DataContext internally to itself you're getting exactly the same effect as if you did this:
Obviously now any Bindings that you set which have no explicit Source defined will use the UpDown control as their context. So when you're trying to bind to the Number property it's looking for a Number property on UpDown instead of your ListBoxItem's data. This is exactly what your error is telling you.
To avoid this change your DataContext setting in your UserControl to apply to an element inside the control, like a root layout Grid with an x:Name.
And set DataContext either in code or XAML.