This is my scenario.
I have a settings page which needs to be validated. I used to do validation in settings page's OnNavigatingFrom event. So, a happy days scenario is user makes some changes and navigates away, app validates and saves the changes in the background without user having to do anything. If validation fails I cancel navigation and display a dialog box, so I only bother the user if there is an issue. This has worked well and was simple to implement:
protected async override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
if (!ValidateSettings())
{
e.Cancel = true;
Dialog dialog = new Dialog();
await dialog.ShowDialogAsync("Validation Error", "Validation error encountered", "", "Close");
}
}
After adding NavigationView control, the above approach no longer works. I am using NavigationView SelectionChanged event to perform navigation. Problem is that this event fires BEFORE the child page's OnNavigatingFrom event and navigation cannot be cancelled. What's worse I cannot even save the changes, or rather they are saved after the navigation is complete. So I cannot move some of that logic to the navigation root page.
How can I perform form validation and cancel navigation in NavigationView control?
Please note that I do not want to have a save button because it is a bad user experience. I'd rather bug the user if they make a mistake instead of every time they want to make a change.
I also do not want to validate the changes on every little change because that would also result in bad UX. For example if a user wants to clear all the check boxes before selecting one, this would not be allowed because having all check boxes unchecked is invalid. I hate it when you have to "wrestle" with an app in this way. If I want to clear the form before completing it, that is a valid approach, I don't want to annoy the user with unnecessary validation errors while they are filling up the form.
I use NavigationView control from Microsoft.UI.XAML NuGet v2.4.2
It's possible to stop navigation by using the property SelectsOnInvoked on the NavigationViewItem.
Setting this to False will stop the NavigationView from selecting the NavigationViewItem when pressed, but the ItemInvoked event is still called, so you can handle your validation there.
https://learn.microsoft.com/en-us/windows/winui/api/microsoft.ui.xaml.controls.navigationviewitem.selectsoninvoked?view=winui-2.8
Related
I want to prompt a message to the user Do You want to save the changes?? if he made some changes in any control on the current page before navigation to other page. what is the best way to do this. every control has their events. Like text-box key change event. combo box selectedItemChange event. But a lot of code have to be written in this scenario. I want this modification on each page of the project....
Thanks In Advance...
you'll atleast need to define the event handlers for the controls that can be changed.
Inside the event handlers you can just set a boolean variable to true, and check the value of the variable in OnNavigatedFrom method of the Page, and accordingly show the message.
If you use the Silverlight Navigation framework:
http://msdn.microsoft.com/en-us/library/cc838245(v=vs.95).aspx
There are events that get raised (navigating, navigated, etc...) where you can prompt the user and cancel the navigation.
I would like to remove the original event behavior of controls within a form (similar to design mode).
So, when the user clicks on the button, i only want to capture that event. I do not want the original button event to be fired. Is this somehow possible?
I am looking for a generic solution. So it should work with any form and any control within the form.
Reason: I wrote a form validation rules designer. It uses reflection to enumerate all form-types in the entry assembly. The user can then select a form type, the designer creates that form, enumerates the controls, and embedds the form in the designer panel.
clicking on a control, opens a formular designer panel, and the user can now create a formular for that control and saves the formular to a DB.
When the form is then opened in the normal "runtime" mode, it loads its validation formulars.
Events are not in fact disabled in the Winforms designer. The designer executes the constructor of the form through Reflection, everything in the InitializeComponent() method executes, including the event subscriptions. Wherever this might cause a problem, the controls check the DesignMode property (prevents a Timer from starting for example) or by custom designers. The form is displayed underneath a transparent layered window on top of which the selection rectangle and drag handles are painted. Which prevents issues with mouse clicks and keyboard focus.
You probably ought to look at this magazine article to get this working for you.
From what I understand from your question, I guess, you can still use the "DesignMode" property for this as well. In your event handling routine, you may want to bypass execution by checking on this property:
if (this.DesignMode) return;
as the first statement in your event handling block of code.
WinForms: I don't want any tab order. I want myself be able to programatically handle all the tab orders on the form with some logic that I need.
How can I completely disable tab order? I assume after that I should deal with KeyDown event of each contorl or some similar event ....
You need to override the form's ProcessCmdKey() method. Test keydata == Keys.Tab and (Keys.Shift | Keys.Tab) to detect respectively a forward and a backward tab. Return true to indicate that you've used the key and it shouldn't be used anymore. Which defeats Winforms default handling for the Tab key. No additional changes are needed to the controls.
The form's ActiveControl property tells you which control currently has the focus, you'll need to use it to figure out which control should be focused next. Beware that it can technically be null. Watch out for controls that are embedded in a container control, like a Panel or UserControl. Making this work is definitely unpleasant, also very hard to maintain. Only do this if there are a limited number of controls on the form.
As Adrian said by setting tab stop to false you can disable it
a Function like this can be usefull to diable all tabstop
private void DiableTabStop(Control ctrl)
{
ctrl.TabStop = false;
foreach (Control item in ctrl.Controls)
{
DiableTabStop(item);
}
}
and calling it at form load
DiableTabStop(this);
One approach is to set the TabStop property of every control in the form to false. This will prevent the tab key from giving the controls focus.
If you don't want to do this manually for every control (e.g. in the design view), you can create a method that will iterate over all of the controls in the form's Controls collection and set the property on each one, then call it from your form's constructor.
In addition to disabling the tab stops for the pageframe, as you mentioned, YOU want to control which "tab" is active. You can have a custom property on your form of "WhichTab" should be shown. Then, override the click event and check if the incoming sender/eventarg page is that of another page... no matter what, force focus back to the "WhichTab" YOU are in control of setting... When ready to activate said page, tell the tab control object to ACTIVATE the new page to get displayed to the user.
I'm writing a Windows application that basically runs in the background with a notification icon to interact with it. The notification icon can do basic things like exit the application or show information about it. It can also launch a modal configuration dialog.
The code that creates the dialog is pretty straightforward:
using(var frmSettings = new SettingsForm(configuration))
{
frmSettings.ConfigurationChanged += ConfigurationChangedHandler;
frmSettings.UnhandledException += UnhandledExceptionHandler;
frmSettings.ShowDialog();
}
The SettingsForm class basically has three GroupBox controls, with a Label and TextBox control in each, and 4 Button controls at the bottom: "Advanced...", "Restore Defaults", "Cancel", and "Apply". Each TextBox has a Validating event handler wired up through the designer. Each button has a Click handler wired up through the designer. Each of them does pretty obvious things: opens another modal dialog with more advanced settings, restores the textboxes to their default values, closes the dialog, or saves the changes, fires the ConfigurationChanged event, and then closes the dialog (but only if all fields are valid!).
When there is a form entry error I cancel the corresponding Validating event by setting ((CancelEventArgs)e).Cancel = true. However, the default behavior of both forms was to prevent the user from changing focus when validation failed. I found this pretty annoying and eventually found the option in the designer to still automatically validate when the user leaves the field, but to allow them to leave even if validation fails: AutoValidate = EnableAllowFocusChange.[1]
My "Apply" button Click handler looks basically like this:
private void btnApply_Click(object sender, EventArgs e)
{
try
{
if(this.ValidateChildren())
{
this.Configuration.Field1 = this.txtField1.Text;
this.Configuration.Field2 = this.txtField2.Text;
this.Configuration.Field3 = this.txtField3.Text;
if(this.Configuration.Changed)
{
this.Configuration.Save();
this.OnConfigurationChanged(new ConfigurationChangedEventArgs(
this.Configuration));
}
this.Close();
}
}
catch(Exception ex)
{
this.OnUnhandledException(new UnhandledExceptionEventArgs(
"Failed To Apply Configuration Settings",
ex));
}
}
I'm currently testing out the code by breaking on the first line and stepping through the method line by line. Essentially, ValidateChildren is returning false as expected and the entire if block, including the this.Close() are skipped. Yet, if I step all the way to the bottom of the method and then step out of it I end up back on the frmSettingsForm.ShowDialog() line and the form is magically closed.
The "Apply" button is set as the form's AcceptButton. I wonder if it's implicitly attached a handler to the button's Click event to automatically close the form when the button is pressed. That doesn't sound like it logically should be assumed, especially considering there doesn't seem to be a way to cancel the Click event, but it's the only explanation that I can come up with. To test that theory, I have tried unsetting the AcceptButton in the designer, but my form still closes when the data is invalid.
What is closing my form and how do I stop it?
[1]: If anybody else has trouble finding it, it's a form property, not a property of each individual control (as I expected it would be).
Do you have the DialogResult of the Button set? If so, when you click the Button, the DialogResult of the Form will be set to that value and the modal Form will close. To prevent this, when validation fails in your Click handler, set the Form's DialogResult to DialogResult.None.
I don't know why that happens, but you could override the event OnFormClosing and check for the value of DialogResult according to your logic.
If (DialogResult != Windows.Forms.DialogResult.Cancel )
e.Cancel = True
I've got a gridview/formview, master/detail relationship going on.
When I click a button in my formview (item template), I display an ajaxcontroltoolkit modal popup.
On this popup there is a textbox (several, actually). I want to validate the data in this textbox (at least six digits, so far I'm using a regex validator) before I dismiss the popup.
The validator works, but I can still dismiss the form by clicking OK. What I'd like to do is have the ok button on the popup disabled until the data is good.
I have tried fiddling with some stuff in javascript, but I couldn't make it work, as there seems to be some issues regarding finding controls in a formview.
Any ideas?
Thanks in advance.
Without a postback
You should be able to find a control using the following technique in JavaScript:
$document.getElementById('<%=btnSubmitForm.ClientID%>').disabled = true;
If you're using RegularExpressionValidator, this forum suggests a quick (albeit hacky) way to check and see if your form is valid, without doing a postback:
http://forums.asp.net/t/1114240.aspx
With a postback
You could put the Submit button in its own UpdatePanel, if it isn't already in one, and enable/disable it in the code behind, depending on the value of the validator's IsValid property.
If you're unable to get the enable/disable functionality working, you could simply keep the modal open, so the user can't close it until they enter valid inputs or click Cancel:
protected void BtnSubmitClick(object sender, EventArgs e)
{
if (!regexValidator.IsValid)
{
modalPopupExtender.Show();
}
}