【问题标题】:Binding to a nested Property in DataGrid row tooltip WPF绑定到 DataGrid 行工具提示 WPF 中的嵌套属性
【发布时间】:2017-03-19 03:34:50
【问题描述】:

我无法正常工作。我有一个视图),其中包含一个填充了可观察集合(MyDataCollection)项目的 DataGrid。 MyDataCollection 的每个项目都有不同的属性(名称、描述、...、日志)。 Logs 本身就是一个可观察的 Log 项集合。每个日志项都有不同的属性(日期、人员、...)。

我的数据网格填充了 MyDataCollection 项,每行集都有一个工具提示。像这样:

<DataGrid ItemsSource="{Binding MyDataCollection}">
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="ToolTip">
                        <Setter.Value>
                            <Border>
                                <Grid Margin="5" MaxWidth="400">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*" />
                                        ...
                                    </Grid.RowDefinitions>

                                    ...
                                    <DataGrid x:Name="LogsGrid" Grid.Row="6" ItemsSource="{Binding PlacementTarget.DataContext.Logs, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToolTip}}">
                                        <DataGrid.Columns>
                                            <DataGridTextColumn Header="Date" 
                                                Binding="{Binding Date}" 
                                                />
                                            <DataGridTextColumn Header="Person" 
                                                Binding="{Binding Person.FullName}" 
                                                />

                                        </DataGrid.Columns>
                                    </DataGrid>
                                </Grid>
                            </Border>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>

我可以看到工具提示,并且可以在工具提示中看到带有标题“日期”和“人员”的数据网格,但网格内容为空。看起来绑定设置不正确。谁能帮我一把?谢谢

更新 1: MyDataColletion 包含我的自定义类“汽车”的对象。这里是汽车的定义:

