I can´t get this working. I have a view) which contains a DataGrid populated with items of an observable collection (MyDataCollection). Every item of MyDataCollection has different properties (Name, Description,..., Logs). Logs is an observable collection itself of Log items. Every Log item has different properties (Date, Person,...).
My data grid populated with items of MyDataCollection has a tooltip per row set. Like this:
<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>
I can see the tooltip, and I can see the datagrid in the tooltip with the Headers "Date" and "Person" but the grid content is empty. Looks like the binding is not set correct. Can anyone give me a hand? Thanks
Update 1 : MyDataColletion contains objects of my custom class "Car". Here the definition of Car:
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));
}
}
And my Log Class is:
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));
}
}
The only thing I can find in your code that doesn't work perfectly for me is Mode=TwoWay
in the binding on LogsGrid.ItemsSource
. That throws an exception for me, because it's telling the Binding
that you want LogsGrid
to write new values for ItemsSource
back to the Binding
source -- in this case, to the viewmodel's Logs
property. Not only is that not what you want, but it's actually impossible since Logs
has a private setter (and furthermore, DataGrid
doesn't do that anyway). Hence the exception.
UpdateSourceTrigger=PropertyChanged
is another one that serves no purpose, though harmlessly this time: That tells it when to write new Logs
collections back to Car.Logs
. But again, DataGrid
can't do that. It doesn't create new values for the property. A TextBox
will assign new Text
values to the source property, that's what a TextBox
is for. But DataGrid
doesn't do that.
When I get rid of those two things, it works fine for me:
<DataGrid x:Name="LogsGrid" Grid.Row="6" ItemsSource="{Binding Logs}">
<!-- etc. -->