Laden...

Problem beim Docken von Form an Bildschirm

Erstellt von sbertl000 vor 17 Jahren Letzter Beitrag vor 16 Jahren 4.978 Views
sbertl000 Themenstarter:in
822 Beiträge seit 2005
vor 17 Jahren
Problem beim Docken von Form an Bildschirm

Hallo

Ich docke mein Form mit folgendem Code an den Bildschirm, es wird aber oben gedockt, über die ganze Breite, ich will es aber rechts docken, wisst ihr weiter?

[StructLayout(LayoutKind.Sequential)]
        struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct APPBARDATA
        {
            public int cbSize;
            public IntPtr hWnd;
            public int uCallbackMessage;
            public int uEdge;
            public RECT rc;
            public IntPtr lParam;
        }

        enum ABMsg : int
        {
            ABM_NEW = 0,
            ABM_REMOVE = 1,
            ABM_QUERYPOS = 2,
            ABM_SETPOS = 3,
            ABM_GETSTATE = 4,
            ABM_GETTASKBARPOS = 5,
            ABM_ACTIVATE = 6,
            ABM_GETAUTOHIDEBAR = 7,
            ABM_SETAUTOHIDEBAR = 8,
            ABM_WINDOWPOSCHANGED = 9,
            ABM_SETSTATE = 10
        }

        enum ABNotify : int
        {
            ABN_STATECHANGE = 0,
            ABN_POSCHANGED,
            ABN_FULLSCREENAPP,
            ABN_WINDOWARRANGE
        }

        enum ABEdge : int
        {
            ABE_LEFT = 0,
            ABE_TOP,
            ABE_RIGHT,
            ABE_BOTTOM
        }

        private bool fBarRegistered = false;

        [DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)]
        static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData);
        [DllImport("USER32")]
        static extern int GetSystemMetrics(int Index);
        [DllImport("User32.dll", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int cx, int cy, bool repaint);
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        private static extern int RegisterWindowMessage(string msg);
        private int uCallBack;

        private void RegisterBar()
        {
            APPBARDATA abd = new APPBARDATA();
            abd.cbSize = Marshal.SizeOf(abd);
            abd.hWnd = this.Handle;
            if (!fBarRegistered)
            {
                uCallBack = RegisterWindowMessage("AppBarMessage");
                abd.uCallbackMessage = uCallBack;

                uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd);
                fBarRegistered = true;

                ABSetPos();
            }
            else
            {
                SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd);
                fBarRegistered = false;
            }
        }

        private void ABSetPos()
        {
            APPBARDATA abd = new APPBARDATA();
            abd.cbSize = Marshal.SizeOf(abd);
            abd.hWnd = this.Handle;
            abd.uEdge = (int)ABEdge.ABE_TOP;

            if (abd.uEdge == (int)ABEdge.ABE_LEFT || abd.uEdge == (int)ABEdge.ABE_RIGHT)
            {
                abd.rc.top = 0;
                abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height;
                if (abd.uEdge == (int)ABEdge.ABE_LEFT)
                {
                    abd.rc.left = 0;
                    abd.rc.right = Size.Width;
                }
                else
                {
                    abd.rc.right = SystemInformation.PrimaryMonitorSize.Width;
                    abd.rc.left = abd.rc.right - Size.Width;
                }

            }
            else
            {
                abd.rc.left = 0;
                abd.rc.right = SystemInformation.PrimaryMonitorSize.Width;
                if (abd.uEdge == (int)ABEdge.ABE_TOP)
                {
                    abd.rc.top = 0;
                    abd.rc.bottom = Size.Height;
                }
                else
                {
                    abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height;
                    abd.rc.top = abd.rc.bottom - Size.Height;
                }
            }

            // Query the system for an approved size and position. 
            SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref abd);

            // Adjust the rectangle, depending on the edge to which the 
            // appbar is anchored. 
            switch (abd.uEdge)
            {
                case (int)ABEdge.ABE_LEFT:
                    abd.rc.right = abd.rc.left + Size.Width;
                    break;
                case (int)ABEdge.ABE_RIGHT:
                    abd.rc.left = abd.rc.right - Size.Width;
                    break;
                case (int)ABEdge.ABE_TOP:
                    abd.rc.bottom = abd.rc.top + Size.Height;
                    break;
                case (int)ABEdge.ABE_BOTTOM:
                    abd.rc.top = abd.rc.bottom - Size.Height;
                    break;
            }

            // Pass the final bounding rectangle to the system. 
            SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref abd);

            // Move and size the appbar so that it conforms to the 
            // bounding rectangle passed to the system. 
            MoveWindow(abd.hWnd, abd.rc.left, abd.rc.top, abd.rc.right - abd.rc.left, abd.rc.bottom - abd.rc.top, true);
        }

        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            if (m.Msg == uCallBack)
            {
                switch (m.WParam.ToInt32())
                {
                    case (int)ABNotify.ABN_POSCHANGED:
                        ABSetPos();
                        break;
                }
            }

            base.WndProc(ref m);
        }

        protected override System.Windows.Forms.CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.Style &= (~0x00C00000); // WS_CAPTION
                cp.Style &= (~0x00800000); // WS_BORDER
                cp.ExStyle = 0x00000080 | 0x00000008; // WS_EX_TOOLWINDOW | WS_EX_TOPMOST
                return cp;
            }
        }

