DataGrid библиотеки Avalonia не показывает строкиC#

Место общения программистов C#
Ответить
Anonymous
 DataGrid библиотеки Avalonia не показывает строки

Сообщение Anonymous »

Я пытаюсь создать элемент управления Avalonia для использования в библиотеке. Предполагается, что элемент управления можно напрямую привязывать к DataTable и отображать содержимое в сетке с текстовыми поляминад каждым столбцом, которые будут использоваться в качестве фильтров для значений в этом столбце. Мне удалось сделать так, чтобы отображались фильтры TextBox, и во время отладки я вижу, что столбцы также создаются, но строки не отображаются, и я не могу понять, почему. Я не такой уж знаток Авалонии и перепробовал все, что только мог придумать.
В проекте библиотеки я использую следующие пакеты nuget: Первая попытка:

Код: Выделить всё

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Layout;
using Avalonia.LogicalTree;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace AvaloniaLibrary;

public class FilterableDataTableGrid : ContentControl
{
DataTable sourceDataTable;
DataView filteredDataView;
DataGrid dataGrid;
StackPanel filterPanel;
Dictionary columnFilters = new();

public static readonly StyledProperty DataSourceProperty =
AvaloniaProperty.Register(nameof(DataSource));

public DataTable DataSource
{
get => GetValue(DataSourceProperty);
set => SetValue(DataSourceProperty, value);
}

public FilterableDataTableGrid()
{
DataSourceProperty.Changed.AddClassHandler(OnDataSourceChanged);
}

static void OnDataSourceChanged(FilterableDataTableGrid control, AvaloniaPropertyChangedEventArgs e)
{
if (e.NewValue is DataTable dataTable)
{
control.LoadDataTable(dataTable);
}
}

protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
BuildControl();
}

void BuildControl()
{
var mainPanel = new StackPanel { Orientation = Orientation.Vertical };

filterPanel = new StackPanel { Orientation = Orientation.Horizontal, Height = 30 };

dataGrid = new DataGrid
{
IsReadOnly = true,
CanUserSortColumns = true,
CanUserResizeColumns = true,
CanUserReorderColumns = true,
GridLinesVisibility = DataGridGridLinesVisibility.All,
HorizontalScrollBarVisibility = Avalonia.Controls.Primitives.ScrollBarVisibility.Auto,
VerticalScrollBarVisibility = Avalonia.Controls.Primitives.ScrollBarVisibility.Auto
};

mainPanel.Children.Add(filterPanel);
mainPanel.Children.Add(dataGrid);

Content = mainPanel;

if (DataSource != null)
{
LoadDataTable(DataSource);
}
}

void LoadDataTable(DataTable dataTable)
{
if (dataGrid == null || filterPanel == null)
return;

sourceDataTable = dataTable;
filteredDataView = dataTable.DefaultView;

dataGrid.Columns.Clear();
filterPanel.Children.Clear();
columnFilters.Clear();

foreach (DataColumn column in dataTable.Columns)
{
CreateColumnFilter(column);
CreateDataGridColumn(column);
}

dataGrid.ItemsSource = filteredDataView;
}

void CreateColumnFilter(DataColumn column)
{
var filterBox = new TextBox
{
Watermark = $"Filter {column.ColumnName}",
Width = 150,
Margin = new Thickness(2)
};

filterBox.TextChanged += (s, e) =>  ApplyFilters();
columnFilters[column.ColumnName] = filterBox;
filterPanel.Children.Add(filterBox);
}

void CreateDataGridColumn(DataColumn column)
{
var gridColumn = new DataGridTextColumn
{
Header = column.ColumnName,
Binding = new Binding($"[{column.ColumnName}]"),
Width = new DataGridLength(150),
CanUserSort = true,
CanUserResize = true,
CanUserReorder = true
};

dataGrid.Columns.Add(gridColumn);
}

void ApplyFilters()
{
if (filteredDataView == null)
return;

var filterExpressions = new List();

foreach (var kvp in columnFilters)
{
string columnName = kvp.Key;
string filterText = kvp.Value.Text;

if (!string.IsNullOrWhiteSpace(filterText))
{
string escapedFilter = filterText.Replace("'", "''");
filterExpressions.Add($"Convert([{columnName}], 'System.String') LIKE '%{escapedFilter}%'");
}
}

filteredDataView.RowFilter = filterExpressions.Count > 0
? string.Join(" AND ", filterExpressions)
: string.Empty;
}
}
затем я добавляю проект Avalonia MVVM, ссылаюсь на проект AvaloniaLibrary и делаю это в MainWindow.axaml: и это в MainWindowViewModel.cs:

Код: Выделить всё

using CommunityToolkit.Mvvm.ComponentModel;
using System.Data;

namespace AvaloniaApplication1.ViewModels;

