none
Form auf Desktop immer sichtbar ohne permanentes TopMost = True ? RRS feed

  • Frage

  • Hallo,

    mein kleines Programm ist soweit fertig und funktioniert auch wunderbar. Einen kleinen Makel hat es aber trotzdem noch, den ich bis jetzt leider nicht selbst beheben konnte:

    Wenn man in der Taskleiste "Desktop anzeigen" aufruft, werden alle Fenster minimiert, also auch mein Programm. Ich möchte aber, daß das Fenster meines Programms trotzdem sichtbar bleibt, ohne TopMost permanent auf True setzen zu müssen, da TopMost im Programm eine wählbare Option bleiben soll und das Problem also auch nur dann auftritt, wenn die Option "Immer im Vordergrund" nicht aktiviert wurde.

    Mein Gedankengang ist der, daß auf das Ereignis "Desktop anzeigen" reagiert werden soll und erst dann und auch nur temporär TopMost auf True gesetzt werden soll. Nur habe ich hier leider gravierende Probleme mit der richtigen Syntax hinsichtlich des auslösenden Events. Weiß jemand Rat?

    Montag, 9. August 2010 17:45

Antworten

  • Hallo Chris,

    Leider kann ich erst jetzt wieder hier im Thread antworten. Und ohne irgendwem zu nahe treten zu wollen, aber das Problem ist noch NICHT GELÖST. Von daher frage ich mich schon, warum der Thread als gelöst gekennzeichnet worden ist.

    Stefan hatte sich zuletzt noch einmal zu dem Thema geäußert und dadurch ist wohl der Eindruck entstanden, dass mein Beitrag doch die Lösung Deines Problems darstellt. Oft gibt der Fragesteller kein Feedback mehr, wenn seine Frage (doch) beantwortet wurde. Entschuldige bitte, dass dies in diesem Fall unzutreffend war.

    Ich habe den FormBorderStyle auf None gesetzt, da ich ein rahmenloses Fenster erzeugen wollte. Und genau das scheint die Ursache des Problems zu sein

    Der FormBorderStyle hat maßgeblich damit zu tun, wie sich das Fenster verhält, wenn die Funktion "Desktop anzeigen" ausgeführt wird. Wenn ein Fenster einen änderbaren Rahmen hat und  MinimizeBox = True ist, wird das Fenster immer minimiert, auch wenn es immer im Vordergrund angezeigt wird. In der Konstellation bekommt man auch das Resize Ereignis und kann gegensteuern. Erst wenn es einen festen bzw. keinen Rahmen hat, bewirkt TopMost = True, dass das Formular sichtbar bleibt, auch wenn der User den Desktop anzeigen lässt. Ist es nicht immer im Vordergrund, bekommt es auch keine Benachrichtigung, sobald die Funktion "Desktop anzeigen" ausgeführt wird. Das System sendet hier keinen Broadcast oder ähnliches. Vielmehr scheint es, als würde der ZOrder des Desktops so geändert, dass dieser im Vordergrund erscheint. Auf dem Weg gerät man auch nicht in Konflikt mit Dialogen oder blockierenden Anwendungen.

    Einzige Lösung die mir hier noch einfällt und für Deinen Fall auch praktikabel erscheint, dieses Formular als Child des sichtbaren Desktops einzuhängen. Der sichtbare Desktop trägt den Klassennamen "Progman". Einige mag das an den "Programm Manager" zu Zeiten von Windows 3.1 erinnern, dort ist dieses Konzept wohl auch historisch einzuordnen, denn dieses Fenster stellt den Desktop mit seinen Symbolen dar und dieses wird immer angezeigt. Sein eigenes Formular bekommt man mit der API Funktion "SetParent" dort als Child angehängt. Dann bleibt es sichtbar, auch wenn der Desktop angezeigt werden soll:

    Imports System.Runtime.InteropServices
    
    Public Class Form1
    
     Private m_OldParent As IntPtr
    
     Private Sub AttachToProgman()
     Dim lProgMan As IntPtr
    
     lProgMan = NativeMethods.FindWindow("Progman", Nothing)
    
     m_OldParent = NativeMethods.SetParent(Me.Handle, lProgMan)
     End Sub
    
     Private Sub DetachFromProgman()
     If m_OldParent <> IntPtr.Zero Then
      NativeMethods.SetParent(Me.Handle, m_OldParent)
    
      m_OldParent = IntPtr.Zero
     End If
     End Sub
    
     Private ReadOnly Property IsAttachedToProgman() As Boolean
     Get
      Return m_OldParent <> IntPtr.Zero
     End Get
     End Property
    
     Private Sub Form1_Load(ByVal sender As Object, _
    	   ByVal e As System.EventArgs) Handles Me.Load
    						 
     AttachToProgman()
     End Sub
    
     Private Sub chkAlwaysOnTop_CheckedChanged(ByVal sender As System.Object, _
    	     ByVal e As System.EventArgs _
    					  ) Handles chkAlwaysOnTop.CheckedChanged
     If Me.chkAlwaysOnTop.Checked Then
      If Me.IsAttachedToProgman Then
      DetachFromProgman()
      Me.TopMost = True
      End If
    			
     Else
      If Not Me.IsAttachedToProgman Then
      Me.TopMost = False
      AttachToProgman()
      End If
     End If
     End Sub
    	
     Private Class NativeMethods
     <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
     Friend Shared Function FindWindow(ByVal lpClassName As String, _
          ByVal lpWindowName As String) As IntPtr
     End Function
     <DllImport("user32.dll", SetLastError:=True)> _
     Public Shared Function SetParent(ByVal hWndChild As IntPtr, _
    		    ByVal hWndNewParent As IntPtr) As IntPtr
     End Function
     End Class
    End Class
    Ab Windows Vista/7 gibt es auch die sogenannten Sidebar Gadgets bzw. Minianwendungen. Diese kommen bereits mit der von Dir gewünschten Funktionalität daher und können optional immer im Vordergrund angezeigt werden.

    Erstellen eigener Windows Vista-Sidebar-Minianwendungen
    http://msdn.microsoft.com/de-de/magazine/cc163370.aspx

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Samstag, 21. August 2010 19:30

