【问题标题】:C# WPF - Binding to parent-ViewModel within DataGrid not workingC# WPF - 绑定到 DataGrid 中的父 ViewModel 不起作用
【发布时间】:2020-03-29 20:42:38
【问题描述】:

在绑定到项目源后,我试图从 DataGrid 中访问与我的 ViewModel 的 DependencyProperty 的绑定。 虽然从外部 DataGrid 绑定运行良好,并且 DataGrid 内的绑定也适用于 Itemssource 的元素,但我无法在 DataGrid 中绑定到我的 viewModel。 我尝试了几种方法。

我想使用该非工作绑定来实现: - 通过 viewModel 中的依赖属性加载列标题 - 从 ViewModel 加载一个 bool 值,用于确定列是否为只读

这是我在 ViewModel 中指定的 DependencyProperties 之一:

public static readonly DependencyProperty FirstColDataGridLabelProperty = DependencyProperty.Register(
            "FirstColDataGridLabel", typeof(string), typeof(MyVm), new PropertyMetadata(default(string)));

在 viewlModel 的构造函数中,一些值被分配给了dependencyProperties。

编辑: 将边界网格和 UserControl-Tag 添加到 Data-Grid: MyList 是一个 List,包含数据(FirstCol、SecondCol 等)

<UserControl x:Class="Aidb.GeoMonPlus.Wpf.Control.EditSpatialReferenceListControl"
             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:viewModel="clr-namespace:Aidb.GeoMonPlus.ViewModel.Control;assembly=Aidb.GeoMonPlus.ViewModel"
             Width="Auto"
             Height="Auto"
             MinWidth="400"
             MinHeight="200"
             mc:Ignorable="d" 
             d:DesignHeight="400" d:DesignWidth="1000"
             x:Name="myControl">
    <Grid>
<DataGrid Grid.Column="0" Grid.Row="0"
    ItemsSource="{Binding MyList}"
    CanUserResizeColumns="True"
    CanUserResizeRows="True"
    CanUserSortColumns="True"
    CanUserAddRows="False"
    AlternatingRowBackground="Gainsboro"
    AlternationCount="2"
    AutoGenerateColumns="False"
    BorderBrush="Black"
    GridLinesVisibility="Vertical">
    <DataGrid.Columns>
        <DataGridTextColumn Header="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type viewModel:MyVm}}, Path=FirstColDataGridLabel}" Binding="{Binding FirstCol}" Width="Auto" IsReadOnly="True"/>
        <DataGridTextColumn Header="{Binding SecondColDataGridLabel, FallbackValue='AnzeigeraumbezugDataGridLabel'}" Binding="{Binding (viewModel:EditSpatialReferenceListVm.GCSDataGridLabel) }" Width="Auto" IsReadOnly="True"/>
        <DataGridTextColumn Header="{Binding (viewModel:MyVm.ThirdColDataGridLabel)}" Binding="{Binding ThirdCol}" Width="Auto" IsReadOnly="True"/>
        <DataGridTextColumn Header="{Binding ElementName=myControl, Path=DataContext.FourthColDataGridLabel}" Binding="{Binding FourthCol}" Width="Auto" IsReadOnly="True">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="Margin" Value="0,0,-1,0"></Setter>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>
<Button Grid.Column="0" Grid.Row="1"
    Margin="0,20,0,20"
    Width="75"
    Height="Auto"
    HorizontalAlignment="Left"
    VerticalAlignment="Center"
    Command="{Binding BtnShowSubmit}"
    Content="{Binding BtnShowLabel, FallbackValue='BtnShowLabel'}" />

标题名称的 dataBinding 的四次尝试均无效。表的所​​有表头为空或显示 fallback-value。

itemssource 的绑定有效,数据按预期显示在数据网格中。 按钮中用于显示按钮文本的绑定按预期工作。

这对 DataGrid 来说是不可能的吗?或者在绑定到 itemssource 后如何从 dataGrid 内部访问 ViewModels 的 DependecyProperties?

编辑2: 有人问,这是我的 ViewModels 基类:

public class ViewModelBase : DependencyObject, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected static void PropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var vmBase = sender as ViewModelBase;
        vmBase?.OnPropertyChanged(args.Property.Name);
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

编辑3:

我发现了一些错误信息:

