我正在尝试制作一个自定义用户控件(
TSFloorPlanProductDispenserStockViewer
)来显示错误代码和供用户交互的按钮列表。在 DataTemplate (TSFloorPlanInputStationProductDispenserMemberTemplate
) 中,我希望使用此自定义 UserControl 的两个“实例”,但我弄乱了 DataContext,但我不确定如何正确设置它。
TSFloorPlanProductDispenserStockViewer.xaml
:
<UserControl x:Class="ASC_Control_HMI.TSFloorPlanProductDispenserStockViewer"
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:local="clr-namespace:ASC_Control_HMI"
mc:Ignorable="d"
Name="ucProductDispenserStockViewer"
>
<Grid>
<DockPanel>
<Border DockPanel.Dock="Top" Background="LightYellow">
<TextBlock x:Name="tbProductDispenserStockID" FontSize="20" HorizontalAlignment="Center"/>
</Border>
<Border x:Name="brdChangeButtons" Background="LightSalmon" DockPanel.Dock="Bottom" Margin="4,0,4,0" Height="60" BorderBrush="White" CornerRadius="4" BorderThickness="1">
<local:TSRemoteManualControlBar x:Name="DispenserStockManualControlBar" HorizontalAlignment="Center" ManualControlBarActions="{Binding ViewerManualControlBarActions}">
</local:TSRemoteManualControlBar>
</Border>
<Border DockPanel.Dock="Bottom" Background="LightBlue">
<TextBlock x:Name="tbErrorStock" FontSize="16" HorizontalAlignment="Center" Text="{Binding ProductDispenserStockError}"/>
</Border>
</DockPanel>
</Grid>
</UserControl>
TSFloorPlanProductDispenserStockViewer.xaml.cs
(摘录):
public static readonly DependencyProperty ProductDispenserStockErrorProperty = DependencyProperty.Register(
"ProductDispenserStockError", typeof(string), typeof(TSFloorPlanProductDispenserStockViewer),
new PropertyMetadata(null, new PropertyChangedCallback(TSFloorPlanProductDispenserStockViewer.OnProductDispenserStockErrorPropertyChanged)));
private static void OnProductDispenserStockErrorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TSFloorPlanProductDispenserStockViewer control = d as TSFloorPlanProductDispenserStockViewer;
if ((control != null) && (e.NewValue != null))
{
//(control.DataContext as TSFloorPlanProductDispenserStockViewer).ProductDispenserStockError = Convert.ToString(e.NewValue);
control.DataContext = e.NewValue;
}
}
public string ProductDispenserStockError
{
get
{
return (string)GetValue(ProductDispenserStockErrorProperty);
}
set
{
SetValue(ProductDispenserStockErrorProperty, value);
}
}
public static readonly DependencyProperty ViewerManualControlBarActionsProperty = DependencyProperty.Register(
"ViewerManualControlBarActions", typeof(ObservableCollection<TSRemoteManualControlBarAction>), typeof(TSFloorPlanProductDispenserStockViewer),
new PropertyMetadata(new PropertyChangedCallback(TSFloorPlanProductDispenserStockViewer.OnManualControlBarActionsPropertyChanged)));
private static void OnManualControlBarActionsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TSFloorPlanProductDispenserStockViewer control = d as TSFloorPlanProductDispenserStockViewer;
if ((control != null) && (e.NewValue != null))
{
control.DataContext = e.NewValue;
}
}
private ObservableCollection<TSRemoteManualControlBarAction> m_ViewerManualControlBarActions;
public ObservableCollection<TSRemoteManualControlBarAction> ViewerManualControlBarActions
{
get
{
return (ObservableCollection<TSRemoteManualControlBarAction>)GetValue(ViewerManualControlBarActionsProperty);
}
set
{
SetValue(ViewerManualControlBarActionsProperty, value);
}
}
TSFloorPlanInputStationProductDispenserMemberTemplate.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ASC_Control_HMI"
>
<local:BoolToOpacityValueConverter x:Key="IsActiveToOpacity"/>
<local:BoolToVisibilityValueConverter x:Key="IsActiveToVisibility"/>
<DataTemplate x:Key="FloorPlanInputStationProductDispenserMemberTemplate" DataType="{x:Type local:TSFloorPlanInputStationProductDispenser}">
<Grid Visibility="{Binding IsVisible, Mode=OneWay, Converter={StaticResource IsActiveToVisibility}}">
<DockPanel>
<DockPanel DockPanel.Dock="Bottom">
<Grid x:Name="grdDispenserStockViewers" Margin="0,10,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="60"/>
<!--<RowDefinition Height="*"/>-->
</Grid.RowDefinitions>
<local:TSFloorPlanProductDispenserStockViewer Grid.Row="0" Grid.Column="0" x:Name="ProductDispenserStockViewer1" ProductDispenserStockID="Upper" ProductDispenserStockError="{Binding UpperStockError}" ViewerManualControlBarActions="{Binding ManualControlBarActions1}">
</local:TSFloorPlanProductDispenserStockViewer>
<local:TSFloorPlanProductDispenserStockViewer Grid.Row="0" Grid.Column="1" x:Name="ProductDispenserStockViewer2" ProductDispenserStockID="Lower" ProductDispenserStockError="{Binding LowerStockError}" ViewerManualControlBarActions="{Binding ManualControlBarActions2}">
</local:TSFloorPlanProductDispenserStockViewer>
</Grid>
</DockPanel>
</DockPanel>
</Grid>
</DataTemplate>
</ResourceDictionary>
我在
TSFloorPlanProductDispenserStockViewer
的构造函数中将错误字符串设置为“DefaultError”,以便至少看到一些内容,但它们打印在为 ManualControlBar
保留的插槽中。我很确定我的 DataContext 设置是错误的,但我无法通过我发现的有关数据绑定的其他帖子来正确设置它。
任何帮助将不胜感激
=======编辑=======
我已经按照 @bioniccode 的建议删除了查看器对 DataContext 的引用,并且我为查看器属性
ProductDispenserStockError
或 ViewerManualControlBarActions
提供的任何默认值都会显示。当我尝试使用 UserControl 的父级属性作为这些值时,它们不会更新
<local:TSFloorPlanProductDispenserStockViewer Grid.Row="0" Grid.Column="0"
x:Name="ProductDispenserStockViewer1"
ProductDispenserStockID="Upper"
ProductDispenserStockError="{Binding UpperStockError}"
ViewerManualControlBarActions="{Binding ManualControlBarActions1}">
</local:TSFloorPlanProductDispenserStockViewer>
<local:TSFloorPlanProductDispenserStockViewer Grid.Row="0" Grid.Column="1"
x:Name="ProductDispenserStockViewer2"
ProductDispenserStockID="Lower"
ProductDispenserStockError="{Binding LowerStockError}"
ViewerManualControlBarActions="{Binding ManualControlBarActions2}">
如何将查看器属性绑定到模板“代码隐藏”中的属性?
您没有在内部设置 DataContext。你永远不会这样做。你甚至没有得到
DataContext
。您的控件无需知道 DataContext
即可进行操作。
内部元素始终绑定到自定义控件(或
UserControl
)的依赖属性。创建 ControlTemplate
时,您可以使用 {TemplateBinding}
或 {Binding RelativeSource={realtiveSource TemplatedParent}}
进行绑定。在所有其他情况下,您都使用 Binding.ElementName
或 Binding.RelativeSource
。
例如
TSFloorPlanProductDispenserStockViewer.xaml.cs
删除对 DataContext 的所有引用。
public static readonly DependencyProperty ProductDispenserStockErrorProperty = DependencyProperty.Register(
"ProductDispenserStockError",
typeof(string),
typeof(TSFloorPlanProductDispenserStockViewer));
public string ProductDispenserStockError
{
get => (string)GetValue(ProductDispenserStockErrorProperty);
set => SetValue(ProductDispenserStockErrorProperty, value);
}
public static readonly DependencyProperty ViewerManualControlBarActionsProperty = DependencyProperty.Register(
"ViewerManualControlBarActions",
typeof(ObservableCollection<TSRemoteManualControlBarAction>),
typeof(TSFloorPlanProductDispenserStockViewer));
public ObservableCollection<TSRemoteManualControlBarAction> ViewerManualControlBarActions
{
get => (ObservableCollection<TSRemoteManualControlBarAction>)GetValue(ViewerManualControlBarActionsProperty);
set => SetValue(ViewerManualControlBarActionsProperty, value);
}
TSFloorPlanProductDispenserStockViewer.xaml.cs
然后修复绑定并直接绑定到由
UserControl
定义的依赖属性。
<UserControl x:Name="Root">
<Grid>
<DockPanel>
<!-- Option #1: Binding.ElementName (recommended) -->
<local:TSRemoteManualControlBar x:Name="DispenserStockManualControlBar"
ManualControlBarActions="{Binding ElementName=Root,
Path=ViewerManualControlBarActions}" />
<!-- Option #2: Binding.RelativeSource -->
<TextBlock x:Name="tbErrorStock"
Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl},
Path=ProductDispenserStockError}"/>
</DockPanel>
</Grid>
</UserControl>
现在您可以照常使用该控件。外部 DataContext 值不再被覆盖,因此控件上设置的外部绑定可以正常运行。