Выбор объекта на холсте 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)

Решение

Все они 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.
            }
        }
    }
}