Danke schon im Vorraus

sbertl

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo sbertl000,

ich denke, du musst nichts anderes machen, als die Berechnung in


// Adjust the rectangle, depending on the edge to which the
// appbar is anchored.

anpassen.

herbivore

sbertl000 Themenstarter:in
822 Beiträge seit 2005
vor 17 Jahren

super, hat funktioniert, weißt du auch wie ich die Vertikale Pos. bestimmen kann, es "klebt ja sonst auf der rechten oberen Ecke.

sbertl

F
86 Beiträge seit 2007
vor 16 Jahren

Servus,

ich docke mein Fenster an den Bildschirm an. Man kann es sogar durch Drag and Drop an die anderen Seiten andocken. Ich mache das indem ich im Move - Eventhandler nach der Position des Cursors frage. Klappt wunderbar, doch entsteht dadurch auch ein Problem.

Und zwar flimmert mein Fenster dann, weil ich es ja zwangsweise bei jedem "Move" ändere. Also hab ich mir gedacht, ich ändere es nur, wenn es denn nötig ist, also beim Wechsel zwischen den Bereichen. Da kommt aber das Problem, das es kurz geändert wird und dann in den Ursprünglichen Zustand zurückkehrt.

Ist meine Änderung nicht dauerhaft? Und wenn ja, warum ist sie nicht dauerhaft?

Kann mir da jemand helfen?

Gruß Flohen

S
15 Beiträge seit 2008
vor 16 Jahren

Super, brauch ich keinen neuen thread aufzumachen.

Genau dieses Flimmern / Flackern geht mir auch auf die Nerven, wenn ich die Positionierung der Form im Move() Ereignis vornehme.
Ich möchte auch ein Docking oder Magnetismus am Bildschirmrand realisieren. Funktioniert auch, aber wie mein Vorposter schon beschreibt - die Form wird (per Maus) verschoben und durch meinen Code wieder an den Rand gezogen. Das sieht man aber auch, und darum dieses Flackern.

Gibt es einen geschickteren Weg ohne APIs ?

WndProc zu überschreiben geeeht so lala, da kommt es schnell mal zu Speicherzugriffsfehlern... und ich kann das Verschieben dort auch nicht verhindern, wie ich es mir erhofft habe.

Wenn immer der Klügere nachgibt, geschieht immer das, was der Dumme will.

915 Beiträge seit 2006
vor 16 Jahren

Setzt dafür einfach


this.DoubleBuffered = true;

oder über


base.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

Läuft bedes aufs selbe hinaus.

