Laden...

BringToFront() bei XAML/WPF?

Erstellt von xbredoillex vor 14 Jahren Letzter Beitrag vor 14 Jahren 7.651 Views
X
xbredoillex Themenstarter:in
46 Beiträge seit 2009
vor 14 Jahren
BringToFront() bei XAML/WPF?

Hallo,

in dem im Anhang folgenden Codestück werden in einem Canvas zwei Figuren in jeweils einem ContentControl erzeugt, deren Größe und Position sich zur Laufzeit über Thumbs verändern lassen. Wenn man die Figuren übereinander schiebt ist immer die zuerst im Code erzeugte Figur im Vordergrund und überdeckt die andere.

Nun soll aber immer die gerade mit der Maus gepackte Figur im Vordergrund sein und beim Loslassen auch so verbleiben. BringToFront() gibt es ja nicht 😃 und irgendwie sitze ich mal wieder auf dem Schlauch.

Hat jemand einen Tip für mich?

Danke im voraus,
xbredoillex

ANHANG:

Die Code entstammt aus dem Projektordner "MoveResize" im Source-Download des Artikels http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part1.aspx und kann dort direkt als Projekt gestartet werden.


<Window x:Class="DiagramDesigner.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:s="clr-namespace:DiagramDesigner"
        WindowStartupLocation="CenterScreen"
        Title="Move and resize"
        Height="550" Width="750">
  <Window.Resources>

    <!-- MoveThumb Template -->
    <ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type s:MoveThumb}">
      <Rectangle Fill="Transparent"/>
    </ControlTemplate>

    <!-- ResizeDecorator Template -->
    <ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}">
      <Grid>
        <s:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 -4 0 0"
                       VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
        <s:ResizeThumb Width="3" Cursor="SizeWE" Margin="-4 0 0 0"
                       VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
        <s:ResizeThumb Width="3" Cursor="SizeWE" Margin="0 0 -4 0"
                       VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
        <s:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 0 0 -4"
                       VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
        <s:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0"
                       VerticalAlignment="Top" HorizontalAlignment="Left"/>
        <s:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0"
                       VerticalAlignment="Top" HorizontalAlignment="Right"/>
        <s:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6"
                       VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
        <s:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6"
                       VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
      </Grid>
    </ControlTemplate>


    <!-- Designer Item Template-->
    <ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
      <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
        <s:MoveThumb Template="{StaticResource MoveThumbTemplate}" Cursor="SizeAll"/>
        <Control Template="{StaticResource ResizeDecoratorTemplate}"/>
        <ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
      </Grid>
    </ControlTemplate>

  </Window.Resources>

  <Canvas>
    <ContentControl Width="130"
                    MinWidth="50"
                    Height="130"
                    MinHeight="50"
                    Canvas.Top="150"
                    Canvas.Left="470"
                    Template="{StaticResource DesignerItemTemplate}">
      <Ellipse Fill="Red"
               IsHitTestVisible="False"/>
    </ContentControl>
    <ContentControl Width="130"
                    MinWidth="50"
                    Height="130"
                    MinHeight="50"
                    Canvas.Top="150"
                    Canvas.Left="150"
                    Template="{StaticResource DesignerItemTemplate}">
      <Path Fill="Blue"
            Data="M 0,5 5,0 10,5 5,10 Z"
            Stretch="Fill"
            IsHitTestVisible="False"/>
    </ContentControl>
  </Canvas>
</Window>


using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace DiagramDesigner
{
    public class MoveThumb : Thumb
    {
        public MoveThumb()
        {
            DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
        }

        private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            Control designerItem = this.DataContext as Control;

            if (designerItem != null)
            {
                double left = Canvas.GetLeft(designerItem);
                double top = Canvas.GetTop(designerItem);
                Canvas.SetZIndex(designerItem, 0);
                Canvas.SetLeft(designerItem, left + e.HorizontalChange);
                Canvas.SetTop(designerItem, top + e.VerticalChange);
            }
        }
    }
}



using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace DiagramDesigner
{
    public class ResizeThumb : Thumb
    {
        public ResizeThumb()
        {
            DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta);
        }

        private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            Control designerItem = this.DataContext as Control;

            if (designerItem != null)
            {
                double deltaVertical, deltaHorizontal;
                Canvas.SetZIndex(designerItem, 0);

                switch (VerticalAlignment)
                {
                    case VerticalAlignment.Bottom:
                        deltaVertical = Math.Min(-e.VerticalChange, designerItem.ActualHeight - designerItem.MinHeight);
                        designerItem.Height -= deltaVertical;
                        break;
                    case VerticalAlignment.Top:
                        deltaVertical = Math.Min(e.VerticalChange, designerItem.ActualHeight - designerItem.MinHeight);
                        Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + deltaVertical);
                        designerItem.Height -= deltaVertical;
                        break;
                    default:
                        break;
                }

                switch (HorizontalAlignment)
                {
                    case HorizontalAlignment.Left:
                        deltaHorizontal = Math.Min(e.HorizontalChange, designerItem.ActualWidth - designerItem.MinWidth);
                        Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + deltaHorizontal);
                        designerItem.Width -= deltaHorizontal;
                        break;
                    case HorizontalAlignment.Right:
                        deltaHorizontal = Math.Min(-e.HorizontalChange, designerItem.ActualWidth - designerItem.MinWidth);
                        designerItem.Width -= deltaHorizontal;
                        break;
                    default:
                        break;
                }
            }

            e.Handled = true;
        }
    }
}

L
95 Beiträge seit 2009
vor 14 Jahren

Versuchs mal mit dem ZIndex...