public class Car : INotifyPropertyChanged
{
    public string name;
    public string description;
    public Contact assignedTo;
    public ObservableCollection<Log> logs = new ObservableCollection<Log>();
    public string Name
    {
        get
        {
            return this.name;
        }
        set
        {
            if (this.name != value)
            {
                this.name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }
    public string Description 
    {
        get
        {
            return this.description;
        }
        set
        {
            if (this.description != value)
            {
                this.description = value;
                NotifyPropertyChanged("Description");
            }
        }
    }
    public Contact AssignedTo 
    {
        get
        {
            return this.assignedTo;
        }
        set
        {
            if (this.assignedTo != value)
            {
                this.assignedTo = value;
                NotifyPropertyChanged("AssignedTo");
            }
        }
    }

    public ObservableCollection<Log> Logs
    {
        get
        {
            return this.logs;
        }
        private set //TODO : Check if this is correct
        {
            if (this.logs != value)
            {
                this.logs = value;
                NotifyPropertyChanged("Logs");
            }
        }
    }

    public Car()
    {
        // TODO: Delete this: (only here for testing)
        Contact c = new Contact();
        c.Name = "Test";
        c.LastName = "Test";
        for (int i = 0; i < 4; i++)
            AddLog(DateTime.Now, c, new TimeSpan(2, 0, 0));
    }
    public void AddLog(DateTime date, Contact person, TimeSpan time)
    {
        Log newLog = new Log(date, person, time);
        Logs.Add(newLog);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
}

我的日志类是:

public class Log : INotifyPropertyChanged
{
    DateTime date; 
    Contact person;
    TimeSpan time;
    public DateTime Date
    {
        get
        {
            return this.date;
        }
        set
        {
            if (this.date != value)
            {
                this.date = value;
                NotifyPropertyChanged("Date");
            }
        }
    }
    public Contact Person
    {
        get
        {
            return this.person;
        }
        set
        {
            if (this.person != value)
            {
                this.person = value;
                NotifyPropertyChanged("Person");
            }
        }
    }
    public TimeSpan Time
    {
        get
        {
            return this.time;
        }
        set
        {
            if (this.time != value)
            {
                this.time = value;
                NotifyPropertyChanged("Time");
            }
        }
    }

    public Log(DateTime date, Contact person, TimeSpan time)
    {
        this.date = date;
        this.person = person;
        this.time = time;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
}

【问题讨论】:

  • 在工具提示网格中的 ItemsSource 绑定上,首先删除您放入其中的所有 TwoWay/PropertyChanged 内容。如果您阅读有关这些的文档,您会发现它们无关。然后将 PresentationTraceSources.TraceLevel=High 添加到该 Binding 中,并在运行时查看 VS 输出窗格。您将在那里看到消息,告诉您在尝试解析绑定路径时会发生什么。您需要找出该绑定的 DataContext 是什么实际对象。那会告诉你的。
  • 我在 VS 输出窗格中收到此错误:System.Windows.Data 错误:40:BindingExpression 路径错误:在 'object' ''DataGrid' 上找不到 'Logs' 属性(Name='LogsGrid ')'。绑定表达式:路径=日志; DataItem='DataGrid'(名称='LogsGrid');目标元素是“DataGrid”(名称=“LogsGrid”);目标属性是“ItemsSource”(类型“IEnumerable”)然后一些警告告诉我该属性为空。但是当应用程序运行时会显示此消息,而不是在我将元素添加到 ObservableCollection 时显示。所以也许项目源没有更新??
  • 它告诉您源对象上不存在 Logs 属性。不是空的。不存在——在它正在寻找的地方。它找错地方了。请改用DataContext.Logs
  • 这是现在的输出:System.Windows.Data 警告:108:BindingExpression (hash=41695345):在级别 0 - 对于 DataGrid.PlacementTarget 找到访问器 System.Windows.Data 错误: 40:BindingExpression 路径错误:在“对象”“DataGrid”(名称=“LogsGrid”)上找不到“PlacementTarget”属性。 BindingExpression:Path=PlacementTarget.DataContext.Logs; DataItem='DataGrid'(名称='LogsGrid');目标元素是“DataGrid”(名称=“LogsGrid”);目标属性是“ItemsSource”(类型“IEnumerable”)
  • 谢谢埃德!!就是这样。您想在评论中插入的答案中回答这个问题,以便我可以将您的答案标记为正确吗? :)

标签: c# wpf binding datagrid tooltip


【解决方案1】:

我能在你的代码中找到的唯一不适合我的是LogsGrid.ItemsSource 绑定中的Mode=TwoWay。这对我来说是一个例外,因为它告诉Binding 您希望LogsGridItemsSource 的新值写回Binding 源——在这种情况下,是视图模型的Logs 属性。这不仅不是您想要的,而且实际上是不可能的,因为Logs 有一个私人设置器(此外,DataGrid 无论如何都不会这样做)。因此例外。

UpdateSourceTrigger=PropertyChanged 是另一个毫无用处的对象,尽管这次是无害的:它告诉它何时将新的Logs 集合写回Car.Logs。但同样,DataGrid 不能这样做。它不会为属性创建新值。 TextBox 将为源属性分配新的 Text 值,这就是 TextBox 的用途。但是DataGrid 不会那样做。

当我摆脱这两个东西时,它对我来说很好:

<DataGrid x:Name="LogsGrid" Grid.Row="6" ItemsSource="{Binding Logs}">
    <!-- etc. -->

【讨论】:

    【解决方案2】:

    代替ItemsSource="{Binding Logs, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"&gt;,使用这个:ItemsSource="{Binding PlacementTarget.DataContext.Logs, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToolTip}}"&gt;

    【讨论】:

    • @chincheta73 对不起,请看我更新的答案
    • 还是什么都没有。输出窗格显示: System.Windows.Data 警告:108 : BindingExpression (hash=41695345): At level 0 - for DataGrid.PlacementTarget found accessor System.Windows.Data Error: 40 : BindingExpression path error: 'PlacementTarget ' 在 'object' ''DataGrid' (Name='LogsGrid')' 上找不到属性。 BindingExpression:Path=PlacementTarget.DataContext.Logs; DataItem='DataGrid'(名称='LogsGrid');目标元素是“DataGrid”(名称=“LogsGrid”);目标属性是“ItemsSource”(类型“IEnumerable”)
    • @chincheta73 再次非常抱歉,忘记更改RelativeSource,请再次查看更新的答案。
    猜你喜欢
    • 2017-05-14
    • 2016-12-06
    • 2011-02-19
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    相关资源
    最近更新 更多