#c# #.net #wpf #optimization
#c# #.net #wpf #оптимизация
Вопрос:
У меня есть компонент WPF, показывающий коллекцию Equipments
. Каждый из них Equipments
содержит один или более Coordinate
. В MouseMove
моем компоненте вызывается функция, проверяющая, находится ли мышь в данный момент в пределах границ любого Coordinate
из любых Equipment
. Если это так, то Equipment
в вопросе возвращается указание на то, что должно быть показано всплывающее окно с текстовой информацией о Equipment
.
Помимо этого, все Coordinates
содержат ImageDrawing
, для каждого из которых Equipment
отображается символ (символ, на который пользователь наводит курсор мыши, чтобы увидеть всплывающий текст). Они помещены в отдельный DrawingGroup
для ускорения рендеринга. Еще одним преимуществом этого является то, что если некоторые из них Equipments
должны быть скрыты, мы можем просто удалить их Coordinates' ImageDrawing
из DrawingGroup
, и они все равно останутся в списке Equipments
(как и должны быть).
Однако это не мешает отображению всплывающего окна при наведении курсора мыши на Coordinate
, поскольку оно отделено от DrawingGroup
. Итак, чтобы проверить, должно ли отображаться текстовое всплывающее окно, я должен проверить, находится ли мышь в пределах любого Coordinate
, а также проверить, есть ли ImageDrawing
для этого Coordinate
в DrawingGroup
.
Переходя к моему вопросу (tl; dr): какой способ перебора всех этих элементов был бы самым быстрым? У меня есть :
List<Equipment> equipments;
И для каждого из них (этот список в 9 случаях из 10 содержит один элемент и никогда не более пяти)
List<Coordinate> coordinates;
Для каждого из них Coordinates
я должен проверить, есть ли их ImageDrawing
в DrawingCollection
(что в данном случае является DrawingGroup.Children
), который, согласно msdn, является ordered collection of Drawing objects.
Чтобы сделать это, я начал с этого:
foreach (Equipment equipment in equipments)
{
foreach (Coordinate coordinate in equipment.Coordinates)
{
ImageDrawing image = coordinate.ImageDrawing;
if (image != null)
{
if (currentDrawingGroup.Children.Contains(image))
{
if (image.Rect.Bottom > y amp;amp;
image.Rect.Top < y amp;amp;
image.Rect.Left < x amp;amp;
image.Rect.Right > x)
{
return equipment;
}
}
}
}
}
Но подумал, что это становится для многих итераций в тех случаях, когда скрыто много оборудования, и что я мог бы изменить это на это (поскольку Children.Contains(image)
в любом случае, итерация за кулисами, вероятно, выполняется):
foreach (var child in currentDrawingGroup.Children)
{
foreach (Equipment equipment in equipments)
{
foreach (Coordinate coordinate in equipment.Coordinates)
{
ImageDrawing image = coordinate.ImageDrawing;
if (image != null)
{
if (image == child)
{
if (image.Rect.Bottom > y amp;amp;
image.Rect.Top < y amp;amp;
image.Rect.Left < x amp;amp;
image.Rect.Right > x)
{
return equipment;
}
}
}
}
}
}
Я знаю, что этот вопрос слишком длинный, и оптимизации, которые я рассматриваю здесь, вероятно, не имеют большого значения в долгосрочной перспективе. Но есть ли способ, которым это можно было бы сделать без такого количества циклов в циклах? Я чувствую, что где-то должно быть LINQ-выражение, помогающее мне, хотя я не знаю, работает ли какое-либо из них быстрее, чем цикл foreach. Способ сортировки объектов ( Equipments
скрытие путем удаления их из DrawingGroup
и тому подобное) находится вне моего контроля, и его трудно изменить. Заранее большое спасибо.
Комментарии:
1. Вы оценили свои подходы с
System.Diagnostics.Stopwatch
? С помощью этого вы можете выяснить, какой подход является самым быстрым.2. Итак, чего именно вы хотите? Меньше кода или быстрее время выполнения?
3. Я предполагаю, что мой вопрос двоякий: моя главная забота, как всегда, заключается в удобочитаемости, но я не хочу, чтобы это требовало слишком больших затрат на производительность. Я, вероятно, надеялся, что будет более читаемое решение, чем любое, которое я мог бы придумать в любом случае. Я проверю с помощью секундомера, чтобы увидеть, есть ли большая разница!
Ответ №1:
если какое-то оборудование должно быть скрыто, не было бы чище позволить оборудованию самому управлять его видимостью? Таким образом, вы просто спрашиваете оборудование, видно ли оно в первую очередь, и пропускаете его, если нет?
Таким образом, ваше оборудование также всегда присутствует, но видно или нет, и при наведении на него курсора мыши вам не придется проверять, находятся ли координаты в DrawingGroup или нет … это уже обработано за вас.
Что касается итерации vs Contains()
, функция contains представляет собой линейный поиск, поэтому она будет такой же, как итерация по списку.
Комментарии:
1. Это хорошее решение, но, к сожалению, в данном случае неприменимо. Поскольку это работает сейчас, это оборудование может отображаться сразу в нескольких разных местах (назовем их картами), и установка оборудования как скрытого на одной карте скрыла бы его на всех других. Решение с DrawingGroups было принято, поскольку каждая карта имеет свою собственную DrawingGroup. Отвратительно, я знаю, но трудно изменить (это большой проект, и это всего лишь крошечная его часть).
2. Я принимаю этот ответ, поскольку он отвечает на мой первоначальный вопрос; любая разница между Contains() и итерацией. Что угодно, но только не читаемость.