Sollte gehen mit:


Canvas.SetZIndex(highestControl, 1);

und für jedes andere nimmst du einfach


Canvas.SetZIndex(control, 0);

Mfg Marc

X
xbredoillex Themenstarter:in
46 Beiträge seit 2009
vor 14 Jahren

Hi,

ich habe jetzt mit setZIndex() herumprobiert. Damit bringe ich das erste angeklickte Element in den Vordergrund. Leider geht das nur ein einziges mal beim allerersten angeklickten Objekt, dann verändert sich beim erneuten Bewegen eines Objektes die ZEbene nicht mehr.

Vermutlich, weil man beim setzen eines ZIndex immer die Indizes aller Objekte relativ dazu anpassen muss, sonst haben alle angeklickten irgendwann den gleichen ("obersten") Index. Kann das so stimmen?
Bei BringToFront()/SendToBack() ging das relative Setzen der Indizes automatisch.

Beim Versuch in MoveThumb_DragDelta() den ZIndex zu setzen kann man zwar den ZIndex des geklickten Objektes setzen, aber nicht den Index aller anderen anpassen. Innerhalb dieser Funktion bekommt man keinen Zugriff auf die anderen Elemente bzw. auf deren setZIndex-Funktion.

Das komplizierte Zugreifen auf die einzelnen verschachtelten Objekte macht es mir irgendwie unmöglich das Problem zu lösen, denn jede Schachtelebene hat völlig unterschiedliche Properties. Mal gibt es Parent/Child, mal nicht etc.
Ich habe es mit PreviewMouse-Events an verschiedenen Stellen versucht, da verheddere ich mich aber immer in den Schachtelebenen bzw. komme nicht weiter, weil ich die benötigten Objekte nicht erreichen kann.

Gibt es eine elegante Lösung, das mit Maus gegriffene Element immer in den Vordergrund zu bringen?

Gruß
xbredoillex

151 Beiträge seit 2009
vor 14 Jahren

Hi,

für deine Frage (ohne den ganzen Post gelesen zu haben) werden dir die Events MouseEnter und MouseLeave im Zusammenhang mit dem ZIndex hilfreich sein.
Dazu den ZIndex erhöhen und wieder runter setzen.

Grüßle
Jéré

X
xbredoillex Themenstarter:in
46 Beiträge seit 2009
vor 14 Jahren

Hi,

danke für den Tipp, mit MouseEnter/Leave geht es jetzt halbwegs.

Sieht halt nicht so toll aus, wenn das aktuelle Objekt beim Loslassen wieder hinter einem anderen verschwindet. Es wäre schöner wenn die Ebenen in der Reihenfolge des Anklickens sortiert sind und nicht in der Reihenfolge in der sie erschaffen wurden.

Es scheint wirklich so, als müsste man den ZIndex aller Objekte selbst verwalten, wenn man das anständig umsetzen will.

Dazu müsste man aber auch den ZIndex des verdeckenden, nicht angeklickten Objekts ermitteln um die Werte der Indizes evtl. zu vertauschen.

Nur wie? Hat jemand eine Idee?

Gruß
xbredoillex

Hier der Code mit MouseEnter/Leave:


public class MoveThumb : Thumb
	{
        private int tempindex = 0;
        
        public MoveThumb()
	    {
            MouseEnter += new MouseEventHandler(MoveThumb_MouseEnter);
            MouseLeave += new MouseEventHandler(MoveThumb_MouseLeave);
	        DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
	    }

        private void MoveThumb_MouseEnter(object sender, MouseEventArgs e)
        {
            ContentControl item = this.DataContext as ContentControl;
            if (item != null)
            {
                tempindex = Canvas.GetZIndex((UIElement)this.DataContext);
                Canvas.SetZIndex((UIElement)this.DataContext, 99);
            }
        }

        private void MoveThumb_MouseLeave(object sender, MouseEventArgs e)
        {
            ContentControl item = this.DataContext as ContentControl;
            if (item != null)
            {
                Canvas.SetZIndex((UIElement)this.DataContext, tempindex);
            }
        }

	    private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
	    {
            Control item = this.DataContext as Control;
	        if (item != null)
	        {	
	            double left = Canvas.GetLeft(item);
	            double top = Canvas.GetTop(item);
				
	            Canvas.SetLeft(item, left + e.HorizontalChange);
	            Canvas.SetTop(item, top + e.VerticalChange);
	        }
	    }
	}
}

420 Beiträge seit 2007
vor 14 Jahren

Hallo xbredoillex,

hast du das Problem inzwischen lösen können? Ich habe das gleiche und benutze die selbe Bibliothek.

Grüße
Dennis

5.742 Beiträge seit 2007
vor 14 Jahren

Hallo zusammen,

spontane Idee: Der MoveThumb könnte jeweils den letzten vergebenen Z-Index speichern und dann jedes Mal, wenn er aktiv wird, inkrementieren und zuweisen.

X
xbredoillex Themenstarter:in
46 Beiträge seit 2009
vor 14 Jahren

Hallo dennisspohr,

eine richtige Lösung für das Problem habe ich nicht gefunden bzw. ab einem gewissen Punkt nicht weiter nachgeforscht.
Mein letzten gespeicherten Links zu dem Thema waren diese hier:

http://blog.norberteder.com/comments.php?y=07&m=11&entry=entry071119-164324
http://www.silverlightshow.net/items/Using-the-Canvas-control-in-Silverlight-2-Beta-1.aspx

Vielleicht hilft dir das ja weiter. Ich erinnere mich, dass ich das damals irgendwie umsetzen wollte.

Gruß
xbredoillex