Reputation: 85
I have datagrid bound to an ObservableCollection of items which do implement INotifyPropertyChanged. Just one column is editable. Another column is an image which I want to be automatically changed based on the value edited in the column. It doesn't work. It does refresh if I click on row header for example (sort), but not right after editing
<DataGrid ItemsSource="{Binding ItemRows,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" AutoGenerateColumns="False"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="false">
<DataGrid.Columns>
<DataGridTextColumn Header="Editable" Binding="{Binding Editable, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image x:Name="imgComplete" Width="20" Height="20">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="{StaticResource imgCheckmarkOrange}" />
<Style.Triggers>
<DataTrigger Value="0" Binding="{Binding Editable,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<Setter Property="Source" Value="{StaticResource imgSadFace}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
EDIT: adding parts of my View model
I'm using FODY, my structure is pretty complex, so I am posting only what's related to datagrid source
[ImplementPropertyChanged]
public class MyViewModel
{
....
public ObservableCollection<StockOrderRow> ItemRows { get; set; } = new ObservableCollection<StockOrderRow>();
.....
}
This collection is loaded with data from the database on a change of another property
The Class "StockOrderRow"
public class StockOrderRow : BaseEntity
{
public string Field1{ get; set; } = "";
...
public int Editable { get; set; } = 0;
}
And the class "BaseEntity"
public class BaseEntity: INotifyPropertyChanged
{
public string Id { get; set; }
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Upvotes: 1
Views: 582
Reputation: 1649
I would recommend using a DataGridTemplateColumn for your Editable property. With this you can handle the Binding with PropertyChanged in your TextBox directly.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Editable}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Editable, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
the second thing is that your ItemsClasses property Editable has to call the OnPropertyChange
public class StockOrderRow:BaseEntity
{
public string Field1{ get; set; } = "";
private int _editable = 0;
public int Editable {
get { return _editable; }
set {
if(value == _editable) return;
// Debug.WriteLine("Editable set. OldVal: " + _editable + "; NewVal:" + value);
_editable = value;
OnPropertyChanged(nameof(Editable));
}
}
}
Your DataTrigger doesn't need to Bind in Mode TwoWay
<Style.Triggers>
<DataTrigger Value="0" Binding="{Binding Editable,UpdateSourceTrigger=PropertyChanged}">
<Setter Property="Source" Value="{StaticResource imgSadFace}"/>
</DataTrigger>
</Style.Triggers>
If this doesn't work I would start Debugging at the setter of Editable (and check, if the property is updated while typing in your TextBox...).
Upvotes: 1