Hrm, denke nur das es über die WinAPI Funktion SetWindowPos (vielleicht?) leichter gewesen wäre da man hierbei auch noch den WindowsStyle entsprechend setzen kann. Um so z.B. das Fenster als PopUpFenster anzeigen zu lassen (SWP_FRAMECHANGED nicht dafür nicht vergessen).

Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(

S
15 Beiträge seit 2008
vor 16 Jahren

Danke für den Vorschlag. Über DoubleBuffered habe ich auch gelesen. Aber auch wenn das true ist, verhindert es nicht das Flackern. Für das Framework ist das Verschieben in der Move() ja bereits tatsächlich passiert. Dass ich das hinterher wieder korrigiere, ist halt eine Aktion direkt danach. Dass er beides zeichnet, ist logisch, aber nicht schön 🙂

Ich würde das Ereignis gerne vorher abfangen, und ggf das Verschieben zulassen oder unterbinden, bevor es gezeichnet wird. Komme nur bis jetzt nicht vorher an die neuen Koordinaten ran, wenn ich im Framework bleiben möchte...

In der WndProc kann man verschiedene Messages abfangen. Ein Verschieben per Maus wird begleitet von diversen messages, wie WM_POSCHANGED, WM_MOVE usw. genaueres kann ich nochmal ermitteln, aber zu dem Zeitpunkt stehen eben die neuen Koordinaten noch nicht fest und das Verschieben lässt sich nicht verhindern, wenn ich den base() Aufruf einfach nicht mache. Hab ich schon versucht, weil ich dachte, erst mit dem Aufruf der Parent-Methode geschieht überhaupt was 😛

Also eigentlich hab ich so gesehen 2 Probleme 🙂
Neue Koordinaten + Move verhindern

Wenn immer der Klügere nachgibt, geschieht immer das, was der Dumme will.

915 Beiträge seit 2006
vor 16 Jahren

Achso, hrm.. das ist natürlich blöd.

Ich positioniere die Fenster direkt beim Handle Create, da sie fix an der Position bleiben sollen. Ne art Snapin habe ich daher gar nicht.

Du könntest mit WinAPI GetWindowRect die Tazächlichen Fensterkoordinaten und größe (also mit den NonClientAreas) holen und in der WM_PAINT Nachricht in der WndProc nachschauen ob Right oder Left je nachdem gegen Screen.PrimaryScreen.WorkingArea.Right oder Screen.PrimaryScreen.WorkingArea.Left usw. läuft. Und wenn ja verhinderst das Zeichnen indem nen Break machst. Dann rufst du entweder über SetWindowPos oder MoveWindow die Position auf an der es gebunden werden soll und löst dann erst ein Invalidate auf. Würde sogar noch das Form um nen DockStyle enum LEFT TOP RIGHT BOTTOM erweitern. Damit dann beim wieder reinkommen in die WndPRoc Nachricht WM_PAINT weisst, wohin es nun einsnappen soll.

Dadurch das eben das Zeichnen unterbunden hast während der kritischen Stelle wird das Fenster erst positioniert (snappin) und dann erst angezeigt. Somit sollte es (eigentlich) kein flackern geben.

Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo Shaker,

Gibt es einen geschickteren Weg ohne APIs ?

ich denke, dass es mit .NET alleine nicht ohne Flackern geht.

herbivore

S
15 Beiträge seit 2008
vor 16 Jahren

Danke euch beiden. Das letzte, was Andreas.May geschrieben hat, hab ich noch nicht ganz verstehenoder ausprobieren können. Mach ich aber noch, wenn ich es verstanden habe 😉

Wenn immer der Klügere nachgibt, geschieht immer das, was der Dumme will.

S
15 Beiträge seit 2008
vor 16 Jahren

Krieg ich nicht hin... Es gibt einfach keine Möglichkeit, das Neuzeichnen zu verhindern, selbst wenn ich in der WndProc() den base() Aufruf verhindere. Es flackert. Und wenn ich in der WndProc() MoveWindow() im Bedarfsfall ausführe, bekomme ich ganz seltsame Erscheinungen... Ich denke, ich werde mit dem bisschen Flackern leben 😉

Danke euch aber!

Wenn immer der Klügere nachgibt, geschieht immer das, was der Dumme will.

N
67 Beiträge seit 2006
vor 16 Jahren

Hi, ich hab ein Problem beim andocken und zwar möchte ich das mein angedocktest fenster nicht


FormBorderStyle = FormBorderStyle.SizableToolWindow;

sondern


FormBorderStyle = FormBorderStyle.None;

Sobald ich es allerdings auf None setze packt er mir es nicht in oben den bereich sondern in den Bereich wo die fenster normal sind....
so nun weiß ich ehrlich gesagt nicht weiter oder gibt es eine andere möglichkeit noch den rahmen von sizabletoolwindow zu entfernen den exit butten bekommt man ja weg
durch


  ControlBox = false;

S
15 Beiträge seit 2008
vor 16 Jahren

packt er mir es nicht in oben den bereich sondern in den Bereich wo die fenster normal sind

Noch ungenauer geht's nich? 😛

Wenn immer der Klügere nachgibt, geschieht immer das, was der Dumme will.

N
67 Beiträge seit 2006
vor 16 Jahren

doch 🙂 ich meinte, das er mir wenn ich auf None setze nicht in den oben reservierten Bereich das fenster reinmacht...

S
15 Beiträge seit 2008
vor 16 Jahren

oberer Bereich? reserviert?? Fenster reinmachen??? Wo sie normal sind????? Der Bereich, wo die Fenster normal sind, ist der Desktop. Den meinst du aber sicher nicht. Also was?

Du musst echt mal deutlicher werden... 😕 Präzise(!) ausdrücken, denn hier kennt niemand auch nur ein Stück von deinem aktuellen Programm und wie es aussieht, bzw. was es tun soll.

Wenn immer der Klügere nachgibt, geschieht immer das, was der Dumme will.