I'm trying to bind a list of custom data objects to a data grid and achieve the following behavior.
Consider the following DataGrid
<DataGrid ItemsSource="{Binding Path=CustomObjectList}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=FieldName}"
Header="Field Name"
IsReadOnly="True" />
<DataGridCheckBoxColumn Binding="{Binding Path=Compare}"
Header="Compare" />
<DataGridTextColumn Binding="{Binding Path=Tolerance}"
Header="Tolerance" />
</DataGrid.Columns>
</DataGrid>
With a backing object like this...
public class CustomObject: BaseModel
{
private bool _compare;
private bool _disableTolerance;
private string _fieldName;
private bool _mustCompare;
private double _tolerance;
/// <summary>
/// Gets or sets the compare.
/// </summary>
/// <value>The compare.</value>
public bool Compare
{
get
{
return this._compare;
}
set
{
this._compare = value;
this.NotifyPropertyChange("Compare");
}
}
/// <summary>
/// Gets or sets the disable tolerance.
/// </summary>
/// <value>The disable tolerance.</value>
public bool DisableTolerance
{
get
{
return this._disableTolerance;
}
set
{
this._disableTolerance = value;
this.NotifyPropertyChange("DisableTolerance");
}
}
/// <summary>
/// Gets or sets the name of the field.
/// </summary>
/// <value>The name of the field.</value>
public string FieldName
{
get
{
return this._fieldName;
}
set
{
this._fieldName = value;
this.NotifyPropertyChange("FieldName");
}
}
/// <summary>
/// Gets or sets the must compare.
/// </summary>
/// <value>The must compare.</value>
public bool MustCompare
{
get
{
return this._mustCompare;
}
set
{
this._mustCompare = value;
this.NotifyPropertyChange("MustCompare");
}
}
/// <summary>
/// Gets or sets the tolerance.
/// </summary>
/// <value>The tolerance.</value>
public double Tolerance
{
get
{
return this._tolerance;
}
set
{
this._tolerance = value;
this.NotifyPropertyChange("Tolerance");
}
}
}
And you can consider the CustomObjectList to be populated like this...
this.ComparisonsAndTolerances.Add(new ComparisonSettingsTolerances()
{
FieldName = "Alpha",
Compare = true,
MustCompare = true,
Tolerance = 0,
DisableTolerance = false
});
this.ComparisonsAndTolerances.Add(new ComparisonSettingsTolerances()
{
FieldName = "Bravo",
Compare = true,
MustCompare = false,
Tolerance = 0,
DisableTolerance = true
});
So, of course the FieldName, Compare, and Tolerance properties are filling into the grid appropriately.
However, what I would like to achieve is, when MustCompare is true, then that cell is marked as read only. And when DisableTolerance is true, that cell is marked as read only.
Obviously this will vary from cell to cell and row to row with the 4 different combinations, but I was hoping to achieve this through binding.
I tried
IsReadOnly="{Binding Path=MustCompare}"
and
IsReadOnly="{Binding Path=CustomObjectList/MustCompare}"
But neither of those worked.
Thanks.
That is one interesting bug/situation you've got there.
What happens? Well, the binding is trying to bind to MustCompare
property (and probably would have succeeded) but it cannot find FrameworkElement
or FrameworkContentElement
to be the target of the binding since none of data grid's columns are in the visual tree.
There is a solution, albeit not so elegant as what you (rightfully) tried to do:
<DataGridTemplateColumn Header="Compare">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="TextHolder" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Compare}"
Value="True">
<Setter TargetName="TextHolder"
Property="Text"
Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Compare}"
Value="False">
<Setter TargetName="TextHolder"
Property="Text"
Value="False" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<CheckBox x:Name="Check"
IsChecked="{Binding Path=Compare}"
ToolTipService.ShowOnDisabled="True"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=MustCompare}"
Value="True">
<Setter TargetName="Check"
Property="IsEnabled"
Value="False" />
<Setter TargetName="Check"
Property="ToolTip"
Value="You cannot change this value since this item must compare" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
I've changed the cell so it shows text when in non-edit mode and check box when editing (just to see in what state is the cell, you can change it to check box in both cases).
This is not optimal, and I'd like to hear from you if you (or anybody) find a better solution.
Thought of another solution:
<DataGridCheckBoxColumn Binding="{Binding Path=Compare}"
Header="Compare">
<DataGridCheckBoxColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding MustCompare}"
Value="True">
<Setter Property="IsEnabled"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridCheckBoxColumn.CellStyle>
</DataGridCheckBoxColumn>
This makes the check box disabled in non-edit mode, so it looks different. Might be a good thing or a bad thing, depending upon your functional design.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With