Validation and Undo

  • Thread starter Thread starter John Richardson
  • Start date Start date
J

John Richardson

General question about how WinForms handles undoing a change during a
control's validation, if it does at all.
After a change to a control's value, if the data is determined to be
invalid, then in the control's Validating event handler, setting e.Cancel =
true will prevent the offending control from losing focus until the data in
the control is good.

If the user wants to revert to the original data, say by hitting ESC, does
the form have any kinds of default behaviours for this kind of action (ie:
undoing a change)? Or do I have to program this whole undo process
manually?

This could entail overriding the ProcessCmdKey and looking for ESC, and
storing the value of the control before the control receives focus so I can
reset it after ESC is hit.

I had thought that this was a default behaviour for some reason, but testing
this out reveals this not to be the case for my TextBox.

Are there any suggestions for a better way to implement a simple undo?
 
John,

The TextBox has undo capability, but you don't know how many changes
have been made, so you just can't unwind the undo stack.

Rather, you will have you go to the data source and get the original
value (or, store the original value when binding occurs). That's the only
way you can be sure of the original value.

Hope this helps.
 
The TextBox has undo capability

Is this only for a databound context? I looked at the interface for the
textbox and I couldn't see where the previous value of the control would be
stored... and I don't need a whole undo history. That being said, I'll
probably build it myself anyways to give myself some flexibility.


Nicholas Paldino said:
John,

The TextBox has undo capability, but you don't know how many changes
have been made, so you just can't unwind the undo stack.

Rather, you will have you go to the data source and get the original
value (or, store the original value when binding occurs). That's the only
way you can be sure of the original value.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

John Richardson said:
General question about how WinForms handles undoing a change during a
control's validation, if it does at all.
After a change to a control's value, if the data is determined to be
invalid, then in the control's Validating event handler, setting e.Cancel
= true will prevent the offending control from losing focus until the
data in the control is good.

If the user wants to revert to the original data, say by hitting ESC,
does the form have any kinds of default behaviours for this kind of
action (ie: undoing a change)? Or do I have to program this whole undo
process manually?

This could entail overriding the ProcessCmdKey and looking for ESC, and
storing the value of the control before the control receives focus so I
can reset it after ESC is hit.

I had thought that this was a default behaviour for some reason, but
testing this out reveals this not to be the case for my TextBox.

Are there any suggestions for a better way to implement a simple undo?
 
"John Richardson" <[email protected]> a écrit dans le message de [email protected]...

| >The TextBox has undo capability
|
| Is this only for a databound context? I looked at the interface for the
| textbox and I couldn't see where the previous value of the control would
be
| stored... and I don't need a whole undo history. That being said, I'll
| probably build it myself anyways to give myself some flexibility.

I can't see the previous messages in this thread, has the subject changed ?

In the absence of other replies, can I suggest you look at implementing
IEditableObject in the class whose instances you are editing. If you are
linking to a database table, then I thought that the record datatype had
undo facilities. It is not the job of the edits to maintain undo
information, that is the job of the class supplying the data.

Joanna
 
It is not the job of the edits to maintain undo information, that is the
job of the class supplying the data.

I think that I might disagree with this. I think that there should be 2
levels of editing/undoing: the individual field, and the "row", or more
generally, a set of fields. A typical form interaction will be to load
data, edit various fields, and then indicate that the data should be
saved -> this is the transaction that should be class level.

But, as the user edits a field, the control itself offers a Validation
event, which is hinting at a Transaction at the control level. So, a Field
transaction should be viewed as beginning when the control is focused,
ending when the control is unfocused, and I would think that a cancel should
be implemented by ESC, or some other commonly understood method.

For some reason, I figured this was a default behaviour of the Control
object, but it is not. In my view, this behaviour is fairly natural
assumption... it makes more sense than say the SHIFT-SPACE behaviour on the
datagrid, that is for sure.
 
"John Richardson" <[email protected]> a écrit dans le message de %[email protected]...

| But, as the user edits a field, the control itself offers a Validation
| event, which is hinting at a Transaction at the control level. So, a
Field
| transaction should be viewed as beginning when the control is focused,
| ending when the control is unfocused, and I would think that a cancel
should
| be implemented by ESC, or some other commonly understood method.
|
| For some reason, I figured this was a default behaviour of the Control
| object, but it is not. In my view, this behaviour is fairly natural
| assumption... it makes more sense than say the SHIFT-SPACE behaviour on
the
| datagrid, that is for sure.

FMPOV, the Validating event in the Control class fits very well into the
Model View Presenter framework as it is a response to a user interaction
trying to quit editing a value.

The edit is a means of entering data that will be passed to the underlhying
data member. The Validating event gives the program an opportunity to
interrupt the flow of data to the data member and prompt the edit to refresh
itself to the, as yet unchanged, underlying data member.

Joanna
 
