Silverlight ListBox 中的 ItemsSource 绑定问题
我正在尝试在 Silverlight 列表框中列出一些字符串。我将普通 List
绑定到 ItemsSource
,然后指定要在 DisplayMemberPath
中显示的列表项的属性。我的实现有一些特定的内容,导致 ListBox 显示模板化项目而不是这些项目内指定的属性。
这是场景。我有一个派生自 UserControl
的父类,它添加了“标题”依赖属性。我创建了一些从 Parent 派生的 Child 控件,并指定继承的 Title 属性。由于某种原因,绑定到 ListBox 中的 Title 属性会导致意外行为。代码如下:
public class Parent : UserControl
{
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(Parent), new PropertyMetadata(String.Empty));
}
Child XAML 代码(Child1 和 Child2 基本上是相同的 XAML,但有一些简单的代码隐藏)
<v:Parent x:Class="TemplateBindingTest.Child1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:v="clr-namespace:TemplateBindingTest"
mc:Ignorable="d" Title="Baby 1" Height="41" Width="94">
<Grid x:Name="LayoutRoot" Background="#FFFFBBBB">
<TextBlock HorizontalAlignment="Center" Text="I da baby" VerticalAlignment="Center" FontSize="14" />
</Grid>
“ViewModel”
public class TheViewModel : INotifyPropertyChanged
{
public List<Parent> Babies { get; set; }
public TheViewModel()
{
Babies = new List<Parent>();
Child1 baby1 = new Child1();
Child2 baby2 = new Child2();
Babies.Add(baby1);
Babies.Add(baby2);
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MainPage.xaml
<UserControl x:Class="TemplateBindingTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" xmlns:my="clr-namespace:TemplateBindingTest" Height="268" Width="355">
<Grid x:Name="LayoutRoot" Background="White">
<ListBox ItemsSource="{Binding Path=Babies}" DisplayMemberPath="Title" Height="219" HorizontalAlignment="Left" Margin="12,12,0,0" VerticalAlignment="Top" Width="180" />
<my:Child1 HorizontalAlignment="Left" Margin="203,26,0,0" x:Name="child1" VerticalAlignment="Top" />
<my:Child2 HorizontalAlignment="Left" Margin="203,92,0,0" x:Name="child2" VerticalAlignment="Top" />
</Grid>
因此,忽略在“viewmodel”类中维护 UI 控件列表有点奇怪的事实,这都是相当简单的 Silverlight。在 MainPage 上的 ListBox 控件中,我希望看到每个子控件的标题。相反,子控件本身显示在列表框中。我在这里缺少什么?我觉得很奇怪的是,Silverlight 只是决定渲染子控件,而在调试输出或其他错误消息中没有任何抱怨。就像 DisplayMemberPath
属性被完全忽略一样。这可能是 Silverlight 中的一个错误吗?
为了便于测试,这里是 指向包含上述代码的完整 Visual Studio 项目的链接。
I'm trying to list some strings in a Silverlight ListBox. I'm binding a vanilla List
to the ItemsSource
and then specifying the property of the List item to display in DisplayMemberPath
. There is something specific to my implementation that causes the ListBox to display the templated items instead of the property specified inside those items.
Here's the scenario. I have a Parent class that derives from UserControl
that adds a "Title" Dependency Property. I create a few Child controls that derive from Parent and specify that inherited Title property. For some reason, binding to that Title property in the ListBox causes the unexpected behavior. Here's the code:
public class Parent : UserControl
{
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(Parent), new PropertyMetadata(String.Empty));
}
The Child XAML code (Child1 and Child2 are basically the same XAML with trivial codebehinds)
<v:Parent x:Class="TemplateBindingTest.Child1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:v="clr-namespace:TemplateBindingTest"
mc:Ignorable="d" Title="Baby 1" Height="41" Width="94">
<Grid x:Name="LayoutRoot" Background="#FFFFBBBB">
<TextBlock HorizontalAlignment="Center" Text="I da baby" VerticalAlignment="Center" FontSize="14" />
</Grid>
The "ViewModel"
public class TheViewModel : INotifyPropertyChanged
{
public List<Parent> Babies { get; set; }
public TheViewModel()
{
Babies = new List<Parent>();
Child1 baby1 = new Child1();
Child2 baby2 = new Child2();
Babies.Add(baby1);
Babies.Add(baby2);
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MainPage.xaml
<UserControl x:Class="TemplateBindingTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" xmlns:my="clr-namespace:TemplateBindingTest" Height="268" Width="355">
<Grid x:Name="LayoutRoot" Background="White">
<ListBox ItemsSource="{Binding Path=Babies}" DisplayMemberPath="Title" Height="219" HorizontalAlignment="Left" Margin="12,12,0,0" VerticalAlignment="Top" Width="180" />
<my:Child1 HorizontalAlignment="Left" Margin="203,26,0,0" x:Name="child1" VerticalAlignment="Top" />
<my:Child2 HorizontalAlignment="Left" Margin="203,92,0,0" x:Name="child2" VerticalAlignment="Top" />
</Grid>
So ignoring the fact that it's a bit weird to maintain a list of UI controls in a "viewmodel" class, this is all fairly simple Silverlight. In the ListBox control on MainPage I would expect to see the title for each Child control. Instead, the Child controls themselves show up in the ListBox. What am I missing here? I find it very odd that Silverlight just decides to render the Children controls with no complaints in the Debug Output or other error messages. It's like the DisplayMemberPath
attribute gets completely ignored. Could this be a bug in Silverlight?
For ease of testing, here's a link to the full Visual Studio project containing the code above.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这种行为似乎是设计使然。如果列表框发现内容是
UIElement
的派生类,那么它会做出简单(而且我认为合理)的假设,即您打算显示该内容。你是对的,你所做的事情“有点奇怪”,你正在付出代价。这个答案可能会为您提供解决方案。不过,我建议您检查在视图模型中保存
UserControl
实例的选择。This behaviour seems to be by design. If the listbox sees that the Content is a derivative of a
UIElement
then it makes the simple (and I think reasonable) assumption that you intend for that content to be displayed.You are right what you are doing is "a bit weird" and you are paying the price. This answer may hold a solution for you. However I would recommend you review the choice to hold an instance of a
UserControl
in the viewmodel.@AnthonyWJones 是正确的,他提供的链接导致对于这个答案:我需要实现我自己的 ListBox 破解版本,才能实现我的问题中提到的所需功能。
我想这个故事的寓意是不要尝试直接在 ViewModel 类中处理 UI 元素。出于某种原因,这不是最佳实践(并且绝对不是 MVVM)。
@AnthonyWJones is correct and the link he provided led to this answer: I would need to implement my own hacked up version of ListBox in order to achieve the desired functionality mentioned in my question.
I guess the moral of this story is don't try to deal with UI elements directly in your ViewModel classes. It's not best practice (and definitely not MVVM) for a reason.