Merge branch 'master' into fix/recycled-cells-not-getting-layed-out-correctly
This commit is contained in:
Коммит
bcf842af94
|
@ -1,4 +1,6 @@
|
|||
using Avalonia.Media;
|
||||
using System.Globalization;
|
||||
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace Avalonia.Controls.Models.TreeDataGrid
|
||||
{
|
||||
|
@ -21,7 +23,8 @@ namespace Avalonia.Controls.Models.TreeDataGrid
|
|||
/// Gets the cell's text wrapping mode.
|
||||
/// </summary>
|
||||
TextWrapping TextWrapping { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cell's text alignment mode.
|
||||
/// </summary>
|
||||
TextAlignment TextAlignment { get; }
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -48,15 +47,31 @@ namespace Avalonia.Controls.Models.TreeDataGrid
|
|||
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +93,7 @@ namespace Avalonia.Controls.Models.TreeDataGrid
|
|||
if (!_isEditing && !IsReadOnly)
|
||||
{
|
||||
_isEditing = true;
|
||||
_cancelValue = Value;
|
||||
_editText = Text;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,19 +101,19 @@ namespace Avalonia.Controls.Models.TreeDataGrid
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using Avalonia.Media;
|
||||
using System.Globalization;
|
||||
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace Avalonia.Controls.Models.TreeDataGrid
|
||||
{
|
||||
|
@ -13,6 +15,16 @@ namespace Avalonia.Controls.Models.TreeDataGrid
|
|||
/// </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>
|
||||
|
|
|
@ -93,7 +93,10 @@ namespace Avalonia.Controls.Primitives
|
|||
protected void EndEdit()
|
||||
{
|
||||
if (EndEditCore() && Model is IEditableObject editable)
|
||||
{
|
||||
editable.EndEdit();
|
||||
UpdateValue();
|
||||
}
|
||||
}
|
||||
|
||||
protected void SubscribeToModelChanges()
|
||||
|
@ -108,6 +111,10 @@ namespace Avalonia.Controls.Primitives
|
|||
inpc.PropertyChanged -= OnModelPropertyChanged;
|
||||
}
|
||||
|
||||
protected virtual void UpdateValue()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
_treeDataGrid = this.FindLogicalAncestorOfType<TreeDataGrid>();
|
||||
|
|
|
@ -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
|
||||
|
@ -64,6 +64,7 @@ namespace Avalonia.Controls.Primitives
|
|||
get => _textAlignment;
|
||||
set => SetAndRaise(TextAlignmentProperty, ref _textAlignment, value);
|
||||
}
|
||||
|
||||
public override void Realize(
|
||||
TreeDataGridElementFactory factory,
|
||||
ITreeDataGridSelectionInteraction? selection,
|
||||
|
@ -71,7 +72,7 @@ namespace Avalonia.Controls.Primitives
|
|||
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;
|
||||
|
@ -85,6 +86,11 @@ namespace Avalonia.Controls.Primitives
|
|||
base.Unrealize();
|
||||
}
|
||||
|
||||
protected override void UpdateValue()
|
||||
{
|
||||
Value = (Model as ITextCell)?.Text;
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace Avalonia.Controls.TreeDataGridTests.Models
|
|||
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();
|
||||
|
@ -86,7 +86,7 @@ namespace Avalonia.Controls.TreeDataGridTests.Models
|
|||
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();
|
||||
|
@ -95,5 +95,46 @@ namespace Avalonia.Controls.TreeDataGridTests.Models
|
|||
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 };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче