Restrict button click on telerik radgridview cellValidating event - winforms - winforms

I was testing its cellValidating event which has some problem or may be i am missing something. When the radgridview cell in in edit mode i cannot click anywhere on the form thats fine here. But when i click on button, code executes and my form hangs. So my question is how can i disable code execution on button click when radgridview cell is in edit mode during cellValidating event. Note: When i debug code and insert breakpoints on cellValidating event and button. Code works well and button code does not executes. Following is the code that i am using.If anyone can immediate answer i shall be very thankful to him.
Private Sub rgv_CellValidating(sender As System.Object, e As Telerik.WinControls.UI.CellValidatingEventArgs) Handles rgv.CellValidating
Dim column As GridViewDataColumn = TryCast(e.Column, GridViewDataColumn)
If TypeOf e.Row Is GridViewDataRowInfo AndAlso column IsNot Nothing AndAlso column.Name = "ProductId" Then
If String.IsNullOrEmpty(DirectCast(e.Value, String)) OrElse DirectCast(e.Value, String).Trim() = String.Empty Then
e.Cancel = True
DirectCast(e.Row, GridViewDataRowInfo).ErrorText = "Validation error!"
Else
DirectCast(e.Row, GridViewDataRowInfo).ErrorText = String.Empty
End If
End If

