我希望在其他UserControls(如页面或窗口)中将我的UserControl重用为DataTemplates,在此示例中是在ListBox中。一切都是MVVM。
我有一个名为“CardControl”的UserControl来显示一个简单的对象“Card”。卡有两个属性,“ID”和“CardImage”。控件DataContext是通过XAML设置的。如果我在VS或Blend中打开此UserControl,它会向我显示我在相应的ViewModel中定义的虚拟卡。
现在我有另一个名为“CardSetControl”的UserControl,它应该显示一组卡片。所以ViewModel有一个ObservableCollection类型的属性< Card>称为“卡片”。
以下是代码:
<ListBox x:Name="MyList" ItemsSource="{Binding CardSet.Cards}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- WORKING, but not what i want -->
<TextBlock Text="{Binding ID}" /> // would display ID of Card
<Image Source="{Binding Image}" /> // would display Image of Card
<!-- NOT WORKING, but this is how i want it to work -->
<UserControls:CardControl DataContext="{Binding "Current listbox item as DataContext of CardControl???"}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
在阅读了大量关于MVVM和DataContext / Binding的文章后,我仍然没有让它工作。整个分层的USerControls / DataContexts事情是如何以最好的方式完成的?
答案 0 :(得分:15)
在您的示例中,UserControl
的 DataContext 将是当前选定的卡片。它流入UserControl
,其子控件与任何其他UIElement
一样,都会收到其父控件的DataContext
。
这样可行:
<ListBox x:Name="MyList" ItemsSource="{Binding CardSet.Cards}">
<ListBox.ItemTemplate>
<DataTemplate>
<UserControls:CardControl />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
CardControl在哪里:
<UserControl x:Class="MySolution.CardControl"
OtherProperties="Not shown to keep this example small">
<StackPanel>
<TextBlock Text="{Binding ID}" />
<Image Source="{Binding Image}" />
</StackPanel>
</UserControl>
答案 1 :(得分:13)
对于ListBox控件,为项源中的每个项创建一个推断的ListBoxItem。将Item设置为DataContext,并将ItemTemplate设置为模板。由于DataContext继承,因此您不必显式设置它,因为它已经是DataTemplate中的Card实例。
对于这种情况,您不必在CardControl上设置DC,因为它是为您设置的。
<ListBox x:Name="MyList" ItemsSource="{Binding CardSet.Cards}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- WORKING, but not what i want -->
<TextBlock Text="{Binding ID}" /> // would display ID of Card
<Image Source="{Binding Image}" /> // would display Image of Card
<!-- NOT WORKING, but this is how i want it to work -->
<UserControls:CardControl />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
应该适合你。
答案 2 :(得分:1)
感谢您的回答,但我发现我的问题是我提到的另一个问题。如果按照你描述的方式进行操作,我可以看到我的UserControls(CardControl)被用作ListBox项目的模板,ID和图像也能正确显示。
除此之外,我总是想知道为什么可以显示ID和图像,而我无法绑定到我在ViewModel中定义的其他属性。
今天我发现了一篇关于DataContext层次结构的有趣文章。在那里,据说ListBox中的DataContext与ListBox所在的页面上的DataContext不同。我之前没有看到过,所以我认为我必须以某种方式设置DataContext,就像我在题。现在我可以绑定到所有属性。
以下是文章: http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/
答案 3 :(得分:0)
我遇到了类似的问题,并使用以下代码修复了该问题。我在这里发布,以便其他人可以从中受益。
如果可以帮助您,请不要忘记上传我的答案。
EmpUserControl.xaml文件
<UserControl x:Class="Sample.UserControls.EmpUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:uc="clr-namespace:Sample.UserControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0">First Name: </Label>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding FirstName}" />
<Label Grid.Row="1" Grid.Column="0">Last Name: </Label>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding LastName}" />
</Grid>
</UserControl>
EmpUserControl.xaml.cs
namespace Sample.UserControls
{
/// <summary>
/// Interaction logic for EmpUserControl.xaml
/// </summary>
public partial class EmpUserControl : UserControl
{
public EmpUserControl()
{
InitializeComponent();
}
}
}
MainWindow.xaml文件
<Window x:Class="Sample.MainWindow"
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:local="clr-namespace:Sample"
xmlns:uc="clr-namespace:Sample.UserControls"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="900" WindowStyle="SingleBorderWindow"
ResizeMode="NoResize">
<Grid>
<ListBox Name="LbEmp" Width="220" Height="220" >
<ListBox.ItemTemplate>
<DataTemplate>
<uc:EmpUserControl DataContext="{Binding}"></uc:EmpUserControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
MainWindow.xaml.cs文件
namespace Sample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void LoadEmpListBox(){
var empList = new List<EmpViewModel>{
new EmpViewModel { FirstName = "Rajeev", LastName = "Kumar" },
new EmpViewModel { FirstName = "Sita", LastName = "Hedge" },
new EmpViewModel { FirstName = "Deepika", LastName = "PL" }
};
LbEmp.ItemsSource = empList;
}
}
}
EmpViewModel模型
public class EmpViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}