Closing a form that was opened by ShowDialog() - c#

I have a winform application where I've written my own little color picker that will only display system colours. It's basically a TableLayoutPanel with a bunch of smaller panels added to it, to which I just set the background color.
Pretty simple:
Now I'm opening this form for with:
using (frmColourWindow colourPicker = new frmColourWindow (Cursor.Position.X, Cursor.Position.Y, findingPriority))
{
colourPicker.ShowDialog();
if (!colourPicker.SelectedColor.IsEmpty)
{
pnlColor.BackColor = colourPicker._SelectedColor;
}
}
and closing it with by setting the DialogResult when the user has clicked on one of the color panels.
This all works pretty good, the only thing I can not manage to get right is by closing the form when it loses focus (E.g. when the user clicks somewhere else or starts typing). I've had a look at the Deactivate, LostFocus, and Leave events. Just can't seem to get those events to fire when I want them to. Maybe I'm missing something obvious?

As I mentioned in the comments, when using the ShowDialog() you can only use the Dialog you have opened and thus it never looses focus, so event like Deactivate, LostFocus and Leave won't work.
You need to use the Show() command to use those event to close the opened Form.
As to addressing the issue you pointed out in the comments about assigning the color to the object. you can do the following:
Declare a public Property
Color SelectedColor {get; private set; }
In your color picker and change your using statement to this:
var colourPicker = new frmColourWindow (Cursor.Position.X, Cursor.Position.Y, findingPriority);
colourPicker.Closed += (o, args) => { pnlColor.BackColor = colourPicker.SelectedColor };
colourPicker.Show();
This is of course just one of many possible solutions for that.

You can achieve this by displaying the form with the Show() method and then using the Form.Deactivate event.

Related

How to prevent text box from gaining focus unless clicked?

I have a WinForms application that has a TextBox control (search box) at the top of it. This TextBox is constantly receiving focus during normal application use, and it is very distracting.
I would like the TextBox to only receive the focus if the user explicitly clicks on it.
I can think of a couple rather complicated ways to accomplish this:
Change an image of a text box into a text box when clicked
Keep track of mouse clicks and shift the focus away based on mouse state
Is there something simpler that I can do to accomplish this?
Edit to add better description of problem based on new understanding
Based on the answers that I have received, I now have a bit of a better understanding of what was causing this problem. As the user interacted with my application, various actions would cause controls to either be disabled or to completely disappear. If one of these controls happened to have the focus at the time, then the next control in the tab order would receive the focus.
I don't know what was the "next control" before I added the text box in question. The application has hundreds of controls on screen at any given time, and I'm pretty sure that tab order was never intentionally defined. Whatever it was before, it was innocuous. After adding the search text box, it seemed like that control would always end up with the focus.
Here is a very simple example that demonstrates what was happening:
public class Form1 : Form
{
public Form1()
{
var button = new Button
{
Location = new System.Drawing.Point(159, 67),
Size = new System.Drawing.Size(75, 23),
TabIndex = 0,
Text = #"Click me"
};
button.Click += (sender, args) => button.Enabled = false;
var textBox = new TextBox
{
Location = new System.Drawing.Point(159, 142),
Name = "textBox1",
Size = new System.Drawing.Size(174, 20),
TabIndex = 1
};
SuspendLayout();
ClientSize = new System.Drawing.Size(486, 392);
Controls.Add(textBox);
Controls.Add(_button);
ResumeLayout(false);
PerformLayout();
}
}
After starting the application, clicking on the button will force the text box to get the focus, since it is the next in the tab order. As mentioned by Handbag Crab in the accepted answer, this behavior can be avoided by setting TabStop = false on the text box.
textBox1.TabStop = false;
The above should stop it receiving focus from tabbing.
Subclass the TextBox and over WndProc function to capture the focus message and handle it. Maybe something like this:
if (m.Msg == WM_MOUSEACTIVATE) {
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);

How to have interior form respond to key down events?

I have a MainView form that just contains a panel. I use a separate class (Presenter) to govern what form will be shown in that panel depending on different events. When one of these sub-forms are shown I want to be able to press a key down and have that sub-form respond; however, the keydown event does not hit in the sub-form, only the main form.
I want to know how to get the sub-form to respond to key events without going from MainView -> Presenter -> SubView.
Since your Presenter class is aware of the form it is putting into the panel, it will also need to get from that form or from associated data what control in the form is meant to have default focus. Presumably, your Presenter class has a method that shows a given form on that panel, so you do something like:
Presenter.ShowForm(MainViewPanel, Form1);
You would then need to do something like:
Form1.Controls.OrderBy(x => x.TabIndex).First().Focus();
What has the focus? If you don't have a control in the child form with the focus, it will never see the keyboard events.
Also, try setting KeyPreview to true on the child form.
https://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview(v=vs.110).aspx
Alright I figured out what my issue was. It was a combination of a few of the posts, but I wanted to put everything down that I had to do in one place.
I have a method that looks like this:
private void DisplayView(Form view)
{
if (view == null || view == _mainView) return;
view.TopLevel = false;
_mainView.GameArea.Controls.Clear();
_mainView.GameArea.Controls.Add(view);
view.Dock = DockStyle.Fill;
view.BringToFront();
view.Show();
_mainView.GameArea.Controls[0].Focus();
}
This was the line that fixed it:
_mainView.GameArea.Controls[0].Focus();
Rather than going through the "view" variable and setting focus, I was able to set focus to the view this way.
I also had to remove the other views from the panel's collection as well:
_mainView.GameArea.Controls.Clear();

