В проекте библиотеки я использую следующие пакеты 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;
}
}
Код: Выделить всё
Код: Выделить всё
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 следующим образом:
Код: Выделить всё
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);
}
Ничего не работает, и у меня больше нет идей. Ни для ChatGPT, ни для Claude AI.
Как сделать так, чтобы элементы DataGrid отображались?
Подробнее здесь: https://stackoverflow.com/questions/798 ... owing-rows
Мобильная версия