I'm moving a Winforms app from VB to C#. I have a TrueDBGrid with a ContextMenuStrip thats pops up on a right click. When I don't handle the mnuContext Opening event the menu pops up. When I do handle the event the handler is called but the menu wont popup - even if the handler does nothing.
The code below has been trimmed to just have the handler call, so it's not what the code is doing, just the existence of the handler itself.
public void MenuOpeningHandler(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = false;
}
Setup code is:
public InvoiceListForm()
{
InitializeComponent();
mnuContext.Opening += MnuContext_Opening;
}
private void MnuContext_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
MenuOpeningHandler(sender, e);
e.Cancel = false;
}
The event appears to be stopped/Cancelled instead of continuing to propagate and open. Any idea what could be missing?
Related
Good morning guys.
I have a little problem. If I close my Mainform (Windows-App) when my second form is opened, the second form closes without using my secondForm_FormClosing Event.
Anyone have a idea to handle this?
secondForm_FormClosing
The 2nd form is an Instance of a Form/Class itself so unless you have it setup as an MDI application the 2nd form won't receive the Closing or Closed event because the program is exiting.
You can tap into the 2nd Forms FormClosing event from Form1's closing event, this is one of many ways:
public Form1()
{
InitializeComponent();
frm2.FormClosing += new FormClosingEventHandler(form2_FormClosing);
frm2.Show();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
form2_FormClosing(null, e);
}
private void form2_FormClosing(object? sender, FormClosingEventArgs e)
{
// This will only get called "directly" when the second form is
// closed otherwise it will always be called from Form1_FormClosing.
}
I'm creating a new window in On_Click method. First I tried this;
public partial class MainWindow : Window
{
CustomerOperations customerOperationsWindow;
public MainWindow()
{
customerOperationsWindow = new CustomerOperations();
InitializeComponent();
}
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
customerOperationsWindow.Owner = this;
customerOperationsWindow.Show();
}
}
It's not working so I started creating the window instance every time the user clicks on the Customers button. And I used the following codes.
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
CustomerOperations customerOperationsWindow = new CustomerOperations();
customerOperationsWindow.Owner = this;
customerOperationsWindow.Show();
}
In the new window, If user clicks to Main button, I want to navigate to main window.
private void btnMain_Click(object sender, RoutedEventArgs e)
{
this.Close();
this.Owner.Show();
}
First question: Does this.Close() releases the window instance?
Second question: Is this usage correct?
What do you think is the best practice?
Thank you all.
Window.Close() will dispose all resources allocated by the instance. That's why you cannot show it again once it was closed.
If you want to reuse the same Window instance, you should cancel the closing procedure to prevent disposal of internal resources and collapse the Window instead (by setting Window.Visibility to Visibility.Collapsed - Visibility.Collapsed is also the default value of an instantiated Window before Window.Show() is called).
Alternatively hide the Window by calling Window.Hide() (which will set the Visibility to Visibility.Hidden) instead of Window.Close().
Calling Window.Show will also set the window's visibility to Visibility.Visible.
As a matter of fact, showing a Window by setting Window.Visibility is the asynchronous version of Window.Show().
Generally, you switch between Window instances by using the Window.Activate method. Calling Window.Show on a Window that is currently showing/visible, does nothing.
public partial class MainWindow : Window
{
CustomerOperations CustomerOperationsWindow { get; }
public MainWindow()
{
InitializeComponent();
this.CustomerOperationsWindow = new CustomerOperations();
// Consider to move this logic to CustomerOperations class,
// where you can override the OnClosing method instead of subscribing to the event
this.CustomerOperationsWindow.Closing += CollapseWindow_OnClosing;
}
// Cancel close to prevent disposal and collapse Window instead
private void CollapseWindow_OnClosing(object sender, CancelEventArgs e)
{
e.Cancel = true;
this.CustomerOperationsWindow.Visibility = Visibility.Collapsed;
this.CustomerOperationsWindow.Owner.Activate();
}
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
this.CustomerOperationsWindow.Owner = this;
// Calling Show will set the Visibility to Visibility.Visible
this.CustomerOperationsWindow.Show();
}
}
Creating a Window instance allocates unmanaged resources. If this happens very frequently, you will keep the garbage collector busy. From a performance point of view you may want to avoid it and prefer to reuse the same instance.
In a common scenario this is not necessary. But since Window exposes a Hide() method, you may consider to use it instead of Close().
If you want to switch to the parent window, you can use the code this.Owner.Activate(); and if you want to close the current window, first this.Owner.Activate(); and then this.Close();.
When you enter this.Close(), the compiler does not execute the following lines after reaching it. And when a sample window still exists there is no need to recreate it
private void btnMain_Click(object sender, RoutedEventArgs e)
{
this.Owner.Activate();
this.Close();
}
I have a Windows form that has a validation event on a textBox so that if the value of that TextBox is a value that already exists it triggers a validation error.
private void txtUsername_Validating(object sender, CancelEventArgs e)
{
var alreadyExists = _logic.UserIdExists(txtUsername.Text.Trim());
if(alreadyExists)
{
errorProvider1.SetError(txtUsername, "This Userid already exists, please choose an alternative");
e.Cancel = true;
}
}
private void txtUsername_Validated(object sender, EventArgs e)
{
errorProvider1.SetError(txtUsername, "");
}
this.txtUsername.Validating += new System.ComponentModel.CancelEventHandler(this.txtUsername_Validating);
this.txtUsername.Validated += new System.EventHandler(this.txtUsername_Validated);
This results in an error image appearing next to that textBox along with a tooltip error message.
If I try and close the application, using the Close button at the top of the window, at this time I cannot as the above Event keeps firing even when I try and close the window (due to me taking focus away from the Text box).
Is there a way of closing the window, without resorting to creating an additional Close button on the form?
Based on your description, you want to maintain the default auto-validation behavior yet allow the Form to be closed using the title bar close button. I have observed that the Form.Closing event is raised in such a circumstance, however its argument Cancel property is preset to true. A simple solution is to handle this event and set e.Cancel = false. Implement any logic in the handler that you deem necessary.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing) e.Cancel = false;
}
The focus rectangle and textbox caret are lost after disabling all controls, then enabling them again (vs2012 / .NET Framework v4.5).
To reproduce the issue, just create a WinForms application project, add a button and a textbox in the form, then use this code to disable and enable both controls in the button click event:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.Enabled = false;
button1.Enabled = true;
textBox1.Enabled = true;
}
You may cycle between the textbox and the button using Tab/Shift+Tab as expected, until you press the button.
After that, the focus is partially lost (its weird). You can still use Tab/Shift+Tab and arrows to nagivate between the controls, and press Enter to active the button, but you cannot type in the textbox, nor use the space key to press the button. The textbox caret and the button focus rectangle are not displayed anymore. Changing focus to another application then returning to this form will fix the focus issue.
This issue does not happen if you don't disabled at least one control that is able to receive focus. Also the focus behavior is restored by disabling and enabling again the form, like this:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.Enabled = false;
button1.Enabled = true;
textBox1.Enabled = true;
this.Enabled = false;
this.Enabled = true;
}
I was trying to disable all the controls of a more complex form at the start of a task, so the task would enable again all controls after finishing, to prevent user input during the processing, but without locking the UI thread. I thought it was related to the cross-thread invoke calls, but I found this issue happens even with all code running on UI thread.
This undesired behavior can be fixed by calling the form Focus() method:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.Enabled = false;
button1.Enabled = true;
textBox1.Enabled = true;
this.Focus();
}
The ActiveControl is not changed after calling Focus(), so this works very well for me.
I'm having problems getting the Silverlight Button Click event to immediately update a control's UI element and then continue doing some other process. For example, update the text of a control and then do some process. I've tried calling the UpdateLayout() method but that doesn't help.
Here is some sample code:
private void button1_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "Testing";
textBlock1.UpdateLayout();
UpdateLayout();
Thread.Sleep(2000);
textBlock1.Text = "Done";
}
In that sample, the textBlock1 control will never display the text "Testing".
It's because you've blocked the UI thread with your Sleep statement which means that the text block won't update until after it's completed, but by that time you've set the text to "Done".
This doesn't work. The UI will block when you do not exit the method. This is why in Silverlight you usually do everything asynchronously:
private void button1_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "Testing";
var myTask = /* ... */
myTask.Completed += new FancyDelegate(myTask_Completed);
}
private void myTask_Completed(object sender, RoutetEventArgs e)
{
textBlock1.Text = "Done.";
}
If your tasks do not have asynchronous functions, just wrap them. But be reminded, that when you want to change your textBlock1.Text property from another thread, you must invoke it with the Dispatcher.