C# 嵌套的UserControls数据上下文
摘要: 我有两个名为C# 嵌套的UserControls数据上下文,c#,wpf,C#,Wpf,摘要: 我有两个名为Zone和ZoneGroup的UserControls。其中一个控件(ZoneGroup)包括另一个控件(Zone)的两个实例。它们都在加载的事件处理程序中将根元素的DataContext设置为this 问题是在加载之前设置了内部控件(区域s)的DataContext(加载之前发生的DataContextChanged事件),这导致UI中出现一些故障。(在区域内控件的初始状态是错误的。)如果我阻止它,一切都正常(至少看起来是这样!)除了我遇到以下错误报告。(在输出窗口中) S
Zone
和ZoneGroup的UserControl
s。其中一个控件(ZoneGroup
)包括另一个控件(Zone
)的两个实例。它们都在加载的事件处理程序中将根元素的DataContext
设置为this
问题是在加载之前设置了内部控件(区域
s)的DataContext
(加载
之前发生的DataContextChanged
事件),这导致UI中出现一些故障。(在区域内
控件的初始状态是错误的。)如果我阻止它,一切都正常(至少看起来是这样!)除了我遇到以下错误报告。(在输出窗口中)
System.Windows.Data错误:40:BindingExpression路径错误:在“对象”“分区组”(名称=“”)上找不到“ZoneBrush”属性。BindingExpression:Path=ZoneBrush;DataItem='ZoneGroup'(名称='');目标元素为“brdRoot”(名称=“”);目标属性为“BorderBrush”(类型为“Brush”)
详细信息:
有一个名为Zone
的UserControl
包含如下几个数据绑定
<UserControl x:Class="MyApp.Zone"
∙∙∙>
<Border x:Name="brdRoot" BorderBrush="{Binding ZoneBrush}" BorderThickness="1">
∙∙∙
</Border>
</UserControl>
另外,还有另一个UserControl
,它有两个ContentPresenter
s,以便包含和管理两个区域
控件
<UserControl x:Class="MyApp.ZoneGroup"
∙∙∙>
<Border x:Name="brdRoot" BorderBrush="Gray" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<ContentPresenter Content="{Binding MainZone}"
Margin="{Binding MainZonePadding}"/>
<ContentPresenter Content="{Binding MemberZone}"/>
</StackPanel>
</Border>
</UserControl>
编辑► 草图:
我的应用程序工作正常,但报告了一些BindingExpression错误。这不是一个直接的答案
正如@HighCore所说,我尝试使用ItemsControl
,而不是在我的用户控件中实现两个ContentPresenter
s。为了清晰起见,我制作了一个新的简单应用程序,可以简单地描述它。因此,请考虑一些新的假设:
这里同样有两个UserControl
sMyItem
和MyItemsControl
如下所示
<UserControl x:Class="MyApp.MyItem"
∙∙∙>
<Grid x:Name="grdRoot">
<Border BorderBrush="{Binding ItemBorderBrsuh}" BorderThickness="1">
<TextBlock x:Name="txtColorIndicator"
Text="Item"
TextAlignment="Center"
Margin="5"/>
</Border>
</Grid>
</UserControl>
这是MyItemsControl
<UserControl x:Class="MyApp.MyItemsControl"
∙∙∙>
<StackPanel>
<TextBlock x:Name="txtHeader" Margin="0,0,0,5" TextAlignment="Center" Text="0 Item(s)"/>
<Border BorderBrush="Gray" BorderThickness="1" Padding="5">
<ItemsControl x:Name="itemsControl" ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:MyItem />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</StackPanel>
</UserControl>
现在,BindingExpression
s没有问题,但是一个重要的问题仍然存在。如何更换
{
grdRoot.DataContext = this;
}
及
使用真实的视图模型
屏幕截图:
编辑:我尝试实现MVVM模式,但存在一些问题。我问了第一个问题。你把它太复杂了,所有那些用户控件
和所有那些依赖属性
。看看这个使用0行C#代码(仅限XAML)的示例:
ItemsControl的样式:
<Style TargetType="ItemsControl" x:Key="ZoneItemsControlStyle">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="5">
<DockPanel>
<TextBlock HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Text="{Binding Items.Count,RelativeSource={RelativeSource TemplatedParent}, StringFormat='{}{0} Item(s)'}"
Foreground="{TemplateBinding Foreground}"
DockPanel.Dock="Top"/>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ItemsPresenter/>
</Border>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
刷子的数据模板:
<DataTemplate DataType="{x:Type Brush}">
<Border BorderBrush="{Binding}" Margin="1" BorderThickness="1" Padding="2,3,2,3">
<TextBlock Text="{Binding}" TextAlignment="Center" Foreground="Black"/>
</Border>
</DataTemplate>
</Window.Resources>
现在,它的用法是:
<Grid>
<ItemsControl VerticalAlignment="Center" HorizontalAlignment="Center"
Style="{StaticResource ZoneItemsControlStyle}">
<SolidColorBrush Color="Red"/>
<SolidColorBrush Color="Green"/>
<SolidColorBrush Color="Black"/>
<SolidColorBrush Color="Blue"/>
</ItemsControl>
</Grid>
</Window>
结果:
查看我如何使用数据模板
,以显示特定数据类型的自定义UI?(在本例中,System.Windows.Media.Brush
class)
我正在“使用画笔作为视图模型”。当然,您也可以创建自己的ViewModels,然后为每种VM类型创建特定的DataTemplate
另外,请参见如何使用TemplateBinding
MarkupExtension将ControlTemplate
中的多个属性绑定到ItemsControl
实例中的相应值
最后,了解如何将任何类型的项目添加到ItemsControl
<Grid>
<local:MyItemsControl HorizontalAlignment="Center" VerticalAlignment="Center" Padding="5" BorderBrush="Black" BorderThickness="1">
<local:MyItemsControl.Items>
<local:MyItem ItemBorderBrsuh="Green" Margin="1"/>
<local:MyItem ItemBorderBrsuh="Red" Margin="1"/>
<local:MyItem ItemBorderBrsuh="Blue" Margin="1"/>
<local:MyItem ItemBorderBrsuh="Orange" Margin="1"/>
</local:MyItemsControl.Items>
</local:MyItemsControl>
</Grid>
另外,我必须提到,为了实现可重用性,我使用了这种基于风格的方法。您可以将另一个ItemsControl
放置在应用程序的其他位置,并设置其Style=“{StaticResource ZoneItemsControlStyle}”
即可。但是如果您只计划使用一次,您可以将所有硬编码的属性放在ItemsControl.Template
ControlTemplate中。这完全是错误的。这就是它出现故障的原因,因此,您的UserControl
s不是存储数据的正确位置。改为创建一个ViewModel,您将不会遇到这些问题。@HighCore您介意解释更多吗?我应该怎么做?发布一个你需要的和你当前拥有的屏幕截图。听起来不错,除了任何给定UI元素的DataContext
应该是它相应的ViewModel,而不是它本身。然后,如果需要绑定到可视化树中的父属性,请使用RelativeSource
bindings。此外,包含多个项的容器是ItemsControl
,而不仅仅是具有某些属性的自定义usercontrol。
<Grid>
<local:MyItemsControl HorizontalAlignment="Center" VerticalAlignment="Center" Padding="5" BorderBrush="Black" BorderThickness="1">
<local:MyItemsControl.Items>
<local:MyItem ItemBorderBrsuh="Green" Margin="1"/>
<local:MyItem ItemBorderBrsuh="Red" Margin="1"/>
<local:MyItem ItemBorderBrsuh="Blue" Margin="1"/>
<local:MyItem ItemBorderBrsuh="Orange" Margin="1"/>
</local:MyItemsControl.Items>
</local:MyItemsControl>
</Grid>
{
grdRoot.DataContext = this;
}
{
this.DataContext = this;
}
<Window x:Class="MiscSamples.ItemsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ItemsControl" Height="300" Width="300">
<Window.Resources>
<Style TargetType="ItemsControl" x:Key="ZoneItemsControlStyle">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="5">
<DockPanel>
<TextBlock HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Text="{Binding Items.Count,RelativeSource={RelativeSource TemplatedParent}, StringFormat='{}{0} Item(s)'}"
Foreground="{TemplateBinding Foreground}"
DockPanel.Dock="Top"/>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ItemsPresenter/>
</Border>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate DataType="{x:Type Brush}">
<Border BorderBrush="{Binding}" Margin="1" BorderThickness="1" Padding="2,3,2,3">
<TextBlock Text="{Binding}" TextAlignment="Center" Foreground="Black"/>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl VerticalAlignment="Center" HorizontalAlignment="Center"
Style="{StaticResource ZoneItemsControlStyle}">
<SolidColorBrush Color="Red"/>
<SolidColorBrush Color="Green"/>
<SolidColorBrush Color="Black"/>
<SolidColorBrush Color="Blue"/>
</ItemsControl>
</Grid>
</Window>