Alle Antworten

  • Hallo username denied,

    ich könnte mir vorstellen, dass deine Idee über einen Desctophandle funktionieren kann. Ich habe hier einen Link gefunden, der sich mit dem Thema Taskleiste und Desktop ausblenden befasst. Die hier verwendete API sollte eigentlich auch behilflich sein, das Event an sich zu erkennen und somit die Situation herzustellen an der du dann deine If Then-Schleife für deine Form einbaust.
    Geprüft habe ich das nicht, hoffe aber, das es dir helfen kann.

    http://msdn.microsoft.com/de-de/library/bb979568.aspx


    Liebe Grüße Stefan
    Montag, 9. August 2010 19:39
  • Hallo,

    Wenn man in der Taskleiste "Desktop anzeigen" aufruft, werden alle Fenster minimiert, also auch mein Programm. Ich möchte aber, daß das Fenster meines Programms trotzdem sichtbar bleibt

    das von Dir gewünschte Verhalten ist aber nicht gerade das, was der Anwender erwartet, wenn er freien Blick auf seinen Desktop haben möchte. Du solltest auf solche Spielereien verzichten, da gerade solche Programme die Usability enorm in den Keller reißen können und schnell vom Benutzer "entsorgt" werden.

    ohne TopMost permanent auf True setzen zu müssen

    TopMost bzw. "Immer im Vordergrund", ändert nichts daran, dass die Funktion "Desktop anzeigen", alle sichtbaren Fenster minimiert.

    Mein Gedankengang ist der, daß auf das Ereignis "Desktop anzeigen" reagiert werden soll und erst dann und auch nur temporär TopMost auf True gesetzt werden soll.

    Wenn der Anwender die Funktion "Desktop anzeigen" wählt, minimiert Windows alle sichtbaren Fenster. Deine Anwendung bekommt diesen Vorgang im Form.Resize Ereignis mit und kann dort die WindowState Eigenschaft wieder auf Normal zurücksetzen. TopMost braucht es hierfür nicht:

     Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
      Me.WindowState = FormWindowState.Normal
     End Sub
    

    Ich rate jedoch davon ab.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Montag, 9. August 2010 19:55
  • Hallo,

    danke schon mal für die ersten Antworten. Ich hoffe trotzdem auf weitere Anregungen.

    @ Stefan: Besten Dank für den Link. Ich werde mich da mal hineinvertiefen. Bis jetzt hatte ich in anderen Foren ähnliche Lösungsansätze gefunden, die aber auch nicht ganz mein Problem trafen. Mal schauen, ob sich dann insgesamt etwas Passendes zusammenbasteln läßt.

    @ Thorsten: Danke für Deinen Vorschlag. Mit Resize und WindowState habe ich schon probiert, das Problem zu lösen. Merkwürdigerweise bekomme ich es damit aber nicht hin. Erst wenn ich TopMost auf True setze, wird mein Programmfenster nicht minimiert, sondern weiterhin auf dem Desktop angezeigt. Ich benutze VB 2008 Express. Vielleicht macht das ja einen Unterschied?

    Mein Programm betreffend möchte ich erklärend hinzufügen, daß es sich lediglich um ein Mini-Fenster handelt (118x58 Pixel), das ausschließlich Anzeigezwecken dient. Damit man das Fenster auch dann noch sehen kann, wenn man gerade mit einer maximierten Anwendung arbeitet, ist im Kontextmenü die Option "Immer im Vordergrund" (TopMost = True) wählbar. Zusätzlich ist eine freie Positionierung des Fensters (und natürlich auch das Programmende) möglich.

    Grüße an alle !

    Chris

    Montag, 9. August 2010 22:17
  • @ Thorsten: Danke für Deinen Vorschlag. Mit Resize und WindowState habe ich schon probiert, das Problem zu lösen. Merkwürdigerweise bekomme ich es damit aber nicht hin. Erst wenn ich TopMost auf True setze, wird mein Programmfenster nicht minimiert, sondern weiterhin auf dem Desktop angezeigt. Ich benutze VB 2008 Express. Vielleicht macht das ja einen Unterschied?

    Nein, der Unterschied ergibt sich wohl aus dem verwendeten FormBorderStyle. Wenn dieser Fixed, oder ToolWindow ist, wird kein Resize Ereignis ausgelöst. Ich habe aber im Moment keine zufriedenstellende Alternative für Dich.
    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Dienstag, 10. August 2010 08:43
  • Hallo,

     

    ich habe das mal hier ausprobiert.

     

    Nur mit:

     

    Me.WindowState = FormWindowState.Normal

    Hatte ich auch nicht den gewünschten erfolg

     

    Mit

    Private Sub Form1_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Resize

            Me.TopMost = True

            Me.WindowState = FormWindowState.Normal

        End Sub

     

    Funktioniert es aber wie du es wünscht.

    Dennoch schließe ich mich den Bedenken von Thorsten an, das so erzeugte Verhalten ist einfach nicht das, was man erwartet.

     

     


    Liebe Grüße Stefan
    Mittwoch, 11. August 2010 18:10
  • Hallo mal wieder!

    Leider kann ich erst jetzt wieder hier im Thread antworten. Und ohne irgendwem zu nahe treten zu wollen, aber das Problem ist noch NICHT GELÖST. Von daher frage ich mich schon, warum der Thread als gelöst gekennzeichnet worden ist.

    Ich habe den FormBorderStyle auf None gesetzt, da ich ein rahmenloses Fenster erzeugen wollte. Und genau das scheint die Ursache des Problems zu sein,

    @ Stefan: Danke für Deine Mühe, aber auch Dein Code hat bei mir nicht den gewünschten Effekt, was sicherlich am FormBorderStyle liegt.

    Ich habe nun die Überlegung, das Ganze als Desktop-Applikation zu programmieren, weil das Fenster eben IMMER sichtbar bleiben soll, sofern der User das Programm nicht schließt.

    Was das Erwarten des Users angeht: Meint Ihr nicht auch, daß man eine Uhr (für Sehschwache übrigens) auf dem Desktop immer sehen sollte, auch wenn man andere Anwendungen per "Desktop anzeigen" minimiert???

    Aber okay, im Grunde genommen ist es nur ein kleiner Schönheitsfehler, daß die Uhr mit minimiert wird. Und letzten Endes ist es ja auch nur Hobby-Programmierung. Von daher ist es nicht so wichtig und eilt es auch nicht, des Rätsels Lösung zu finden.

    Trotzdem danke für Eure Hilfe und Grüße an alle !

    Chris

    Freitag, 20. August 2010 13:17
  • Hallo Chris,

    Leider kann ich erst jetzt wieder hier im Thread antworten. Und ohne irgendwem zu nahe treten zu wollen, aber das Problem ist noch NICHT GELÖST. Von daher frage ich mich schon, warum der Thread als gelöst gekennzeichnet worden ist.

    Stefan hatte sich zuletzt noch einmal zu dem Thema geäußert und dadurch ist wohl der Eindruck entstanden, dass mein Beitrag doch die Lösung Deines Problems darstellt. Oft gibt der Fragesteller kein Feedback mehr, wenn seine Frage (doch) beantwortet wurde. Entschuldige bitte, dass dies in diesem Fall unzutreffend war.

    Ich habe den FormBorderStyle auf None gesetzt, da ich ein rahmenloses Fenster erzeugen wollte. Und genau das scheint die Ursache des Problems zu sein

    Der FormBorderStyle hat maßgeblich damit zu tun, wie sich das Fenster verhält, wenn die Funktion "Desktop anzeigen" ausgeführt wird. Wenn ein Fenster einen änderbaren Rahmen hat und  MinimizeBox = True ist, wird das Fenster immer minimiert, auch wenn es immer im Vordergrund angezeigt wird. In der Konstellation bekommt man auch das Resize Ereignis und kann gegensteuern. Erst wenn es einen festen bzw. keinen Rahmen hat, bewirkt TopMost = True, dass das Formular sichtbar bleibt, auch wenn der User den Desktop anzeigen lässt. Ist es nicht immer im Vordergrund, bekommt es auch keine Benachrichtigung, sobald die Funktion "Desktop anzeigen" ausgeführt wird. Das System sendet hier keinen Broadcast oder ähnliches. Vielmehr scheint es, als würde der ZOrder des Desktops so geändert, dass dieser im Vordergrund erscheint. Auf dem Weg gerät man auch nicht in Konflikt mit Dialogen oder blockierenden Anwendungen.

    Einzige Lösung die mir hier noch einfällt und für Deinen Fall auch praktikabel erscheint, dieses Formular als Child des sichtbaren Desktops einzuhängen. Der sichtbare Desktop trägt den Klassennamen "Progman". Einige mag das an den "Programm Manager" zu Zeiten von Windows 3.1 erinnern, dort ist dieses Konzept wohl auch historisch einzuordnen, denn dieses Fenster stellt den Desktop mit seinen Symbolen dar und dieses wird immer angezeigt. Sein eigenes Formular bekommt man mit der API Funktion "SetParent" dort als Child angehängt. Dann bleibt es sichtbar, auch wenn der Desktop angezeigt werden soll:

    Imports System.Runtime.InteropServices
    
    Public Class Form1
    
     Private m_OldParent As IntPtr
    
     Private Sub AttachToProgman()
     Dim lProgMan As IntPtr
    
     lProgMan = NativeMethods.FindWindow("Progman", Nothing)
    
     m_OldParent = NativeMethods.SetParent(Me.Handle, lProgMan)
     End Sub
    
     Private Sub DetachFromProgman()
     If m_OldParent <> IntPtr.Zero Then
      NativeMethods.SetParent(Me.Handle, m_OldParent)
    
      m_OldParent = IntPtr.Zero
     End If
     End Sub
    
     Private ReadOnly Property IsAttachedToProgman() As Boolean
     Get
      Return m_OldParent <> IntPtr.Zero
     End Get
     End Property
    
     Private Sub Form1_Load(ByVal sender As Object, _
    	   ByVal e As System.EventArgs) Handles Me.Load
    						 
     AttachToProgman()
     End Sub
    
     Private Sub chkAlwaysOnTop_CheckedChanged(ByVal sender As System.Object, _
    	     ByVal e As System.EventArgs _
    					  ) Handles chkAlwaysOnTop.CheckedChanged
     If Me.chkAlwaysOnTop.Checked Then
      If Me.IsAttachedToProgman Then
      DetachFromProgman()
      Me.TopMost = True
      End If
    			
     Else
      If Not Me.IsAttachedToProgman Then
      Me.TopMost = False
      AttachToProgman()
      End If
     End If
     End Sub
    	
     Private Class NativeMethods
     <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
     Friend Shared Function FindWindow(ByVal lpClassName As String, _
          ByVal lpWindowName As String) As IntPtr
     End Function
     <DllImport("user32.dll", SetLastError:=True)> _
     Public Shared Function SetParent(ByVal hWndChild As IntPtr, _
    		    ByVal hWndNewParent As IntPtr) As IntPtr
     End Function
     End Class
    End Class
    Ab Windows Vista/7 gibt es auch die sogenannten Sidebar Gadgets bzw. Minianwendungen. Diese kommen bereits mit der von Dir gewünschten Funktionalität daher und können optional immer im Vordergrund angezeigt werden.

    Erstellen eigener Windows Vista-Sidebar-Minianwendungen
    http://msdn.microsoft.com/de-de/magazine/cc163370.aspx

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Samstag, 21. August 2010 19:30
  • Hallo Thorsten,

    besten Dank für die ausführliche Erklärung und den Code, der wirklich sehr gut aussieht. Nur bemängelt mein VB 2008 Express das chkAlwaysOnTop, so daß ich den Code leider nicht ausprobieren kann.

    Meines Erachtens nach fehlt die Deklaration für chkAlwaysOnTop, da bemängelt wird, daß dies kein FriendWithEvents und kein Member des Forms ist. Nur ... als was muß diese Variable deklariert werden?

    Das hab' ich bis jetzt noch nicht herausfinden können. Habe im Moment aber auch eine gewisse Denk-Blockade, da ich nebenbei schon wieder mühsam an etwas anderem (ein Text-Editor mit erweiterten Funktionen) gebastelt habe - getreu dem Motto "Learning by doing".

    Vista/Windows 7 ... danke für den Tip. Aber das ist weit entfernt von mir. Ich nutze Windows XP und bin im Großen und Ganzen eigentlich auch glücklich damit. Nur die Sonderwünsche, die muß - nein: will - man sich eben selbst programmieren ...

    Viele Grüße!

    Chris

    Dienstag, 24. August 2010 08:29
  • Hallo,

    Nur bemängelt mein VB 2008 Express das chkAlwaysOnTop

    'chkAlwaysOnTop' ist in meinem Beispiel eine CheckBox, die ich im Designer auf dem Formular platziert habe. Du hast ja geschrieben, dass Deine Anwendung optional auch immer im Vordergrund angezeigt werden soll. Das Handling dieser CheckBox war quasi stellvertretend für diese Option und kann auch entfallen (also die komplette Methode chkAlwaysOnTop_CheckedChanged), wenn Du das anders gelöst hast.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Dienstag, 24. August 2010 08:51
  • Hallo noch mal Thorsten,

    während Du hier geantwortet hast, bin ich nun auch dahinter gekommen, was es mit chkAlwaysOnTop auf sich hat ... Aufgrund des Namens dachte ich auch an eine Checkbox - nur hab' ich ja gar keine ... aber dafür ein Contextmenu mit einem MenuItem (wenn Option gewählt, dann farblich hervorgehoben).

    So weit so gut. Habe den Code nun auch gleich mit dem Debugger ausprobiert. Die Uhr bleibt tatsächlich immer auf dem Desktop sichtbar, wenngleich der Nebeneffekt eintritt, daß man die Uhr nun generell nicht mehr über maximierten Anwendungen sieht, egal ob man "Immer im Vordergrund" auswählt oder nicht. Aber ich denke, daß man das mit einer If-Abfrage auch noch lösen kann.

    Dein Code = großartige Hilfe! Allerbesten Dank!

    Problem ist nun gelöst. :-)

    Dankbare Grüße!

    Chris

    Dienstag, 24. August 2010 09:30
  • Hallo Chris,

    So weit so gut. Habe den Code nun auch gleich mit dem Debugger ausprobiert. Die Uhr bleibt tatsächlich immer auf dem Desktop sichtbar, wenngleich der Nebeneffekt eintritt, daß man die Uhr nun generell nicht mehr über maximierten Anwendungen sieht, egal ob man "Immer im Vordergrund" auswählt oder nicht. Aber ich denke, daß man das mit einer If-Abfrage auch noch lösen kann.

    Ja, das war die Demo mit der CheckBox. Das kann man auch einfacher haben, indem man die TopMost Eigenschaft überschattet. Dazu müsstest Du folgende Eigenschaft in Deinem Formular ergänzen:

     Public Shadows Property TopMost() As Boolean
      Get
       Return MyBase.TopMost
      End Get
    
      Set(ByVal value As Boolean)
       If value <> MyBase.TopMost Then
        If value Then
         ' Immer im Vordergrund:
         If Me.IsAttachedToProgman Then
          Me.DetachFromProgman()
         End If
    
        Else
         ' Immer auf dem Desktop:
         If Not Me.IsAttachedToProgman Then
          Me.AttachToProgman()
         End If
        End If
    
        MyBase.TopMost = value
       End If
      End Set
     End Property

    Damit hat man eine Zwangsläufigkeit und löst das Formular vom Desktop, sobald die TopMost Eigenschaft auf True gesetzt wird.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Dienstag, 24. August 2010 10:56
  • Und wieder hallo Thorsten,

    danke für Deine Mühe. Mir scheint fast, heute lerne ich hier mehr als sonst in einer ganzen Woche. Die Möglichkeit einer Überschattung kannte ich noch nicht. Es funktioniert auch so, wie ich es in meinen Code testweise eingebaut habe. In der Zwischenzeit habe ich derweil ein bißchen herumprobiert (die Click-Sub umgeschrieben und die Attach-Sub aus dem Load genommen) und konnte ein gleiches Ergebnis erzielen.

    Einziger Wermutstropfen bei beiden Varianten: Man wählt "Desktop anzeigen" und sieht den Desktop und die Uhr. Wenn man nun die Option "Immer im Vordergrund" wieder deaktiviert, verschwindet die Uhr vom Desktop so lange, bis man ein gerade minimiertes Fenster aktiviert.

    Ich hab' nun schon Activate(), Focus() und andere mir hilfreich erscheinende Methoden ausprobiert, doch leider ändert das nichts. Aber morgen ist auch noch ein Tag. Und das ursprüngliche Problem ist ja trotzdem gelöst.  ;-)

    Viele Grüße!

    Chris

    Dienstag, 24. August 2010 13:46
  • Hallo an alle Interessierten,

    nachdem ich mal wieder einen Tag Programmierpause eingelegt habe, waren die Sinne wieder klar für den nächsten Anlauf zur Fehlersuche. Und ich wurde auch schnell fündig, was heißt: Nun habe ich endlich alles so, wie ich es haben möchte - ohne jeglichen Schönheitsfehler. An dieser Stelle auch noch mal ein großes DANKE an Thorsten für seine tolle Hilfe! Und so funktioniert's:

    In meine ursprüngliche Form habe ich gleich ganz am Anfang zusätzlich zu meinen eigenen Deklarationen folgende Zeilen aus Thorstens Code eingefügt:

    	Imports System.Runtime.InteropServices
    
    	Private m_OldParent As IntPtr
    
    	Private Class NativeMethods
    		<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    		Friend Shared Function FindWindow(ByVal lpClassName As String, _
    		 ByVal lpWindowName As String) As IntPtr
    		End Function
    
    		<DllImport("user32.dll", SetLastError:=True)> _
    		Public Shared Function SetParent(ByVal hWndChild As IntPtr, _
    		 ByVal hWndNewParent As IntPtr) As IntPtr
    		End Function
    	End Class
    
    	Private ReadOnly Property IsAttachedToProgman() As Boolean
    		Get
    			Return m_OldParent <> IntPtr.Zero
    		End Get
    	End Property
    
    	Private Sub AttachToProgman()
    		Dim lProgMan As IntPtr
    		lProgMan = NativeMethods.FindWindow("Progman", Nothing)
    		m_OldParent = NativeMethods.SetParent(Me.Handle, lProgMan)
    	End Sub
    
    	Private Sub DetachFromProgman()
    		If m_OldParent <> IntPtr.Zero Then
    			NativeMethods.SetParent(Me.Handle, m_OldParent)
    			m_OldParent = IntPtr.Zero
    		End If
    	End Sub
    
    'Dann folgt meine Load-Sub:
    
    	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    	Handles Me.Load
    		ReadUserSettings()
    		SetTime()
    	End Sub
    
    

    In ReadUserSettings() werden die zuletzt gewählten Programm-Einstellungen noch ganz altertümlich aus einer .ini-Datei ausgelesen (mit MySettings habe ich mich noch nicht näher befaßt, deshalb die .ini). Für die Option "Immer im Vordergrund" wurde der Wert von TopMost in der .ini-Datei gespeichert. Die Programm-Einstellungen werden nach dem Auslesen auch gleich gesetzt.

    Wie schon im Thread erwähnt, habe ich für die Einstellung "Immer im Vordergrund" einen ganz normalen ContextMenuItem verwendet. Ist die Option aktiviert, wird diese farblich hervorgehoben. Für das Setzen der Option "Immer im Vordergrund" bei Programmstart ist nun folgender Code-Teil zuständig:

    	Me.TopMost = Info(4)
    
    	If Me.TopMost = True Then
    		ContextMenuItem_Vordergrund.ForeColor = Color.Coral
    		If Me.IsAttachedToProgman Then
    		DetachFromProgman()
    		End If
    	Else
    		ContextMenuItem_Vordergrund.ForeColor = SystemColors.ControlText
    		If Not Me.IsAttachedToProgman Then
    		AttachToProgman()
    		End If
    	End If
    
    'Die Sub für das Klick-Ereignis des ContextMenuItems sieht dann so aus:
    
    	Private Sub ContextMenuItem_Vordergrund_Click(ByVal sender As Object, ByVal e As 
    System.EventArgs) _
    	Handles ContextMenuItem_Vordergrund.Click
    
    	If Me.IsAttachedToProgman Then
    		DetachFromProgman()
    		ContextMenuItem_Vordergrund.ForeColor = Color.Coral
    		Me.TopMost = True
    	Else
    		ContextMenuItem_Vordergrund.ForeColor = SystemColors.ControlText
    		Me.TopMost = False
    		AttachToProgman()
    	End If
    	End Sub
    
    'Die End-Sub gestaltet sich wie folgt:
    
    	Private Sub ContextMenuItem_Beenden_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    	Handles ContextMenuItem_Beenden.Click
    
    	WriteUserSettings()
    	If Me.IsAttachedToProgman Then
    		DetachFromProgman()
    	End If
    	Me.Dispose()
    	Me.Close()
    	End Sub
    

    Was dem Programm nun der Vollständigkeit halber noch fehlt, ist ein Event-Handling für das Herunterfahren des PCs, also falls das Programm vor dem Herunterfahren vom User nicht geschlossen wurde. Windows schließt zwar alle laufenden Programme vor dem Herunterfahren, aber die Ereignisabzeige ist nicht so ganz zufrieden damit. Nur eine Warnung, also kein Beinbruch. Aber es sollte schon alles korrekt sein, finde ich. Mal schauen, was mir dazu dann so einfällt.

    Grüße an alle!

    Chris

    Donnerstag, 26. August 2010 00:44
  • das von Dir gewünschte Verhalten ist aber nicht gerade das, was der Anwender erwartet, wenn er freien Blick auf seinen Desktop haben möchte. Du solltest auf solche Spielereien verzichten, da gerade solche Programme die Usability enorm in den Keller reißen können und schnell vom Benutzer "entsorgt" werden.

    ...

     Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize

      Me.WindowState = FormWindowState.Normal

    End Sub

    Ich rate jedoch davon ab.

     

    Hallo,

    ist zwar schon ein paar Tage her, aber trotzdem meine Meinung.

    Wenn ich ein Anwendung auf meinem Rechner habe, die so ein Verhalten an den Tag legt, dauert es nicht länger als die Deinstallationsroutine bis die Anwendung vom meinem Rechner verschwunden ist!

    Ich betone das deswegen, weil es keine Anwendung gibt, die wichtiger ist als das Betriebssystem selber. Ich habe nichts gegen TopMost, ist auch in einigen Fällen sinnvoll und habe ich auch schon eingesetzt(bspw. bei einer "Bildschirmlupe"). Jedoch sollte man seine eigene Anwendung nicht versuchen so in den Vordergrund zu schieben, als wenn es das wichtigste ist.

    Also, wie Thorsten schon gesagt hat, bitte, bitte lasst sowas sein.

    --

    Gruß Scotty

    Freitag, 10. September 2010 07:45