The phenomnenon you describe about buttoncode still executing also is true for ribbonmenu buttons and ribbonmenutabs. The hanging up problem I couldn't reproduce so I guess it has to do with the code of your executed buttons there.
For a possible workaround you could put a private variable into your form and in the cellvalidation code set it to true if an error occurs and false if no error occurs (and naturally set it fo false in the form initialization code).
Then within the buttons code you test for the variables value if its true no code is executed.
Thus if you have a ribbonform (or any other form) as class:
public partial class MF : RadRibbonForm
{
private bool _hasValidationError;
public MF()
{
...//Normal construction handler code
_hasValidationError = false;
}
void MF_CellValidating(objec sender, CellValidatingEventArgs e)
{
.....//Do validation and set e.Cancel true if the validation fails.
if (e.Cancel)
{
hasValidationError = true;
}
else
{
hasValidationError = false;
}
}
private void MyButton_Click(object sender, EventArgs e)
{
if (_hasValidationError)
{
// Before return you could put in a messagebox that there are cell errors that need to be looked at first
return;
}
else
{
.......//Button code execution occurs here
}
}
With this code you can make sure that the code of the buttons you don't want to be executed won't get executed on an Cell validation error.
The Code is in C# but should work similar for VB winforms.

This seems to be a known issue with the grid issue link.
There is also work around for the issue provided:
bool validating = false;
void radGridView1_CellValidating(object sender, Telerik.WinControls.UI.CellValidatingEventArgs e)
{
if (e.Value.ToString().Length < 5)
{
e.Cancel = true;
validating = true;
e.Row.ErrorText = "Validation error!";
}
else
{
validating = false;
}
}
private void radButton1_Click(object sender, EventArgs e)
{
if (!validating)
{
Debug.WriteLine("Executed");
}
}

Related

textbox validated method does not work while assigning value to textbox

I am using c#.net 2.0 winforms. I use errorprovider control in my form to validate a textbox. While I programatically assign value to that textbox. textbox validated method does not take the value from the textbox or considers it a blank value. How can I validate my textbox by without entering value in the textbox. Here is the code
private void textBox6_Validated(object sender, EventArgs e)
{
bTest6 = txtRegExPinIsValid(textBox6.Text);
if (bTest6)
{
this.errorProvider1.SetError(textBox6, "");
}
else
{
this.errorProvider1.SetError(textBox6, "This field must contain Exactly 6 digits");
}
}
private bool txtRegExPinIsValid(string textToValidate)
{
Regex TheRegExpression;
string TheTextToValidate;
string TheRegExTest = #"^\d{6}$";
TheTextToValidate = textToValidate;
TheRegExpression = new Regex(TheRegExTest);
// test text with expression
if (TheRegExpression.IsMatch(TheTextToValidate))
{
return true;
}
else
{
return false;
}
}
While performing update operation I fill the textbox with values from the ms access table. If the value is correct, just leave it otherwise I have to update it. Please help me. Thanks in advance
I would recommend placing the validation code in a separate method. Call that method from both the Validated event and the location in your code where you need to programatically validate, as shown below:
// Call this from wherever you need to validate a TextBox
void PerformValidation(TextBox textBox)
{
bTest6 = txtRegExPinIsValid(textBox6.Text);
if (bTest6)
{
this.errorProvider1.SetError(textBox6, "");
}
else
{
this.errorProvider1.SetError(textBox6, "This field must contain Exactly 6 digits");
}
}
private void textBox6_Validated(object sender, EventArgs e)
{
PerformValidation(textBox6);
}

Working with ProgressBar and ComboBox

I'm in trouble with a Marquee ProgressBar. I need to execute a method (refreshList()) to get a List<string>. Then I assign this List to a ComboBox, so ComboBox refreshes with the new Items. As refreshList() take 3 or 4 sec, I wanted to run a Marquee ProgressBar. But I couldn't. ProgressBar is ok, but ComboBox doesn't load new Items.
My refreshList() method:
private void refreshList(List<string> list)
{
albumList.DataSource = null;
albumList.DataSource = list;
}
I have the following code, it works fine:
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
refreshList(N.getList(folderPath));
}
}
But I added a ProgressBar and wrote this code:
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
bgWorker.WorkerReportsProgress = true;
bgWorker.RunWorkerAsync();
}
}
And I placed refreshList() in doWork() method:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
refreshList(N.getList(folderPath));
}
But unfortunately this isn't working. Can anybody help me solving this problem? Thanks in advance.
You can use the MarqueeAnimationSpeed and Value properties of the ProgressBar control to stop and start the Marquee. There's no need to use WorkerReportsProgress* as you aren't incrementing a normal progress bar - you just want to "spin" the Marquee.
You can do something like the following:
public Form1()
{
InitializeComponent();
//Stop the progress bar to begin with
progressBar1.MarqueeAnimationSpeed = 0;
//If you wire up the event handler in the Designer, then you don't need
//the following line of code (the designer adds it to InitializeComponent)
//backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
//This line effectively starts the progress bar
progressBar1.MarqueeAnimationSpeed = 10;
bgWorker.RunWorkerAsync(); //Calls the DoWork event
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = N.getList(folderPath); //Technically this is the only work you need to do in the background
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//these two lines effectively stop the progress bar
progressBar1.Value = 0;
progressBar1.MarqueeAnimationSpeed = 0;
//Now update the list with the result from the work done on the background thread
RefreshList(e.Result as List<String>);
}
private void RefreshList(List<String> results)
{
albumList.DataSource = null; //You don't need this line but there is no real harm.
albumList.DataSource = list;
}
Remember to wire up the RunWorkerCompleted event to backgroundWorker1_RunWorkerCompleted via the Properties bar, Events section in the designer.
To begin with, we start the ProgressBar's animation by setting the MarqueeAnimationSpeed property to a non-zero positive number as part of your successful folder selection.
Then, after calling RunWorkerAsync, the code builds your list in the DoWork method, then assigns the result to the DoWorkEventArgs, which get passed to the RunWorkerCompleted event (which fires when DoWork is finished).
In the backgroundWorker1_RunWorkerCompleted method, we stop the progress bar (and set it's value to zero to effectively return it to it's original state), and then we pass the list to the refreshList method to databind it and populate the ComboBox.
Tested using VS2012, Windows Forms, .Net 4.0 (with a Thread.Sleep to emulate the time taken for N.getList)
*WorkerReportsProgress, and the associated ReportProgress method/event are used when you want to increment the progress bar - you can tell the GUI that you are 10% done, 20% done, 50% done etc etc.

2 Issues with BackgroundWorker component

Firstly, I know I should be using proper Threading techniques (Threadpool, BeginInvoke, etc.) to accomplish this, but thats a bit over my head currently and will call for some time to read over material and understand it (if you have any URL references for my scenario, please feel free to post it).
In the interim I am using the backgroundWorker to pull a very large resultset and populate a DatagridView with it. I successfully create a SortableBindingList<TEntities> in my DoWork event and pass that out in the result. And in the RunWorkerCompleted event, I cast and bind that SortableBindingList<TEntities> to my Grid. My 2 main areas of concern are as follows:
1) Access to private variables.
I want to pass one of two parameters List<long> into my DoWork event, but run a different query depending on which list was passed to it. I can get around this by declaring a class-level private boolean variable that acts a flag of sorts. This seems silly to ask, but in my DoWork, am I allowed to access that private variable and route the query accordingly? (I've tested this and it does work, without any errors popping up)
private bool SearchEngaged = false;
private void bgw_DoWork(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
e.Result = GetTasks((List<long>)e.Argument, worker, e);
}
SortableBindingList<Task> GetTasks(List<long> argsList, BackgroundWorker worker, DoWorkEventArgs e) {
SortableBindingList<Task> sbl = null;
if (worker.CancellationPending) {
e.Cancel = true;
}
else {
if (SearchEngaged) {
sbl = DU.GetTasksByKeys(argsList);
}
else {
sbl = DU.GetTasksByDivision(argsList);
}
}
return sbl;
}
2) UI Thread freezes on beginning of RunWorkerCompleted.
Ok, I know that my UI is responsive during the DoWork event, 'cos it takes +/- 2seconds to run and return my SortableBindingList<Task> if I don't bind the List to the Grid, but merely populate it. However my UI freezes when I bind that to the Grid, which I am doing in the RunWorkerCompleted event. Keep in mind that my Grid has 4 image columns which I handle in CellFormatting. This process takes an additional 8 seconds to accomplish, during which, my UI is completely non-interactive. Im aware of the cross-thread implications of doing so, but is there any way I can accomplish the Grid population and formatting either in the background or without causing my UI to freeze? RunWorkeCompleted looks like so:
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Cancelled) {
lblStatus.Text = "Operation was cancelled";
}
else if (e.Error != null) {
lblStatus.Text = string.Format("Error: {0}", e.Error.Message);
}
else {
SortableBindingList<Task> sblResult = (SortableBindingList<Task>)e.Result;
dgv.DataSource = sblResult;
dgv.Enabled = true;
TimeSpan Duration = DateTime.Now.TimeOfDay - DurationStart;
lblStatus.Text = string.Format("Displaying {0} {1}", sblResult.Count, "Tasks");
lblDuration.Visible = true;
lblDuration.Text = string.Format("(data retrieved in {0} seconds)", Math.Round(Duration.TotalSeconds, 2));
cmdAsyncCancel.Visible = false;
tmrProgressUpdate.Stop();
tmrProgressUpdate.Enabled = false;
pbStatus.Visible = false;
}
}
Sorry for the lengthy query, but I will truly appreciate your responses! thank you!
Your code appears to be doing exactly the right thing.
As for the 8 seconds that it takes for the UI thread to update the screen, there's not much you can do about that. See my answer to this question.
To optimise the UI part, you could try calling SuspendLayout and ResumeLayout on the grid or its containing panel.
You could also look at trying to reduce the amount of processing that is done during the data binding. For example:
Calculations done in the grid could be moved into the data model (thereby doing them in the worker thread).
If the grid auto-calculates its columns based on the data model, then try hard-coding them instead.
EDIT: Page the data in the Business Layer and make the grid only show a small number of rows at a time.
I think the easiest solution for your problem is setting the datasource of your grid in DoWork instead of RunWorkerCompleted using Dispatcher.BeginInvoke which you have mentioned yourself. Something like this:
private bool SearchEngaged = false;
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
SortableBindingList<Task> sblResult = GetTasks((List<long>)e.Argument, worker, e);
BeginInvoke((Action<object>)(o => dataGridView1.DataSource = o), sblResult);
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled) {
lblStatus.Text = "Operation was cancelled";
}
else if (e.Error != null) {
lblStatus.Text = string.Format("Error: {0}", e.Error.Message);
}
else
{
dgv.Enabled = true;
TimeSpan Duration = DateTime.Now.TimeOfDay - DurationStart;
lblStatus.Text = string.Format("Displaying {0} {1}", sblResult.Count, "Tasks");
lblDuration.Visible = true;
lblDuration.Text = string.Format("(data retrieved in {0} seconds)", Math.Round(Duration.TotalSeconds, 2));
cmdAsyncCancel.Visible = false;
tmrProgressUpdate.Stop();
tmrProgressUpdate.Enabled = false;
pbStatus.Visible = false;
}
}
As far as the private variable issue is concerned, I don't think it will be of any problem in your case. In case you are changing it using some UI event, just mark the private field as volatile. The documentation of the volatile keyword can be found here:
http://msdn.microsoft.com/en-us/library/x13ttww7.aspx

why form_closing() is firing twice?

