Выбор объекта на холсте WPF?
У меня есть холст WPF с некоторыми объектами Ellipse (отображаются в виде кружков). Каждый круг взят из экземпляра класса коллекции, который на самом деле является классом настраиваемого шаблона отверстий. В каждом шаблоне есть определенное количество кругов, и каждый круг затем добавляется на холст с помощью итерации по коллекции с использованием приведенного ниже кода.
Итак, холст заполнен кучей кругов, и каждый круг принадлежит определенному экземпляру узора. Вы можете увидеть снимок экрана здесь: http://twitpic.com/1f2ci/full
Теперь я хочу добавить возможность щелкнуть круг на холсте и иметь возможность определять коллекцию, к которой он принадлежит, чтобы затем я мог еще немного поработать с выбранным шаблоном, которому принадлежит этот круг.
public void DrawHoles()
{
// Iterate over each HolePattern in the HolePatterns collection...
foreach (HolePattern HolePattern in HolePatterns)
{
// Now iterate over each Hole in the HoleList of the current HolePattern...
// This code adds the HoleEntity, HoleDecorator, and HoleLabel to the canvas
foreach (Hole Hole in HolePattern.HoleList)
{
Hole.CanvasX = SketchX0 + (Hole.AbsX * _ZoomScale);
Hole.CanvasY = SketchY0 - (Hole.AbsY * _ZoomScale);
canvas1.Children.Add(Hole.HoleEntity);
}
}
}
Ответов (3)3
Все они FrameworkElements
имеют Tag
свойство типа object, которое можно использовать для хранения произвольной информации. Вы можете назначить HolePattern
на Tag
собственность и легко использовать , что позже , чтобы получить соответствующую коллекцию.
то есть:
...
Hole.HoleEntity.Tag = HolePattern as object;
canvas1.Children.Add(Hole.HoleEntity);
позже в событии щелчка:
event(object sender,....)
{
Ellipse e = sender as Ellipse;
HolePattern hp = e.Tag as HolePattern;
...
}
Так что вы, наверное, уже читали мой ответ, где я сказал, что это работает. И он работает отлично (за исключением того, что требует большой точности с мышью), но я хочу спросить вот что: действительно ли разумно добавлять обработчик событий к КАЖДОМУ эллипсу, который добавляется на холст? Теперь я не знаю, что это за трясина памяти, или, может быть, это пустяк для WPF и Windows.
В практическом случае, я предполагаю, что даже на экране с несколькими рисунками будет не более 30-50 отверстий, но все же; ПЯТЬДЕСЯТ обработчиков событий? Это просто кажется страшным. И на самом деле каждая «дыра» визуально представлена двумя концентрическими кругами и текстовой меткой (см. Снимок экрана здесь: http://twitpic.com/1f2ci/full ), и я знаю, что пользователь ожидает, что сможет щелкнуть по любой из этих элементов, чтобы выбрать отверстие. Это означает, что обработчик событий по 3 элемента для каждой дыры. Теперь мы можем говорить о 100 или более обработчиках событий.
Похоже, должно быть решение, в котором вы могли бы иметь только один обработчик событий на холсте и читать ссылку на элемент под мышью, а затем работать над этим, чтобы получить свойство .Tag этого элемента и так далее.
Я подумал, что опубликую свое окончательное и более усовершенствованное решение на случай, если оно кому-то поможет.
void canvas1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
int ClickMargin = 2;// Adjust here as desired. Span is in both directions of selected point.
var ClickMarginPointList = new Collection<Point>();
Point ClickedPoint = e.GetPosition(canvas1);
Point ClickMarginPoint=new Point();
for (int x = -1 * ClickMargin; x <= ClickMargin; x++)
{
for (int y = -1 * ClickMargin; y <= ClickMargin; y++)
{
ClickMarginPoint.X = ClickedPoint.X + x;
ClickMarginPoint.Y = ClickedPoint.Y + y;
ClickMarginPointList.Add(ClickMarginPoint);
}
}
foreach (Point p in ClickMarginPointList)
{
HitTestResult SelectedCanvasItem = System.Windows.Media.VisualTreeHelper.HitTest(canvas1, p);
if (SelectedCanvasItem.VisualHit.GetType().BaseType == typeof(Shape))
{
var SelectedShapeTag = SelectedCanvasItem.VisualHit.GetValue(Shape.TagProperty);
if (SelectedShapeTag!=null && SelectedShapeTag.GetType().BaseType == typeof(Hole))
{
Hole SelectedHole = (Hole)SelectedShapeTag;
SetActivePattern(SelectedHole.ParentPattern);
SelectedHole.ParentPattern.CurrentHole = SelectedHole;
return; //Get out, we're done.
}
}
}
}