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
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
super, hat funktioniert, weißt du auch wie ich die Vertikale Pos. bestimmen kann, es "klebt ja sonst auf der rechten oberen Ecke.
sbertl
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
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.
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(
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.
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(
Hallo Shaker,
Gibt es einen geschickteren Weg ohne APIs ?
ich denke, dass es mit .NET alleine nicht ohne Flackern geht.
herbivore
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.
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.
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;
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.
doch 🙂 ich meinte, das er mir wenn ich auf None setze nicht in den oben reservierten Bereich das fenster reinmacht...
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.