I am working on a windows form application. I want to show user a message stating close reason when user clicks "X" button in the main window.With "X" button i mean "close" button in "minimize","maximize" and "close" tray in windows.
I have written this code.
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("This application is closing down because of " + e.CloseReason.ToString() + ". Do you really want to close it ?", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
Application.Exit();
}
}
Now what happens is,If user clicks no to message box,event is discarded and when user clicks yes,form_closing() fires again and shows other messagebox.So messagebox is shown twice.I want to show it once.Please help and tell why is it firing twice.
You can skip the else part of your application. If your form is main form of application, it will exit anyway.
Application.Exit() causes all windows to close. Your "first" close is still pending, so form is not yet closed and Application.Exit() tries to close your form for the second time.
You can try this:
bool closingPending = false;
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (closingPending) return;
if (MessageBox.Show("This application is closing down because of " + e.CloseReason.ToString() + ". Do you really want to close it ?", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
closingPending = true;
Application.Exit();
}
}
I know this thread is a bit old, but why not:
$Application.OpenForms["NameOfMainForm"].Close;
I know this is old and I stumbled upon this question as I encountered the same behavior. I'm using .Net 4.5 and here is how I went about this issue:
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
if (MessageBox.Show("This application is closing down because of " + e.CloseReason.ToString() + ". Do you really want to close it ?", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
Application.Exit();
}
}
}
You can find more information about CloseReason enumeration here: http://msdn.microsoft.com/en-us/library/system.windows.forms.closereason.aspx
Why Application.Exit in the else branch? This is done automatically and may solve your problem.
Private Sub ClaimEditor_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If MsgBox("Edit mode active. Exit without saving?", MsgBoxStyle.YesNo Or MsgBoxStyle.Question, "Edit mode") <> MsgBoxResult.Yes Then
e.Cancel = True
Exit Sub
'Else
' e.Cancel = False
End If
WriteIntoRregistry()
RemoveHandler Me.FormClosing, AddressOf ClaimEditor_FormClosing
Application.Exit()
End Sub
I had this same issue and determined that the Application.Exit() was calling the FormClosing event.
Only put Application.Exit() in the FormClosed event, instead of the FormClosing event.
Use this code:
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (closingPending) return;
if (MessageBox.Show("This application is closing down because of " +
e.CloseReason.ToString () + ". Do you really want to close it ?", ""
, MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
closingPending = true;
// Application.Exit(); <-- Remove this
}
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
Application.Exit(); <-- Put it here.
}
I think #Tornado726 already answered the best possible answer for all. But there is just one Copy/Paste mistake I guess (typed form_closing twice)
Private Sub FORM1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
Select Case (MessageBox.Show("Do you really want to close?", "Quit", MessageBoxButtons.YesNo))
Case MsgBoxResult.No
e.Cancel = True
End Select
End Sub
Private Sub FORM1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
Application.Exit()
End Sub
try this: this will be a great help
private void Master_FormClosing(object sender, FormClosingEventArgs e)
{
DialogResult result = MessageBox.Show("Do you really want to exit the program?", "Data Patch", MessageBoxButtons.YesNo);
if (result != DialogResult.Yes)
{
e.Cancel = true;
}
}
Application.Exit() calls frmX_FormClosing().
That's why FormClosing() gets called twice.
I've just had that same problem. This is what I did to get around it:
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("This application is closing down because of " + e.CloseReason.ToString() + ". Do you really want to close it ?", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
try
{
Environment.Exit(0); // It will try to close your program "the hard way"
}
catch (Exception)
{
Application.Exit(); // If a Win32 exception occurs, then it will be able to close your program "the normal way"
}
}
}
I'm sure it's going to work for you, if you haven't already found a solution or even given up on that code as it's been quite a while.

Detecting the user pressing F10 in WPF

My WPF application has behaviour triggered by the functions keys (F1-F12).
My code is along these lines:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.F1:
...
case Key.F2:
...
}
}
This works for all F-keys except F10. Debugging, I find that e.Key == Key.System when the user presses F10.
In the enum definition, F10 = 99 and System = 156, so I can rule out it being a duplicate enum value (like PageDown = Next = 20).
So, how do I tell when the user presses F10?
Is it safe to check for Key.System instead? This feels a little dirty - might it be possible that Key.System would ever result from some other key being pressed? Or is there some setting somewhere that will make F10 report as Key.F10?
In addition to Yacoder's response, use the following to check for the F10 key:
case Key.System:
if (e.SystemKey == Key.F10)
{
// logic...
}
The SystemKey property will tell you which System key was pressed.
F10 launches the window menu. It's the same in all Windows apps.
It seems that Key.System is the expected value for the F10 key.
Answer with DataContext:
public partial class BankView : UserControl
{
public BankView()
{
InitializeComponent();
this.KeyDown += new KeyEventHandler(BankView_KeyDown);
}
private void BankView_KeyDown(object sender, KeyEventArgs e)
{
try
{
switch (e.Key)
{
case Key.F4:
((BankViewModel)DataContext).OpenAccount();
break;
}
}
catch (Exception ex)
{
...
}
}
This worked for me, for F1
Private Sub Window_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If (e.Key = Key.F1) Then
ShowHelp()
End If
End Sub

Resources