public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
DataTable items;

public MainWindowViewModel()
{
DataTable table = new DataTable();
table.Columns.Add("ID", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Age", typeof(int));
table.Rows.Add(1, "Alice", 30);
table.Rows.Add(2, "Bob", 25);
table.Rows.Add(3, "Charlie", 35);

Items = table;
}
}
и я получаю это при запуске:
Изображение

Что я пробовал (безрезультатно):
  • Изменить ContentControl на UserControl
  • Добавить отладку регистрация количества столбцов и строк в DataGrid (журналы показали, что 3 столбца и 3 строки были связаны)
  • Удалить метод OnApplyTemplate и переместить BuildControl(); в конструктор
  • Добавлен && control.dataGrid != null в if (e.NewValue is DataTable dataTable)
  • Изменить filteredDataView = dataTable.DefaultView; на filteredDataView = new DataView(dataTable);
  • Изменить Binding = new Binding($"[{column.ColumnName}]"), на Binding = new Binding($"Row.ItemArray[{column.Ordinal}]"), затем на Binding = new Binding(column.ColumnName),
  • Попробуйте использовать Items вместо ItemsSource в DataGrid, но, несмотря на то, что во многих местах в Интернете утверждается, что это правильное свойство, в моем оно не существует.
  • Измените DataView на оболочки объектов, например:

Код: Выделить всё

DataView filteredDataView;
до

Код: Выделить всё

ObservableCollection allRows;

Код: Выделить всё

ObservableCollection  filteredRows;
и следующие методы:

Код: Выделить всё

void LoadDataTable(DataTable dataTable)
{
sourceDataTable = dataTable;

dataGrid.Columns.Clear();
filterPanel.Children.Clear();
columnFilters.Clear();

allRows = new ObservableCollection();
filteredRows = new ObservableCollection();

foreach (DataRow row in dataTable.Rows)
{
var expando = new ExpandoObject();
var expandoDict = (IDictionary)expando;

foreach (DataColumn column in dataTable.Columns)
{
expandoDict[column.ColumnName] = row[column];
}

allRows.Add(expando);
filteredRows.Add(expando);
}

foreach (DataColumn column in dataTable.Columns)
{
CreateColumnFilter(column);
CreateDataGridColumn(column);
}

dataGrid.ItemsSource = filteredRows;

System.Diagnostics.Debug.WriteLine($"Loaded DataTable with {dataTable.Rows.Count} rows and {dataTable.Columns.Count} columns");
System.Diagnostics.Debug.WriteLine($"DataGrid has {dataGrid.Columns.Count} columns");
System.Diagnostics.Debug.WriteLine($"Filtered collection has {filteredRows.Count} items");
}

void ApplyFilters()
{
if (allRows == null)
return;

filteredRows.Clear();

foreach (var row in allRows)
{
var rowDict = (IDictionary)row;
bool matches = true;

foreach (var kvp in columnFilters)
{
string columnName = kvp.Key;
string filterText = kvp.Value.Text;

if (!string.IsNullOrWhiteSpace(filterText))
{
if (!rowDict.ContainsKey(columnName))
{
matches = false;
break;
}

string cellValue = rowDict[columnName]?.ToString() ?? string.Empty;
if (!cellValue.Contains(filterText, StringComparison.OrdinalIgnoreCase))
{
matches = false;
break;
}
}
}

if (matches)
{
filteredRows.Add(row);
}
}
}
  • Измените родительский элемент DataGrid со StackPanel на Grid следующим образом:
(заполнитель Markdown)

Код: Выделить всё

void BuildControl()
{
var grid = new Grid
{
RowDefinitions =
{
new RowDefinition(GridLength.Auto),
new RowDefinition(GridLength.Star)
}
};

filterPanel = new StackPanel
{
Orientation = Orientation.Horizontal,
Height = 30
};

dataGrid = new DataGrid
{
IsReadOnly = true,
CanUserSortColumns = true,
CanUserResizeColumns = true,
CanUserReorderColumns = true,
GridLinesVisibility = DataGridGridLinesVisibility.All,
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
VerticalScrollBarVisibility = ScrollBarVisibility.Auto
};

Grid.SetRow(filterPanel, 0);
Grid.SetRow(dataGrid, 1);

grid.Children.Add(filterPanel);
grid.Children.Add(dataGrid);

Content = grid;

if (DataSource != null)
LoadDataTable(DataSource);
}
также пробовал изменить новое RowDefinition(GridLength.Star) на новое RowDefinition(60, GridUnitType.Pixel), все равно ничего
Ничего не работает, и у меня больше нет идей. Ни для ChatGPT, ни для Claude AI.
Как сделать так, чтобы элементы DataGrid отображались?

Подробнее здесь: https://stackoverflow.com/questions/798 ... owing-rows
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»