System.Windows.Data 错误:4:找不到绑定源 参考'RelativeSource FindAncestor, AncestorType='MyProject.ViewModel.Control.EditSpatialReferenceListVm', 祖先级别='1''。绑定表达式:路径=GCSDataGridLabel; 数据项=空;目标元素是“DataGridTextColumn” (哈希码=8060118);目标属性是“标题”(类型“对象”)

System.Windows.Data 错误:2:找不到管理 FrameworkElement 或 FrameworkContentElement 为目标元素。 BindingExpression:Path=(viewModel:EditSpatialReferenceListVm.GCSDataGridLabel); 数据项=空;目标元素是“DataGridTextColumn” (哈希码=16639474);目标属性是“标题”(类型“对象”)

搜索这个会导致那个帖子: WPF Error: Cannot find governing FrameworkElement for target element 用户“WPF-it”指出:

遗憾的是,托管在 DataGrid.Columns 下的任何 DataGridColumn 都不属于 可视化树,因此未连接到 数据网格。

他建议使用代理控制。

【问题讨论】:

  • 你的viewmodel的基类是什么?
  • 在上面查看我的编辑

标签: c# wpf mvvm data-binding datagrid


【解决方案1】:

正如主帖(编辑 3)中提到的,它确实不适用于数据网格。 但是使用 DataView 可以解决这个问题。

使用带有内部 GridView 而不是 DataGrid 的 ListView 也可以解决这个问题。 这样,以下绑定就可以工作了:

<GridViewColumn Header="{Binding HoehenbezugsrahmenDataGridLabel, FallbackValue='HoehenbezugsrahmenDataGridLabel'}" DisplayMemberBinding="{Binding Hoehenbezugsrahmen}" Width="250" />
<GridViewColumn Header="{Binding ElementName=myControl, Path=DataContext.TransformationDataGridLabel, FallbackValue='AnzPunkteGeoMonDataGridLabel'}" DisplayMemberBinding="{Binding Transformation}" Width="250" />
<GridViewColumn Header="{Binding Path=Text, Source={x:Reference tmpHeader}}" DisplayMemberBinding="{Binding AnzPunkteGeoMon}" Width="250" />


<GridViewColumn DisplayMemberBinding="{Binding Ursprungsraumbezug}" Width="250">
    <GridViewColumn.HeaderTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding ElementName=myControl, Path=DataContext.TransformationDataGridLabel, FallbackValue='AnzPunkteGeoMonDataGridLabel'}"/>
        </DataTemplate>
    </GridViewColumn.HeaderTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Ursprungsraumbezug}" Width="250">
    <GridViewColumn.HeaderTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=Text, Source={x:Reference tmpHeader}}"/>
        </DataTemplate>
    </GridViewColumn.HeaderTemplate>
</GridViewColumn>

所有其他提到的绑定都不起作用,标题一直是空的。 再次使用 Ancestor 不起作用。

尤其是第一种方法是最短的。 因此,我将从 DataGrid 更改为 ListView。

【讨论】:

    【解决方案2】:

    我刚刚经历了同样的事情。发布了几种解决此问题的方法,我可以看到您已经尝试了一些,但是除了一种之外,它们都不适合我。 在数据网格上方创建一个控件并为其命名:

    <TextBlock x:Name="tempcontrol" Text="{Binding HeaderText}" Visibility="Collapsed"/>
    

    然后将此临时控件绑定到您想要的数据并将其可见性设置为折叠。

    然后将您的 DataGridColumn 绑定到临时控件属性:

    <DataGridTextColumn Header="{Binding Path=Text, Source={x:Reference tempControl}}"/>
    

    我的情况略有不同,因为我绑定到 Visibilty 属性,所以我使用 FrameworkElement 而不是 TextBlock 作为虚拟控件,但我认为这应该也可以。

    【讨论】:

    • 好的,这确实有效。我只是想到了这样的事情,实际上是在主控件头中创建一个局部变量,将您需要的所有变量存储在临时控件中并通过 x:Name 重用它们。谢谢你。但在选择此作为正确答案之前,我想等待知道为什么所有其他方式都不起作用。数据网格有问题吗?至少祖先搜索应该可以工作,不是吗?我可能正在切换到 ListView,它似乎可以使用上面的一种解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 2013-01-14
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    相关资源
    最近更新 更多