Вопрос или проблема
У меня есть приложение .Net 8.0 / AvalonuaUI для редактирования таблиц с использованием CommunityToolkit для MVVM.
Конфигурация таблицы определяется во время выполнения. Поэтому я связываю DataGrid с коллекцией object[]
, а затем создаю столбцы во время выполнения.
Мне нужно валидировать входные данные в каждом столбце особым образом.
Например, используя минимальное и максимальное значение для числовых параметров (мин и макс также определяются во время выполнения) или TimeSpan.TryParse()
для временных параметров.
Как я могу создать пользовательские валидаторы и связать их со столбцами?
На данный момент я создаю столбцы в MainWindow.axaml.cs
следующим образом
(я знаю, что это плохо для MVVM, но мне кажется, что это самый простой способ динамически создавать столбцы):
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void BuildDataGridColumns(Parameter[] structure)
{
dataGrid.Columns.Clear();
for(int i = 0; i < structure.Length; i++)
dataGrid.Columns.Add(CreateColumn(structure[i], i));
}
private DataGridColumn CreateColumn(Parameter parameter, int index)
{
switch(parameter.Type.Name)
{
case nameof(Boolean):
{
return new DataGridCheckBoxColumn() {
Header = parameter.Name,
Binding = new Binding($"[{index}]"),
IsReadOnly = false,
};
}
case nameof(Int32):
case nameof(Single):
{
return new DataGridTextColumn() {
Header = parameter.Name,
Binding = new Binding($"[{index}]"),
IsReadOnly = false
//Что-то вроде Validator = NumberValidator и т.д.
};
}
default: throw new NotImplementedException();
}
}
}
MainWindowViewModel.cs
public partial class MainWindowViewModel : ViewModelBase
{
public ObservableCollection<ObservableCollection<object?>> Rows { get; set; }
private MainWindow? _view;
//Пустой конструктор для предварительного просмотра
public MainWindowViewModel() : this(null) { }
public MainWindowViewModel(MainWindow? view)
{
_view = view;
Rows = [[123, 172.32f, true], [321, 3.14f, false], [567, 2.71f, true]];
Parameter[] structure = new Parameter[] {
new Parameter("Int", typeof(Int32)),
new Parameter("Float", typeof(Single)),
new Parameter("Bool", typeof(Boolean))
};
_view?.BuildDataGridColumns(structure);
}
}
Parameter.cs
public class Parameter
{
public string Name;
public Type Type;
public Parameter(string name, Type type)
{
Name = name;
Type = type;
}
}
Двусторонняя ссылка в App.axaml.cs
public partial class App : Application
{
//... сгенерированный код ...
public override void OnFrameworkInitializationCompleted()
{
if(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
BindingPlugins.DataValidators.RemoveAt(0);
MainWindow mainWindow = new MainWindow();
mainWindow.DataContext = new MainWindowViewModel(mainWindow);
desktop.MainWindow = mainWindow;
}
base.OnFrameworkInitializationCompleted();
}
}
Ответ или решение
Для добавления валидации данных в столбцы DataGrid в приложении Avalonia, разработанном с использованием .NET 8.0 и CommunityToolkit для MVVM, мы можем создать кастомные валидаторы и связанных их со столбцами динамически. Ниже представлено подробное описание процесса, включая реализацию логики валидации для различных типов данных.
Шаг 1: Определение валидатора
Первое, что вам нужно сделать, это определить интерфейс валидатора и его реализацию для различных типов данных. Например, мы можем создать валидатор для целых чисел и чисел с плавающей запятой.
public interface IValueValidator
{
bool Validate(object value);
string ErrorMessage { get; }
}
public class NumberRangeValidator : IValueValidator
{
private readonly int _min;
private readonly int _max;
public NumberRangeValidator(int min, int max)
{
_min = min;
_max = max;
}
public bool Validate(object value)
{
return value is int intValue && intValue >= _min && intValue <= _max;
}
public string ErrorMessage => $"Значение должно быть в пределах от {_min} до {_max}.";
}
public class FloatRangeValidator : IValueValidator
{
private readonly float _min;
private readonly float _max;
public FloatRangeValidator(float min, float max)
{
_min = min;
_max = max;
}
public bool Validate(object value)
{
return value is float floatValue && floatValue >= _min && floatValue <= _max;
}
public string ErrorMessage => $"Значение должно быть в пределах от {_min} до {_max}.";
}
Шаг 2: Изменение класса Parameter
Обновите класс Parameter
для хранения информации о валидаторе:
public class Parameter
{
public string Name { get; }
public Type Type { get; }
public IValueValidator? Validator { get; }
public Parameter(string name, Type type, IValueValidator? validator = null)
{
Name = name;
Type = type;
Validator = validator;
}
}
Шаг 3: Создание столбцов с валидатором
При создании столбцов в вашем методе CreateColumn
вы можете добавить логику для валидации:
private DataGridColumn CreateColumn(Parameter parameter, int index)
{
var column = new DataGridTextColumn()
{
Header = parameter.Name,
Binding = new Binding($"[{index}]"),
IsReadOnly = false
};
// Добавление обработки валидации
column.CellStyle = new Style(typeof(DataGridCell))
{
Setters =
{
new Setter(DataGridCell.BackgroundProperty, new SolidColorBrush(Colors.White))
},
Triggers =
{
new DataTrigger
{
Binding = new Binding($"[{index}]"),
Value = null,
Setters =
{
new Setter(DataGridCell.BackgroundProperty, new SolidColorBrush(Colors.Red)) // Zдесь можно поменять цвет
}
},
new DataTrigger
{
Binding = new MultiBinding
{
Converter = new ValidationConverter(parameter.Validator), // Вам нужно реализовать под вашу логику
Bindings =
{
new Binding($"[{index}]")
}
},
Value = false,
Setters =
{
new Setter(DataGridCell.BackgroundProperty, new SolidColorBrush(Colors.Red)) // Zнак неверного значения
}
}
}
};
return column;
}
Шаг 4: Реализация логики валидации в конвертере
Чтобы связать значение с вашим валидатором, создайте IValueConverter
, который будет использовать валидатор для проверки значения:
public class ValidationConverter : IMultiValueConverter
{
private readonly IValueValidator _validator;
public ValidationConverter(IValueValidator validator)
{
_validator = validator;
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var value = values[0];
return _validator.Validate(value);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Пример использования
Теперь вы можете создать экземпляр вашего параметра с использованием валидаторы при инициализации:
Parameter[] structure = new Parameter[]
{
new Parameter("Int", typeof(Int32), new NumberRangeValidator(0, 100)),
new Parameter("Float", typeof(Single), new FloatRangeValidator(0.0f, 100.0f)),
new Parameter("Bool", typeof(Boolean))
};
Заключение
Таким образом, вы сможете динамически добавлять валидацию данных в столбцы вашего DataGrid в приложении Avalonia, используя объектно-ориентированный подход и принципы MVVM. Важно помнить, что для каждой строки, ячейки и ввода данных можно использовать кастомные валидаторы, что позволит предотвратить неправильный ввод в вашем приложении. Это решение обеспечит более высокий уровень надежности и улучшит пользовательский интерфейс вашего приложения.