WPF 数据绑定问题:DataGrid 单元格中的用户控件未绑定
WPF DataBinding issue: UserControls in DataGrid Cells not binding
我正在尝试构建用于管理 属性 网格的 DataGrid 控件。我的参数基础 class 有一个抽象 class ,各种类型的参数都实现了。这个基础 class 包含在每个参数之间共享的变量(如组、名称、IsLocked 等),然后每个参数管理与特定类型相关的信息。例如,一个数字参数可以使用一个滑块作为用户控件,然后它也使用 min/max 值等。
我已经设置了一个 class,它是我的基本参数的 Observable Collection,并将其建立为 CollectionViewSource 的静态资源:
<UserControl.Resources>
<local:Parameters x:Key="Parameters"/>
<CollectionViewSource x:Key="cvsParameters" Source="{StaticResource Parameters}" />
</UserControl.Resources>
然后在我的 DataGrid 中,我使用样式触发器在每个参数的用户控件之间切换:
<DataGrid x:Name="DataGrid_Globals"
ItemsSource="{Binding Source={StaticResource cvsParameters}}"
AutoGenerateColumns="False"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Key" Binding="{Binding Key}" IsReadOnly="True"/>
<DataGridTemplateColumn Width="*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding UIType}" Value="Text">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<controls:ucText DataContext="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding UIType}" Value="Number">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<controls:ucNumber DataContext="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
我的用户控件是使用在 XAML 中声明的数据上下文设置的:
<UserControl.DataContext>
<local:TestNumber_cls/>
</UserControl.DataContext>
<Grid HorizontalAlignment="Stretch">
<Slider
Value="{Binding NumberValue}"
Minimum="{Binding Min}"
Maximum="{Binding Max}"
/>
</Grid>
我不知道如何确保我的用户控件正确绑定。我的另一列工作正常,每个键值都出现,被正确绑定和更新(对于这个例子,它只是 "Key" 列,但是来自基础 class 的所有字段都表现得很好。)还根据 UIType DataTrigger 选择了正确的 UserControls,但 UserControls 只是从一个空的构造函数实例化并且不绑定。
我还确认我的 UserControls 的独立实例工作正常并且绑定正确。例如,当我从后面的代码(我不想这样做)设置数据上下文时它起作用了:
this.OneOffNumberUserControl.DataContext = ((Parameters)this.ParameterGrid.Resources["Parameters"])[2];
我也曾尝试从我的用户控件中删除 DataContext="{Binding}",但这并没有改变任何东西。
如果要给不同的子类放不同的控件,指定不同的datatemplates,然后
<!-- subtype-specific column -->
<DataGridTemplateColumn Header="">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
结合上面 Mechanic 的建议,大大简化了我的 属性 网格的 XAML,通过进一步的研究,我还了解到我需要为每个子类相关的用户控件实现一个 DependencyProperty。在我的 属性 网格 UserControl 中为每个数据类型设置 DataTemplate 的地方,我将绑定设置到我的 DependencyProperty。
<UserControl.Resources>
<local:Parameters x:Key="Parameters"/>
<CollectionViewSource x:Key="cvsParameters" Source="{StaticResource Parameters}" />
<DataTemplate DataType="{x:Type local:TestText_cls}">
<controls:ucText TextObject="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:TestNumber_cls}">
<controls:ucNumber NumberObject="{Binding}"/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<DataGrid x:Name="DataGrid_Globals"
ItemsSource="{Binding Source={StaticResource cvsParameters}}"
AutoGenerateColumns="False"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Key" Binding="{Binding Key}" IsReadOnly="True"/>
<DataGridTemplateColumn Width="*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
然后在我的 UserControls 后面的代码中,我实现了 DependencyProperty:
public static readonly DependencyProperty TextObjectProperty =
DependencyProperty.Register("TextObject",
typeof(TestText_cls),
typeof(ucText),
new PropertyMetadata(new TestText_cls()));
[Bindable(true)]
public TestText_cls TextObject
{
get { return (TestText_cls)this.GetValue(TextObjectProperty); }
set { this.SetValue(TextObjectProperty, value); }
}
public ucText()
{
InitializeComponent();
}
最后,在每个 UserControl 中,我确保已为其命名,然后在我的 DependencyProperty 中将我的绑定设置为正确的变量:
<UserControl x:Class="Testing.ucText"
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:Testing.Classes"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Name="TextUI">
<Grid HorizontalAlignment="Stretch">
<TextBox Text="{Binding ElementName=TextUI, Path=TextObject.Value}"/>
</Grid>
</UserControl>
我希望这对其他人有帮助!
我正在尝试构建用于管理 属性 网格的 DataGrid 控件。我的参数基础 class 有一个抽象 class ,各种类型的参数都实现了。这个基础 class 包含在每个参数之间共享的变量(如组、名称、IsLocked 等),然后每个参数管理与特定类型相关的信息。例如,一个数字参数可以使用一个滑块作为用户控件,然后它也使用 min/max 值等。
我已经设置了一个 class,它是我的基本参数的 Observable Collection,并将其建立为 CollectionViewSource 的静态资源:
<UserControl.Resources>
<local:Parameters x:Key="Parameters"/>
<CollectionViewSource x:Key="cvsParameters" Source="{StaticResource Parameters}" />
</UserControl.Resources>
然后在我的 DataGrid 中,我使用样式触发器在每个参数的用户控件之间切换:
<DataGrid x:Name="DataGrid_Globals"
ItemsSource="{Binding Source={StaticResource cvsParameters}}"
AutoGenerateColumns="False"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Key" Binding="{Binding Key}" IsReadOnly="True"/>
<DataGridTemplateColumn Width="*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding UIType}" Value="Text">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<controls:ucText DataContext="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding UIType}" Value="Number">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<controls:ucNumber DataContext="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
我的用户控件是使用在 XAML 中声明的数据上下文设置的:
<UserControl.DataContext>
<local:TestNumber_cls/>
</UserControl.DataContext>
<Grid HorizontalAlignment="Stretch">
<Slider
Value="{Binding NumberValue}"
Minimum="{Binding Min}"
Maximum="{Binding Max}"
/>
</Grid>
我不知道如何确保我的用户控件正确绑定。我的另一列工作正常,每个键值都出现,被正确绑定和更新(对于这个例子,它只是 "Key" 列,但是来自基础 class 的所有字段都表现得很好。)还根据 UIType DataTrigger 选择了正确的 UserControls,但 UserControls 只是从一个空的构造函数实例化并且不绑定。
我还确认我的 UserControls 的独立实例工作正常并且绑定正确。例如,当我从后面的代码(我不想这样做)设置数据上下文时它起作用了:
this.OneOffNumberUserControl.DataContext = ((Parameters)this.ParameterGrid.Resources["Parameters"])[2];
我也曾尝试从我的用户控件中删除 DataContext="{Binding}",但这并没有改变任何东西。
如果要给不同的子类放不同的控件,指定不同的datatemplates,然后
<!-- subtype-specific column -->
<DataGridTemplateColumn Header="">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
结合上面 Mechanic 的建议,大大简化了我的 属性 网格的 XAML,通过进一步的研究,我还了解到我需要为每个子类相关的用户控件实现一个 DependencyProperty。在我的 属性 网格 UserControl 中为每个数据类型设置 DataTemplate 的地方,我将绑定设置到我的 DependencyProperty。
<UserControl.Resources>
<local:Parameters x:Key="Parameters"/>
<CollectionViewSource x:Key="cvsParameters" Source="{StaticResource Parameters}" />
<DataTemplate DataType="{x:Type local:TestText_cls}">
<controls:ucText TextObject="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:TestNumber_cls}">
<controls:ucNumber NumberObject="{Binding}"/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<DataGrid x:Name="DataGrid_Globals"
ItemsSource="{Binding Source={StaticResource cvsParameters}}"
AutoGenerateColumns="False"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Key" Binding="{Binding Key}" IsReadOnly="True"/>
<DataGridTemplateColumn Width="*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
然后在我的 UserControls 后面的代码中,我实现了 DependencyProperty:
public static readonly DependencyProperty TextObjectProperty =
DependencyProperty.Register("TextObject",
typeof(TestText_cls),
typeof(ucText),
new PropertyMetadata(new TestText_cls()));
[Bindable(true)]
public TestText_cls TextObject
{
get { return (TestText_cls)this.GetValue(TextObjectProperty); }
set { this.SetValue(TextObjectProperty, value); }
}
public ucText()
{
InitializeComponent();
}
最后,在每个 UserControl 中,我确保已为其命名,然后在我的 DependencyProperty 中将我的绑定设置为正确的变量:
<UserControl x:Class="Testing.ucText"
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:Testing.Classes"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Name="TextUI">
<Grid HorizontalAlignment="Stretch">
<TextBox Text="{Binding ElementName=TextUI, Path=TextObject.Value}"/>
</Grid>
</UserControl>
我希望这对其他人有帮助!