Need to use a color dialog result in a separate Windows Form

Please go easy on me I am very new to coding and stuck on something that I'm sure is very simple.
Currently I have an Options form in which the user can select from the standard colordialog.showdialog() and the result is displayed as a sample on the form as a label
If(backColorDialog.Showdialog() == DialogResult.OK);
backColorLabel.BackColor = backColorDialog.Color; // set to label to show option selected
I need to take that selected color and apply it to the background color of a "game board" in another Windows form. I have already added a reference from the "game board" form to the options form.
The "Game Board" is laid over a TableLayoutPanel so I need to be able to change the BackColor of the panel
TableLayoutPanel1.BackColor = (colordialog result from options form)
Like I said I am new to this and appreciate any help you can provide
Create a property on your configuration form:
Color SelectedColor { get; private set; }
And assign users choice to it:
if (backColorDialog.Showdialog() == DialogResult.OK)
{
backColorLabel.BackColor = backColorDialog.Color;
SelectedColor = backColorDialog.Color;
}
(note there was a mistake in your code - the ; after if line)
After this, in your main form you can read it from your configuration form:
TableLayoutPanel1.BackColor = optionsForm.SelectedColor;
As noted by justin.chmura in the comments below, you can also consider a different approach using events. Your options form would raise an event when user selects a different color, and main form's event handler would apply this color instantly on the game panel. The difference is that it would update the color immediately. When it's not needed the above solution with a property is enough.

WPF 4 keyboard focus: never recieving key events

In WPF 4.0, I can't seem to get any keyboard shortcuts to work if I swap the user control in the window after it's been loaded. A code sample says a thousand words, so here's what I'm doing:
Window window = new Window { Width = 800, Height = 600 };
window.Loaded += delegate
{
editor = new EditorRoot();
window.Content = editor;
};
app.Run(window);
window gets KeyDown events (and routed commands work fine), but editor never gets any keyboard events (nor do any controls within it). I tried:
editor.Loaded += (sender, e) => Keyboard.Focus(editor);
... but that didn't do anything. EditorRoot extends UserControl and has IsFocusable=true Any ideas what's wrong?
And if this does not work - use Dispatcher.BeginInvoke. From my experience - setting focus synchronously doesn't always work. And not only in WPF 4.
Maybe you could try the FocusManager instead of your approach. I use it and it works, you can even use it in XAML:
FocusManager.FocusedElement=editor;

Disabling a control from receiving a event in C#

I have a dialog with loads of control in it. Each and evey control will be populated during the loading sequence and it might take a while for it to get completely filled. Mean while, I don't wanna allow the user to click on any of the controls. In other words, I wanna disable the control from receiving the events and I don't wanna disable the controls (as it might look odd).Also, I don't wanna subscribe and unsubscribe for the events regular intervals. Is there any way to stop the controls from listening to the events for a brief time ??
Sudarsan Srinivasan
The whole point of disabling controls is to communicate to the user that the control cannot be used at a particular time. This is a convention that users have learned and are used to, so I would advice to follow that. Not doing that may confuse the users.
The easiest way is to disable the container in which the controls are located in, rather than disabling each and every control. A better way (or at least the way that I prefer) is to have a method that will control the Visible and Enabled properties of controls based on which state the UI is in.
The easiest way is to move the control population out of the load event (if possible). Then in Load do something like:
private bool _LoadComplete;
void OnFormLoad(Object sender, EventArgs e)
{
_LoadComplete = true;
InitializeControls();
_LoadComplete = false;
}
void InitializeControls()
{
// Populate Controls
}
void OnSomeControlEvent()
{
if (_LoadComplete)
{
// Handle the event
}
}
Edit A Couple other Ideas:
Set the Application.Cursor = WaitCursor (typically will disallow clicking, but not a 100% guarantee)
Create a "Spinner" control to let the user know that the screen is busy. When loading bring it to the front so it sits on top and covers all other controls. Once you're done loading set it to visible = false and show your other controls
Unfortunately the only way i know of is to have a class variable (called something like _loading) and in each control handler do something like:
If (! _loading )
{
...
}
And in your loading code set _loading = true; once you have finished loading.
If you just want to disable user input, then you can set the form's Enabled property to false.
This has the effect of blocking user input to any of the form's controls, without changing the appearance of the controls; it's the technique used internally by the ShowDialog method.

Categories