Skip to content

Commit

Permalink
Merge branch 'master' into fix/recycled-cells-not-getting-layed-out-c…
Browse files Browse the repository at this point in the history
…orrectly
  • Loading branch information
grokys authored Nov 5, 2024
2 parents 4ffa527 + d4a77ff commit bcf842a
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Avalonia.Media;
using System.Globalization;

using Avalonia.Media;

namespace Avalonia.Controls.Models.TreeDataGrid
{
Expand All @@ -21,7 +23,8 @@ public interface ITextCell : ICell
/// Gets the cell's text wrapping mode.
/// </summary>
TextWrapping TextWrapping { get; }


/// <summary>
/// Gets the cell's text alignment mode.
/// </summary>
TextAlignment TextAlignment { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
using Avalonia.Media;
using System.Globalization;

using Avalonia.Media;

namespace Avalonia.Controls.Models.TreeDataGrid
{
public interface ITextCellOptions : ICellOptions
{
/// <summary>
/// Gets the format string to be used to format the cell value.
/// </summary>
string StringFormat { get; }

/// <summary>
/// Gets the culture to be used in conjunction with <see cref="StringFormat"/>.
/// </summary>
CultureInfo Culture { get; }

/// <summary>
/// Gets the text trimming mode for the cell.
/// </summary>
Expand Down
47 changes: 31 additions & 16 deletions src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/TextCell.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reactive.Subjects;
using Avalonia.Data;
using Avalonia.Media;
Expand All @@ -11,11 +10,11 @@ namespace Avalonia.Controls.Models.TreeDataGrid
public class TextCell<T> : NotifyingBase, ITextCell, IDisposable, IEditableObject
{
private readonly ISubject<BindingValue<T>>? _binding;
private readonly ITextCellOptions? _options;
private readonly IDisposable? _subscription;
[AllowNull] private T? _value;
[AllowNull] private T? _cancelValue;
private string? _editText;
private T? _value;
private bool _isEditing;
private ITextCellOptions? _options;

public TextCell(T? value)
{
Expand Down Expand Up @@ -48,15 +47,31 @@ public TextCell(

public string? Text
{
get => _value?.ToString();
set{
if (string.IsNullOrEmpty(value))
get
{
if (_isEditing)
return _editText;
else if (_options?.StringFormat is { } format)
return string.Format(_options.Culture ?? CultureInfo.CurrentCulture, format, _value);
else
return _value?.ToString();
}
set
{
if (_isEditing)
{
Value = default(T?);
_editText = value;
}
else
{
Value = (T?)Convert.ChangeType(value, typeof(T));
try
{
Value = (T?)Convert.ChangeType(value, typeof(T));
}
catch
{
// TODO: Data validation errors.
}
}
}
}
Expand All @@ -78,27 +93,27 @@ public void BeginEdit()
if (!_isEditing && !IsReadOnly)
{
_isEditing = true;
_cancelValue = Value;
_editText = Text;
}
}

public void CancelEdit()
{
if (_isEditing)
{
Value = _cancelValue;
_isEditing = false;
_cancelValue = default;
_editText = null;
}
}

public void EndEdit()
{
if (_isEditing && !EqualityComparer<T>.Default.Equals(_value, _cancelValue))
if (_isEditing)
{
var text = _editText;
_isEditing = false;
_cancelValue = default;
_binding!.OnNext(_value!);
_editText = null;
Text = text;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Avalonia.Media;
using System.Globalization;

using Avalonia.Media;

namespace Avalonia.Controls.Models.TreeDataGrid
{
Expand All @@ -13,6 +15,16 @@ public class TextColumnOptions<TModel> : ColumnOptions<TModel>, ITextCellOptions
/// </summary>
public bool IsTextSearchEnabled { get; set; }

/// <summary>
/// Gets or sets the format string for the cells in the column.
/// </summary>
public string StringFormat { get; set; } = "{0}";

/// <summary>
/// Culture info used in conjunction with <see cref="StringFormat"/>
/// </summary>
public CultureInfo Culture { get; set; } = CultureInfo.CurrentCulture;

/// <summary>
/// Gets or sets the text trimming mode for the cells in the column.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ protected void CancelEdit()
protected void EndEdit()
{
if (EndEditCore() && Model is IEditableObject editable)
{
editable.EndEdit();
UpdateValue();
}
}

protected void SubscribeToModelChanges()
Expand All @@ -108,6 +111,10 @@ protected void UnsubscribeFromModelChanges()
inpc.PropertyChanged -= OnModelPropertyChanged;
}

protected virtual void UpdateValue()
{
}

protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
_treeDataGrid = this.FindLogicalAncestorOfType<TreeDataGrid>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Controls.Selection;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;

namespace Avalonia.Controls.Primitives
Expand Down Expand Up @@ -64,14 +64,15 @@ public TextAlignment TextAlignment
get => _textAlignment;
set => SetAndRaise(TextAlignmentProperty, ref _textAlignment, value);
}

public override void Realize(
TreeDataGridElementFactory factory,
ITreeDataGridSelectionInteraction? selection,
ICell model,
int columnIndex,
int rowIndex)
{
Value = model.Value?.ToString();
Value = (model as ITextCell)?.Text;
TextTrimming = (model as ITextCell)?.TextTrimming ?? TextTrimming.CharacterEllipsis;
TextWrapping = (model as ITextCell)?.TextWrapping ?? TextWrapping.NoWrap;
TextAlignment = (model as ITextCell)?.TextAlignment ?? TextAlignment.Left;
Expand All @@ -85,6 +86,11 @@ public override void Unrealize()
base.Unrealize();
}

protected override void UpdateValue()
{
Value = (Model as ITextCell)?.Text;
}

protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Expand Down
45 changes: 43 additions & 2 deletions tests/Avalonia.Controls.TreeDataGrid.Tests/Models/TextCellTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public void Modified_Value_Is_Written_To_Binding_On_EndEdit()
target.Text = "new";

Assert.Equal("new", target.Text);
Assert.Equal("new", target.Value);
Assert.Equal("initial", target.Value);
Assert.Equal(new[] { "initial"}, result);

target.EndEdit();
Expand All @@ -86,7 +86,7 @@ public void Modified_Value_Is_Not_Written_To_Binding_On_CancelEdit()
target.Text = "new";

Assert.Equal("new", target.Text);
Assert.Equal("new", target.Value);
Assert.Equal("initial", target.Value);
Assert.Equal(new[] { "initial" }, result);

target.CancelEdit();
Expand All @@ -95,5 +95,46 @@ public void Modified_Value_Is_Not_Written_To_Binding_On_CancelEdit()
Assert.Equal("initial", target.Value);
Assert.Equal(new[] { "initial" }, result);
}

public class StringFormat
{
[AvaloniaFact(Timeout = 10000)]
public void Initial_Int_Value_Is_Formatted()
{
var binding = new BehaviorSubject<BindingValue<int>>(42);
var target = new TextCell<int>(binding, true, GetOptions());

Assert.Equal("42.00", target.Text);
Assert.Equal(42, target.Value);
}

[AvaloniaFact(Timeout = 10000)]
public void Int_Value_Is_Formatted_After_Editing()
{
var binding = new BehaviorSubject<BindingValue<int>>(42);
var target = new TextCell<int>(binding, false, GetOptions());
var result = new List<int>();

binding.Subscribe(x => result.Add(x.Value));

target.BeginEdit();
target.Text = "43";

Assert.Equal("43", target.Text);
Assert.Equal(42, target.Value);
Assert.Equal(new[] { 42 }, result);

target.EndEdit();

Assert.Equal("43.00", target.Text);
Assert.Equal(43, target.Value);
Assert.Equal(new[] { 42, 43 }, result);
}

private ITextCellOptions? GetOptions(string format = "{0:n2}")
{
return new TextColumnOptions<int> { StringFormat = format };
}
}
}
}

0 comments on commit bcf842a

Please sign in to comment.