Comment fermer un formulaire lorsqu'un utilisateur clique en dehors de la fenêtre du formulaire?
Question
Je souhaite fermer un objet System.Windows.Forms.Form si l'utilisateur clique en dehors de celui-ci. J'ai essayé d'utiliser IMessageFilter, mais même dans ce cas, aucun des messages n'est transmis à PreFilterMessage. Comment recevoir des clics en dehors de la fenêtre d'un formulaire?
La solution 2
Merci à p-daddy dans , j'ai trouvé cette solution qui me permet d'utiliser ShowDialog:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
this.Capture = true;
}
protected override void OnCaptureChanged(EventArgs e)
{
if (!this.Capture)
{
if (!this.RectangleToScreen(this.DisplayRectangle).Contains(Cursor.Position))
{
this.Close();
}
else
{
this.Capture = true;
}
}
base.OnCaptureChanged(e);
}
Autres conseils
Dans l'événement Deactivate de votre formulaire, insérez "this.Close ()". Votre formulaire se ferme dès que vous cliquez n'importe où dans Windows.
Mise à jour: je pense que vous avez maintenant un bouton de volume. Dans l'événement Click, vous créez une instance de votre formulaire VolumeSlider et le faites apparaître en appelant ShowDialog (), qui bloque jusqu'à ce que l'utilisateur ferme le formulaire affiché. . Dans la ligne suivante, lisez le volume sélectionné par l'utilisateur et utilisez-le dans votre programme.
Ce n’est pas un problème, mais comme vous l’avez remarqué, cela oblige l’utilisateur à fermer explicitement la fenêtre afin de revenir au programme principal. Show () est la méthode que vous voulez vraiment utiliser ici dans votre formulaire contextuel, mais Show () ne bloque pas, ce qui signifie que l'événement Click revient sur votre formulaire principal se termine sans savoir ce que le nouveau volume est censé être.
Une solution simple consiste à créer une méthode publique sur votre formulaire principal, comme suit:
public void SetVolume(int volume)
{
// do something with the volume - whatever you did before with it
}
Ensuite, dans l'événement Click de votre bouton Volume (également sur le formulaire principal), vous donnez à VolumeSlider l'apparence suivante:
VolumeSlider slider = new VolumeSlider();
slider.Show(this); // the "this" is needed for the next step
Dans le formulaire VolumeSlider, lorsque l'utilisateur utilise la barre de défilement (je suppose), vous insérez ce code dans l'événement ValueChanged de la barre de défilement (je pense que c'est bien ce qu'il est):
MainForm owner = (MainForm)this.Owner;
owner.SetVolume(scrollbar.Value);
Ensuite, dans l'événement Deactivate du formulaire VolumeSlider, placez this.Close () comme indiqué ci-dessus. Votre formulaire se comportera alors comme prévu.
Avec la solution de Simon, j'avais le même problème décrit par Noam. Avec le code suivant, j'ai évité les " Click through " problème ...
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// if click outside dialog -> Close Dlg
if (m.Msg == NativeConstants.WM_NCACTIVATE) //0x86
{
if (this.Visible)
{
if (!this.RectangleToScreen(this.DisplayRectangle).Contains(Cursor.Position))
this.Close();
}
}
}
S'il s'agit d'un formulaire enfant dans une application MDI, vous pouvez intercepter le clic dans le formulaire parent, sinon la solution sera désordonnée.
De toute façon, je ne suis pas convaincu que ce que vous suggérez représente un comportement intuitif de l'interface utilisateur. Etes-vous sûr que c'est le meilleur design?
Si vous essayez de créer une fenêtre contextuelle qui se comporte un peu comme un menu, si ce n'est qu'elle vous permet d'interagir avec vos contrôles, vous pouvez essayer d'héberger un contrôle utilisateur dans une liste déroulante de la barre d'outils.
FAIRE SIMPLEMENT: sur Form1, utilisez ce code pour appeler form2:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Form2.Owner = Me
Form2.Show()
End Sub
puis utilisez à nouveau ce code sur form1:
Private Sub Form1_MouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
If Form2.IsHandleCreated = True Then
Form2.Close()
End If
End Sub
c'est simple:
private void button1_Click(object sender, EventArgs e)
{
Form f = new Form();
f.LostFocus +=new EventHandler(f_LostFocus);
f.Show();
}
void f_LostFocus(object sender, EventArgs e)
{
Form f = sender as Form;
f.Close();
f.Dispose();
}