Skip to content

Commit

Permalink
Merge pull request #325 from AvaloniaUI/feature/cell-value-changed
Browse files Browse the repository at this point in the history
Added `TreeDataGrid.CellValueChanged` event.
  • Loading branch information
grokys authored Dec 16, 2024
2 parents f2a71d5 + ef0561f commit c4c078b
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 12 deletions.
13 changes: 10 additions & 3 deletions src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public virtual void Unrealize()
Model = null;
}

protected void BeginEdit()
protected internal void BeginEdit()
{
if (!IsEditing)
{
Expand All @@ -84,18 +84,19 @@ protected void BeginEdit()
}
}

protected void CancelEdit()
protected internal void CancelEdit()
{
if (EndEditCore() && Model is IEditableObject editable)
editable.CancelEdit();
}

protected void EndEdit()
protected internal void EndEdit()
{
if (EndEditCore() && Model is IEditableObject editable)
{
editable.EndEdit();
UpdateValue();
RaiseCellValueChanged();
}
}

Expand All @@ -115,6 +116,12 @@ protected virtual void UpdateValue()
{
}

protected void RaiseCellValueChanged()
{
if (!IsEditing && ColumnIndex != -1 && RowIndex != -1)
_treeDataGrid?.RaiseCellValueChanged(this, ColumnIndex, RowIndex);
}

protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
_treeDataGrid = this.FindLogicalAncestorOfType<TreeDataGrid>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@ public bool? Value
get => _value;
set
{
if (SetAndRaise(ValueProperty, ref _value, value) && Model is CheckBoxCell cell)
cell.Value = value;
if (SetAndRaise(ValueProperty, ref _value, value))
{
if (Model is CheckBoxCell cell)
cell.Value = value;
RaiseCellValueChanged();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ public class TreeDataGridTemplateCell : TreeDataGridCell
private IDataTemplate? _editingTemplate;
private ContentPresenter? _editingContentPresenter;

public object? Content
{
public object? Content
{
get => _content;
private set => SetAndRaise(ContentProperty, ref _content, value);
private set
{
if (SetAndRaise(ContentProperty, ref _content, value))
RaiseCellValueChanged();
}
}

public IDataTemplate? ContentTemplate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@ public string? Value
get => _value;
set
{
if (SetAndRaise(ValueProperty, ref _value, value) && Model is ITextCell cell && !_modelValueChanging)
cell.Text = _value;
if (SetAndRaise(ValueProperty, ref _value, value) && Model is ITextCell cell)
{
if (!_modelValueChanging)
cell.Text = _value;
RaiseCellValueChanged();
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ internal ITreeDataGridSelectionInteraction? SelectionInteraction

public event EventHandler<TreeDataGridCellEventArgs>? CellClearing;
public event EventHandler<TreeDataGridCellEventArgs>? CellPrepared;
public event EventHandler<TreeDataGridCellEventArgs>? CellValueChanged;
public event EventHandler<TreeDataGridRowEventArgs>? RowClearing;
public event EventHandler<TreeDataGridRowEventArgs>? RowPrepared;

Expand Down Expand Up @@ -415,6 +416,17 @@ internal void RaiseCellPrepared(TreeDataGridCell cell, int columnIndex, int rowI
}
}

internal void RaiseCellValueChanged(TreeDataGridCell cell, int columnIndex, int rowIndex)
{
if (CellValueChanged is not null)
{
_cellArgs ??= new TreeDataGridCellEventArgs();
_cellArgs.Update(cell, columnIndex, rowIndex);
CellValueChanged(this, _cellArgs);
_cellArgs.Update(null, -1, -1);
}
}

internal void RaiseRowClearing(TreeDataGridRow row, int rowIndex)
{
if (RowClearing is not null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,77 @@ public void Raises_CellClearing_CellPrepared_Events_On_Scroll()
Assert.Equal(2, preparedRaised);
}

[AvaloniaFact(Timeout = 10000)]
public void Raises_CellValueChanged_When_Model_Value_Changed()
{
var (target, items) = CreateTarget();
var raised = 0;

target.CellValueChanged += (s, e) =>
{
Assert.Equal(1, e.ColumnIndex);
Assert.Equal(1, e.RowIndex);
++raised;
};

items[1].Title = "Changed";

Assert.Equal(1, raised);
}

[AvaloniaFact(Timeout = 10000)]
public void Raises_CellValueChanged_After_Cell_Edit()
{
var (target, items) = CreateTarget();
var raised = 0;

target.CellValueChanged += (s, e) =>
{
Assert.Equal(1, e.ColumnIndex);
Assert.Equal(1, e.RowIndex);
++raised;
};

var cell = Assert.IsType<TreeDataGridTextCell>(target.TryGetRow(1)?.TryGetCell(1));
cell.BeginEdit();
cell.Value = "Changed";

Assert.Equal(0, raised);
Assert.Equal("Item 1", items[1].Title);

cell.EndEdit();

Assert.Equal("Changed", items[1].Title);
Assert.Equal(1, raised);
}

[AvaloniaFact(Timeout = 10000)]
public void Does_Not_Raise_CellValueChanged_Events_On_Initial_Layout()
{
var (target, items) = CreateTarget(runLayout: false);
var raised = 0;

target.CellValueChanged += (s, e) => ++raised;

target.UpdateLayout();

Assert.Equal(0, raised);
}

[AvaloniaFact(Timeout = 10000)]
public void Does_Not_Raise_CellValueChanged_Events_On_Scroll()
{
var (target, items) = CreateTarget();
var raised = 0;

target.CellValueChanged += (s, e) => ++raised;

target.Scroll!.Offset = new Vector(0, 10);
Layout(target);

Assert.Equal(0, raised);
}

[AvaloniaFact(Timeout = 10000)]
public void Does_Not_Realize_Columns_Outside_Viewport()
{
Expand Down Expand Up @@ -723,7 +794,7 @@ private static (TreeDataGrid, AvaloniaList<Model>) CreateTarget(IEnumerable<Mode
else
{
source.Columns.Add(new TextColumn<Model, int>("ID", x => x.Id));
source.Columns.Add(new TextColumn<Model, string?>("Title", x => x.Title));
source.Columns.Add(new TextColumn<Model, string?>("Title", x => x.Title, (o, v) => o.Title = v));
}

var target = new TreeDataGrid
Expand Down Expand Up @@ -785,8 +856,14 @@ private static TextColumnOptions<Model> MaxWidth(double max)

private class Model : NotifyingBase
{
private string? _title;

public int Id { get; set; }
public string? Title { get; set; }
public string? Title
{
get => _title;
set => RaiseAndSetIfChanged(ref _title, value);
}
}
}
}

0 comments on commit c4c078b

Please sign in to comment.