I completely agree with what you wrote below. But it doesn't quite address
what I was asking about originially. I was using the Validation event as an
example, but my original post was about how the user can indicate aborting
an edit of an individual field, which would then undo the value -> going
back to the original previous to the edit. In this case, the *standard*
Validation event doesn't apply because the control hasn't lost focus yet.
The user is indicating that a mistake was just made, and the original value
of the field should be restored. Admittedly, this is very subtle, since
it's very similar to just forcing a failed validation procedure.

To continue your Model View Presenter paradigm, it seems useful to have a
kind of UserCancelled message to cause the display of the control to be
reloaded with previous data; it differentiates a user-initiated cancel from
failing a logic test in the Validating handler when the user tries to enter
bad data. If this is in fact a good idea, then I guess I'm surprised that
the general control interface doesn't provide any implicit methods for this.

<Tab> will change focus. Why not <ESC> to revert to the value before focus.
I guess maybe the Form is capturing Esc msgs...
Well, either way, I'll have to code what I want myself.

It's been a fun discussion.
 
"John Richardson" <[email protected]> a écrit dans le message de
news: (e-mail address removed)...

|I completely agree with what you wrote below. But it doesn't quite address
| what I was asking about originially. I was using the Validation event as
an
| example, but my original post was about how the user can indicate aborting
| an edit of an individual field, which would then undo the value -> going
| back to the original previous to the edit.

| <Tab> will change focus. Why not <ESC> to revert to the value before
focus.
| I guess maybe the Form is capturing Esc msgs...

If you implement IEditableObject in the business object whose properties you
are trying to edit, then pressing the Esc key whilst still in the edit will
revert the value in the edit to that of the underlying property. Is that
what you want ?

| Well, either way, I'll have to code what I want myself.

Not necessarily :-)

Joanna
 
That is precisely what I want, but I realise now that it can only be
acheived with databinding, which is not quite what I want, since I don't use
databinding where I can avoid it. It's interesting, because online
documentation says nothing about relating ESC, IEditableObject, and any
generic control. Most google hits discuss the DataGrid, which has several
special key behaviours defined. If this works for a textbox, I will be a
bit surprised.

Thanks for going the distance.
 
"John Richardson" <[email protected]> a écrit dans le message de (e-mail address removed)...

John, I must admit, having gone to the trouble to design a good working
BindingList and implementing all the right interfaces to support this
behaviour in a DataGridView, I had expected it to work with the edits as
well.

Surprise, surprise !! Thanks to you, I now need to delve into the inward
parts of the FCL and see why this is not happening; it is a functionality
that my client requires as well.

If you should find the answer before I do, please be good enough to drop me
a note as well as posting it here. my address is my first name at
carterconsulting, the domain is .org.uk.

Joanna
 
John, I just found out the following *horrible* idea to allow for undoing :

private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape && textBox1.CanUndo)
{
textBox1.Undo();
textBox1.ClearUndo();
}
}

....or you can do something sensible like creating an Extender Provider.

This will get added to your toolbox and you can add one of them to any form;
it will hook into the KeyDown event of any and all TExtBoxBase derivatives
on the form if you set the UndoOnEsc property of each TextBox to true :

////////////////////////////
using System;
using System.ComponentModel;
using System.Collections;
using System.Windows.Forms;

namespace // your namespace
{
[ProvideProperty("UndoOnEsc", typeof(TextBoxBase))]
public class EditUndoProvider : Component, IExtenderProvider
{
private class Properties
{
private bool undoOnEsc = false;

public bool UndoOnEsc
{
get { return undoOnEsc; }
set { undoOnEsc = value; }
}
}

private Hashtable properties = new Hashtable();

public EditUndoProvider(IContainer parent)
{
parent.Add(this);
}

bool IExtenderProvider.CanExtend(object obj)
{
return obj is TextBoxBase;
}

private Properties EnsurePropertiesExists(object key)
{
Properties p = (Properties) properties[key];

if (p == null)
{
p = new Properties();

properties[key] = p;
}

return p;
}

[Category("Behavior")]
[Description("Allows Undo when Esc key is pressed")]
[DefaultValue(false)]
public bool GetUndoOnEsc(Control c)
{
return EnsurePropertiesExists(c).UndoOnEsc;
}

public void SetUndoOnEsc(Control c, bool value)
{
EnsurePropertiesExists(c).UndoOnEsc = value;

if (value)
c.KeyDown += HandleKeyDown;
else
c.KeyDown -= HandleKeyDown;
}

private void HandleKeyDown(object sender, KeyEventArgs args)
{
if (!DesignMode)
{
TextBoxBase control = (TextBoxBase) sender;
if (args.KeyCode == Keys.Escape && control.CanUndo)
{
control.Undo();
control.ClearUndo();
}
}
}
}
}
////////////////////////

Joanna
 
Back
Top