Виртуализация WPF DataGrid – странная ошибка после прокруткиC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Виртуализация WPF DataGrid – странная ошибка после прокрутки

Сообщение Anonymous »

Я столкнулся с проблемой и не могу двигаться дальше.
Надеюсь, вы мне поможете.
Краткое объяснение:
У меня есть DataGrid (VirtualizingPanel.IsVirtualizing="true") и панель поиска. Когда я вводю что-то в строку поиска, список соответствующим образом фильтруется, а текст поиска выделяется с помощью AttachedProperty.
Выделение осуществляется путем разделения текста TextBlock на несколько строк. Затем во строках, содержащих искомый текст, устанавливается соответствующий цвет фона.
Работает нормально:
[img]https://i.sstatic .net/ULYSVnED.png[/img]

Я проверил событие LoadingRow Grid и увидел, что строка, попадающая в видимую область, содержит правильные данные в DataContext, но тексты в TextBlocks не обновились.
Я подумал, что, возможно, привязка была нарушена из-за манипуляций со встроенными строками, но, похоже, проблема не в этом.
Изображение

Если для параметра EnableRowVirtualization установлено значение ложь, это работает, но, к сожалению, виртуализация абсолютно необходима, поскольку список может содержать n записей, текущая оценка составляет до 5000.
В начале метода HighlightTextBlock(TextBlock) вызов txtBlock.GetBindingExpression(TextBlock.TextProperty) возвращает соответствующие данные, но в В конце метода после установки встроенных строк txtBlock.GetBindingExpression(TextBlock.TextProperty) возвращает значение null.
Разрушило ли это привязку? Это объясняет, почему в GridOnLoadingRow DataContext содержатся новые данные, а TextBlocks по-прежнему содержит старые.
Надеюсь, вы мне поможете, ниже приведен код моего тестового проекта.

Formular.xaml Formular.xaml.cs

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

public partial class Formular : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { };

public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion

public ICollectionView DisplayedItems { get; set; }

private string filter;
public string Filter
{
get =>  this.filter;
set
{
this.filter = value;

this.DisplayedItems.Refresh();
this.RaisePropertyChanged();
}
}

public Formular()
{
InitializeComponent();

this.DataContext = this;

var listItems = new ObservableCollection()
{
new MyListItem("Alpha", "Mission1"),
new MyListItem("Beta1", "Mission1"),
new MyListItem("Beta1", "Mission2"),
new MyListItem("Beta1", "Mission3"),
new MyListItem("Beta1", "Mission4"),
new MyListItem("Beta1", "Mission5"),
new MyListItem("Beta1", "Mission6"),
new MyListItem("Beta1", "Mission7"),
new MyListItem("Beta1", "Mission8"),
new MyListItem("Beta1", "Mission9"),
new MyListItem("Beta2", "Mission2"),
};

this.DisplayedItems = CollectionViewSource.GetDefaultView(listItems);
this.DisplayedItems.Filter = this.FilterCallback;
}

public bool FilterCallback(object obj)
{
var item = (MyListItem) obj;

return string.IsNullOrEmpty(this.Filter)
|| item.Name.ToUpper().Contains(Filter.ToUpper())
|| item.MissionName.ToUpper().Contains(Filter.ToUpper());
}
}
Highlighter.cs

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

public static class Highlighter
{
private static string filter;

static Highlighter(){}

#region Filter
public static readonly DependencyProperty FilterProperty =
DependencyProperty.RegisterAttached("Filter", typeof(string), typeof(Highlighter), new PropertyMetadata("", PropertyChangedCallback));

public static void SetFilter(DependencyObject obj, string value)
{
obj.SetValue(FilterProperty, value);
}

public static string GetFilter(DependencyObject obj)
{
return (string)obj?.GetValue(FilterProperty);
}

private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => DoAction(d)));
}
#endregion

private static void DoAction(DependencyObject d)
{
filter = GetFilter(d);
if (filter == null)
{
return;
}

var grid = (DataGrid)d;
grid.LoadingRow += GridOnLoadingRow;

// Get DataGridRows
var gridRows = grid.GetDescendants().ToList();
foreach (var row in gridRows)
{
HighlightRow(row);
}
}

private static void HighlightRow(DataGridRow row)
{
// Get TextBlocks
var txtBlocks = row.GetDescendants().ToList();
if (!txtBlocks.Any())
{
return;
}

foreach (var txtBlock in txtBlocks)
{
HighlightTextBlock(txtBlock);
}
}

private static void HighlightTextBlock(TextBlock txtBlock)
{
var text = txtBlock.Text;
if (string.IsNullOrEmpty(text))
{
return;
}

// Check whether the text contains the filter text
var index = text.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase);
if (index <  0)
{
// Filter text not found
return;
}

// Generate Inlines with highlighting information
var inlines = new List();
while (true)
{
// Text from beginning to filter text
inlines.Add(new Run(text.Substring(0, index)));

// Text that corresponds to the filter text
inlines.Add(new Run(text.Substring(index, filter.Length))
{
Background = Brushes.Yellow
});

// Text from filter text to ending
text = text.Substring(index + filter.Length);

// Check whether the remaining text also contains the filter text
index = text.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase);
if (index < 0)
{
// If not, add remaining text and exit loop
inlines.Add(new Run(text));
break;
}
}

// Replace Inlines
txtBlock.Inlines.Clear();
txtBlock.Inlines.AddRange(inlines);
}

private static void GridOnLoadingRow(object sender, DataGridRowEventArgs e)
{
var dataContext = (MyListItem) e.Row.DataContext;

var newData = $"{dataContext.Name}_{dataContext.MissionName}";
var oldData = string.Join("_", e.Row.GetDescendants().Select(t => t.Text).ToList());
}
}
MyListItem.cs

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

public class MyListItem : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { };

public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion

public string name;
public string Name
{
get => name;
set
{
this.name = value;
this.RaisePropertyChanged();
}
}

public string missionName;
public string MissionName
{
get => missionName;
set
{
this.missionName = value;
this.RaisePropertyChanged();
}
}

public MyListItem(string name, string missionName)
{
this.Name = name;
this.MissionName = missionName;
}
}
Я не знаю, что я могу сделать.

Я проверил другие ответы, но у меня сложилось впечатление, что ничто не подходит для моей проблемы.

Подробнее здесь: https://stackoverflow.com/questions/792 ... -scrolling
Реклама
Ответить Пред. темаСлед. тема

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Виртуализация WPF DataGrid – странная ошибка после прокрутки
    Anonymous » » в форуме C#
    0 Ответы
    19 Просмотры
    Последнее сообщение Anonymous
  • WPF — виртуализация Treeview и ContentControl
    Anonymous » » в форуме C#
    0 Ответы
    45 Просмотры
    Последнее сообщение Anonymous
  • Как объединить GridSplitter и DataGrid, где DataGrid должен иметь вертикальную полосу прокрутки?
    Anonymous » » в форуме C#
    0 Ответы
    116 Просмотры
    Последнее сообщение Anonymous
  • Как изменить стили прокрутки DataGrid DataGrid MUI-X?
    Anonymous » » в форуме Javascript
    0 Ответы
    9 Просмотры
    Последнее сообщение Anonymous
  • Вложенная виртуализация KVM: kvm-adm или kvm_amd? [закрыто]
    Anonymous » » в форуме Linux
    0 Ответы
    35 Просмотры
    Последнее сообщение Anonymous

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