Click here to Skip to main content
15,861,172 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,
I am doing a parallel task using thread pool. When user clicks go button, I simply disable the go button until all the tasks are completed. I am checking button.InvokeRequired before setting the enabled property to true or false.
I facing a problem here,
1. When I let all the tasks to complete themselves before enabling the go button again then I am able to fire a click event on the button.
2. But when I cancel the remaining tasks in between and re-enable the button again, its not responding to any click events.

I finally narrowed down to setting e.cancel on TabPage_validating from different thread which is doing something wrong here and is making complete tab page not responding to events. Cancel property seems to be in sharedstate and is not getting set propely... what's the correct solution. Please help.

Following is the complete source code of a POC where I've replicated the issue,
C#
namespace POCUI
{
 partial class ThreadingTabIssue
 {
 /// <summary>
 /// Required designer variable.
 /// </summary>
 private System.ComponentModel.IContainer components = null;
 /// <summary>
 /// Clean up any resources being used.
 /// </summary>
 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
 protected override void Dispose(bool disposing)
 {
  if (disposing && (components != null))
  {
  components.Dispose();
  }
  base.Dispose(disposing);
 }
 #region Windows Form Designer generated code
 /// <summary>
 /// Required method for Designer support - do not modify
 /// the contents of this method with the code editor.
 /// </summary>
 private void InitializeComponent()
 {
  this.tabControl1 = new System.Windows.Forms.TabControl();
  this.tabPage1 = new System.Windows.Forms.TabPage();
  this.btnCancel = new System.Windows.Forms.Button();
  this.lblError = new System.Windows.Forms.Label();
  this.textBox1 = new System.Windows.Forms.TextBox();
  this.btnStart = new System.Windows.Forms.Button();
  this.tabPage2 = new System.Windows.Forms.TabPage();
  this.tabControl1.SuspendLayout();
  this.tabPage1.SuspendLayout();
  this.SuspendLayout();
  // 
  // tabControl1
  // 
  this.tabControl1.Controls.Add(this.tabPage1);
  this.tabControl1.Controls.Add(this.tabPage2);
  this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
  this.tabControl1.Location = new System.Drawing.Point(0, 0);
  this.tabControl1.Name = "tabControl1";
  this.tabControl1.SelectedIndex = 0;
  this.tabControl1.Size = new System.Drawing.Size(869, 562);
  this.tabControl1.TabIndex = 0;
  // 
  // tabPage1
  // 
  this.tabPage1.Controls.Add(this.btnCancel);
  this.tabPage1.Controls.Add(this.lblError);
  this.tabPage1.Controls.Add(this.textBox1);
  this.tabPage1.Controls.Add(this.btnStart);
  this.tabPage1.Location = new System.Drawing.Point(4, 22);
  this.tabPage1.Name = "tabPage1";
  this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
  this.tabPage1.Size = new System.Drawing.Size(861, 536);
  this.tabPage1.TabIndex = 0;
  this.tabPage1.Text = "tabPage1";
  this.tabPage1.UseVisualStyleBackColor = true;
  this.tabPage1.Validating += new System.ComponentModel.CancelEventHandler(this.tabPage1_Validating);
  // 
  // btnCancel
  // 
  this.btnCancel.Location = new System.Drawing.Point(147, 6);
  this.btnCancel.Name = "btnCancel";
  this.btnCancel.Size = new System.Drawing.Size(89, 23);
  this.btnCancel.TabIndex = 3;
  this.btnCancel.Text = "Cancel";
  this.btnCancel.UseVisualStyleBackColor = true;
  this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
  // 
  // lblError
  // 
  this.lblError.AutoSize = true;
  this.lblError.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
  this.lblError.ForeColor = System.Drawing.Color.Red;
  this.lblError.Location = new System.Drawing.Point(242, 11);
  this.lblError.Name = "lblError";
  this.lblError.Size = new System.Drawing.Size(0, 13);
  this.lblError.TabIndex = 2;
  // 
  // textBox1
  // 
  this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
   | System.Windows.Forms.AnchorStyles.Left)
   | System.Windows.Forms.AnchorStyles.Right)));
  this.textBox1.Location = new System.Drawing.Point(3, 35);
  this.textBox1.Multiline = true;
  this.textBox1.Name = "textBox1";
  this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
  this.textBox1.Size = new System.Drawing.Size(855, 498);
  this.textBox1.TabIndex = 1;
  // 
  // btnStart
  // 
  this.btnStart.Location = new System.Drawing.Point(3, 6);
  this.btnStart.Name = "btnStart";
  this.btnStart.Size = new System.Drawing.Size(138, 23);
  this.btnStart.TabIndex = 0;
  this.btnStart.Text = "Start Long Operation";
  this.btnStart.UseVisualStyleBackColor = true;
  this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
  // 
  // tabPage2
  // 
  this.tabPage2.Location = new System.Drawing.Point(4, 22);
  this.tabPage2.Name = "tabPage2";
  this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
  this.tabPage2.Size = new System.Drawing.Size(861, 536);
  this.tabPage2.TabIndex = 1;
  this.tabPage2.Text = "tabPage2";
  this.tabPage2.UseVisualStyleBackColor = true;
  // 
  // ThreadingTabIssue
  // 
  this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
  this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  this.ClientSize = new System.Drawing.Size(869, 562);
  this.Controls.Add(this.tabControl1);
  this.Name = "ThreadingTabIssue";
  this.Text = "ThreadingTabIssue";
  this.tabControl1.ResumeLayout(false);
  this.tabPage1.ResumeLayout(false);
  this.tabPage1.PerformLayout();
  this.ResumeLayout(false);
 }
 #endregion
 private System.Windows.Forms.TabControl tabControl1;
 private System.Windows.Forms.TabPage tabPage1;
 private System.Windows.Forms.TextBox textBox1;
 private System.Windows.Forms.Button btnStart;
 private System.Windows.Forms.TabPage tabPage2;
 private System.Windows.Forms.Label lblError;
 private System.Windows.Forms.Button btnCancel;
 }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;
using System.Threading;
using POCLib;
namespace POCUI
{
 public partial class ThreadingTabIssue : Form
 {
 private Int32 _numberOfObjects;
 AutoResetEvent _doneEvent;
 List<SpreadSheetHandler> handlers;
 protected Boolean SendOperationInProgress { get; set; }
 protected Boolean IsCancelled { get; set; }
 public ThreadingTabIssue()
 {
  InitializeComponent();
  ThreadPool.SetMaxThreads(100, 100);
 }
 private void btnStart_Click(object sender, EventArgs e)
 {
  _numberOfObjects = 65;
  _doneEvent = new AutoResetEvent(false);
  this.ActivateDeactivateUI(false);
  StartSpreadsheetEngine();
 }
 protected void StartSpreadsheetEngine()
 {
  try
  {
  Thread mainThread = new Thread(new ThreadStart(ProcesTasks));
  mainThread.IsBackground = true;
  mainThread.Name = "Main Worker Thread";
  mainThread.Start();
  }
  catch (Exception ee)
  {
  this.SetControlProperty(lblError, "Text", ee.Message);
  }
 }
 private void ProcesTasks()
 {
  try
  {
  IsCancelled = false;
  this.SetControlProperty(lblError, "Text", "Please Wait");
  this.SetControlProperty(textBox1, "Text", "Item Status\r\n \r\n ");
  handlers = new List<SpreadSheetHandler>();
  SendOperationInProgress = true;
  for (Int32 i = 0; i < _numberOfObjects; i++)
  {
   handlers.Add(ParallelSpreadSheetHandler.QueueSpreadSheet(Task, i));
  }
  _doneEvent.WaitOne();
  if (!IsCancelled)
   this.SetControlProperty(lblError, "Text", "Done");
  else
   this.SetControlProperty(lblError, "Text", "Cancelled");
  this.ActivateDeactivateUI(true);
  SendOperationInProgress = false;
  }
  catch (Exception ee)
  {
  this.SetControlProperty(lblError, "Text", ee.Message);
  }
 }
 protected void Task(Object obj)
 {
  try
  {
  Int32 inst = (Int32)obj;
  ThreadingTabIssueImplementation implementation = new ThreadingTabIssueImplementation();
  SpreadsheetItem item = implementation.DoSomething(inst);
  this.UpdateText(item);
  }
  catch (Exception) { }
  finally { if (Interlocked.Decrement(ref _numberOfObjects) == 0) { _doneEvent.Set(); } }
 }
 protected void CancelSend(SpreadSheetHandler[] items)
 {
  this.SetControlProperty(lblError, "Text", "Please wait while operation is cancelled");
  foreach (SpreadSheetHandler item in items)
  {
  SpreadsheetStatus status = ParallelSpreadSheetHandler.Cancel(item, false);
  if (status == SpreadsheetStatus.Cancelled)
  {
   if (Interlocked.Decrement(ref _numberOfObjects) == 0) { _doneEvent.Set(); }
  }
  }
 }
 #region UI Update Code
 private void UpdateText(SpreadsheetItem item)
 {  
  try
  {
  this.UpdateTextBoxStatus(item);
  }
  catch { }
 }
 delegate void updatetext(SpreadsheetItem item);
 void UpdateTextBoxStatus(SpreadsheetItem item)
 {
  if (textBox1.InvokeRequired)
  {
  textBox1.BeginInvoke(new updatetext(UpdateTextBoxStatus),
   new object[] { item });
  }
  else { textBox1.Text = textBox1.Text + "\r\n" + item.Message; }
 }
 delegate DialogResult ShowCustomMessage(String value);
 DialogResult ShowDialog(String value)
 {
  if (InvokeRequired)
  {
  BeginInvoke(new ShowCustomMessage(ShowDialog), new object[] { value });
  return DialogResult.OK;
  }
  return MessageBox.Show(value, "Test Poc", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
 }
 private delegate void ControlPropertyDel(Control control, string propertyName, object propertyValue);
 void SetControlProperty(Control cntrl, string propertyName, object propertyValue)
 {
  try
  {
  if (InvokeRequired)
  {
   BeginInvoke(new ControlPropertyDel(SetControlProperty),
   new object[] { cntrl, propertyName, propertyValue });
  }
  else
   cntrl.GetType().InvokeMember(propertyName, BindingFlags.SetProperty,
   null, cntrl, new object[] { propertyValue });
  }
  catch { }
 }
 void ActivateDeactivateUI(Boolean value)
 {
  try
  {
  this.SetControlProperty(btnStart, "Enabled", value);
  }
  catch (Exception ee) { throw ee; }
 }
 private delegate void ValidatingEvent(object sender, System.ComponentModel.CancelEventArgs e);
 private void tabPage1_Validating(object sender, CancelEventArgs e)
 {
  if (tabPage1.InvokeRequired)
  {
  tabPage1.BeginInvoke(new ValidatingEvent(tabPage1_Validating),
   new object[] { sender, e });
  }
  else
  {
  if (this.SendOperationInProgress)
  {
   e.Cancel = true;
   if (this.ShowDialog("Do you want to cancel") == DialogResult.OK)
   {
   IsCancelled = true;
   this.CancelSend(this.handlers.ToArray());
   }
  }
  }
 }
 private void btnCancel_Click(object sender, EventArgs e)
 {
  if (this.SendOperationInProgress)
  {
  if (this.ShowDialog("Do you want to cancel") == DialogResult.OK)
  {
   IsCancelled = true;
   this.CancelSend(this.handlers.ToArray());
  }
  }
  else { this.ShowDialog("Nothing to cancel"); }
 }
 #endregion UI Update Code
 
 }
}
using System;
using System.Collections.Generic;
using System.Threading;
namespace POCLib
{
 public sealed class SpreadSheetHandler
 {
 private WaitCallback appCallBack;
 private Object objState;
 private ExecutionContext appContext;
 internal SpreadSheetHandler(WaitCallback wCallBack, Object oState, ExecutionContext context)
 {
  appCallBack = wCallBack;
  objState = oState;
  appContext = context;
 }
 internal WaitCallback AppCallback { get { return appCallBack; } }
 internal object ObjectState { get { return objState; } }
 internal ExecutionContext Context { get { return appContext; } }
 }
 public enum SpreadsheetStatus
 {
 Completed, Cancelled, Executing, Aborted
 }
 public static class ParallelSpreadSheetHandler
 {
 private static LinkedList<SpreadSheetHandler> appCallBacks =
  new LinkedList<SpreadSheetHandler>();
 private static Dictionary<SpreadSheetHandler, Thread> executingThreads =
  new Dictionary<SpreadSheetHandler, Thread>();
 public static SpreadSheetHandler QueueSpreadSheet(
  WaitCallback callback, object state)
 {
  if (callback == null) throw new ArgumentNullException("Spreadsheet Callback method is null");
  SpreadSheetHandler item = new SpreadSheetHandler(
  callback, state, ExecutionContext.Capture());
  lock (appCallBacks) appCallBacks.AddLast(item);
  ThreadPool.QueueUserWorkItem(new WaitCallback(HandleItem));
  return item;
 }
 private static void HandleItem(object ignored)
 {
  SpreadSheetHandler item = null;
  try
  {
  lock (appCallBacks)
  {
   if (appCallBacks.Count > 0)
   {
   item = appCallBacks.First.Value;
   appCallBacks.RemoveFirst();
   }
   if (item == null) return;
   executingThreads.Add(item, Thread.CurrentThread);
  }
  ExecutionContext.Run(item.Context,
   delegate { item.AppCallback(item.ObjectState); }, null);
  }
  finally
  {
  lock (appCallBacks)
  {
   if (item != null) executingThreads.Remove(item);
  }
  }
 }
 public static SpreadsheetStatus Cancel(SpreadSheetHandler item, bool allowAbort)
 {
  if (item == null) throw new ArgumentNullException("Parallet Sheet handler is null");
  lock (appCallBacks)
  {
  LinkedListNode<SpreadSheetHandler> node = appCallBacks.Find(item);
  if (node != null)
  {
   appCallBacks.Remove(node);
   return SpreadsheetStatus.Cancelled;
  }
  else if (executingThreads.ContainsKey(item))
  {
   if (allowAbort)
   {
   executingThreads[item].Abort();
   executingThreads.Remove(item);
   return SpreadsheetStatus.Aborted;
   }
   else return SpreadsheetStatus.Executing;
  }
  else return SpreadsheetStatus.Completed;
  }
 }
 }
}
using System;
using System.Collections.Generic;
using System.Threading;
namespace POCLib
{
 public class ThreadingTabIssueImplementation
 {
 public SpreadsheetItem DoSomething(Int32 instance)
 {
  SpreadsheetItem retVal = new SpreadsheetItem();
  try
  {
  Thread.Sleep(4000);
  retVal.Message = "Completed on : " + instance;
  retVal.ItemStatus = SpreadsheetItemStatus.Success;
  }
  catch (Exception ee)
  {
  retVal.ItemStatus = SpreadsheetItemStatus.HardError;
  retVal.Message = "Error on : " + instance.ToString() + ", Message : " + ee.Message;
  }
  return retVal;
 }
 }
 [Serializable]
 public class SpreadsheetItem
 {
 private String _message = String.Empty;
 public Int32 Identity { get; set; }
 public SpreadsheetItemStatus ItemStatus { get; set; }
 public String Message { get { return _message; } set { _message = value; } }
 public EventWaitHandle ResetEvent { get; set; }
 }
 [Serializable]
 public enum SpreadsheetItemStatus
 {
 None, Warning, HardError, Success
 }
}
Posted
Updated 29-Apr-11 5:41am
v2
Comments
Ed Nutting 29-Apr-11 11:54am    
Does your ProcessTasks method actually call ActivateDeactivateUI when the tasks are cancelled? Have you debugged to check? There is so much code it is unclear/hard to read :~
dvd123 29-Apr-11 12:20pm    
I call ActivateDeactivateUI(false) once when "Start Long Operation" button is clicked. Then, I call it again once all the tasks are completed or in case it is cancelled on the main thread.

The code is very simple and can be directly copied pasted into a code behind file. I do not expect anyone debug my code, but just one line where I am trying to switch tabs and ask users to cancel the current operation before moving on to different tab.

I use tabpage.validating event for that, and set e.cancel propety to true... In simple words; I don't let the tab switching until operation is completed or fully cancelled. Cancel is where I am facing issues.

This looks like a very good case of sharedstate property (e.cancel) creating issues in multithreaded environment! and Its something, I am not finding good reference to refer to.

Your help is much appreciated.

Seriously - that is WAY too much code, especially considering that nobody here is going to want to create a whole new project with your source code just to debug something that you could more easily debug yourself.
 
Share this answer
 
Hey John,

I can understand your frustration. But, I just wanted to give the complete project "Proof Of Concept" to explain my point. E.Cancel here is simply making complete tabpage controls not responding to events.

I looks for answer on Microsoft documentation for this property and I couldn't find anything.

Only following code is worth seeing here,

C#
private delegate void ValidatingEvent(object sender, System.ComponentModel.CancelEventArgs e);
private void tabPage1_Validating(object sender, CancelEventArgs e)
{
 if (tabPage1.InvokeRequired)
 {
 tabPage1.BeginInvoke(new ValidatingEvent(tabPage1_Validating),
  new object[] { sender, e });
 }
 else
 {
 if (this.SendOperationInProgress)
 {
  e.Cancel = true;
  if (this.ShowDialog("Do you want to cancel") == DialogResult.OK)
  {
  IsCancelled = true;
  this.CancelSend(this.handlers.ToArray());
  }
 }
 }
}


hope to find an answer here. Thanks!

Regards, Vinay
 
Share this answer
 
v2
It's hard to scan all you code, but I see a design issues here. I looked at your code of button event handler and see that you're created a thread on the click. This can work in principle, but such design is more expensive (which can be quite accessible) and it is really prone to exact same problems you have described: you try to manage pretty complex issue with the life cycle control of your thread, which is not very easy.

There is much better way: create a permanent thread from the very beginning. For example, you can created a thread in the form in the handler of its event System.Windows.Forms.Form.Shown. You
also need to make sure the thread if finished or aborted when the user closed the form.

The thread should be kept from running by an instance of System.Threading.EventWaitHandle. Your buttons should only Set or Reset this instance to control the thread behavior. Initial state of the handle should be not set (reset). You thread should implement an infinite cycle calling System.Threading.EventWaitHandle.WaitOne on the same instance from the very beginning. If the instance is not set, the thread is kept by the OS in a wait state: the OS switched your thread of and never schedule it back to execution until it is waken up. You can wake up it when you tasks are ready for the thread processing, but your button click which would call System.Threading.EventWaitHandle.Set. Use auto-reset mode for this event handle. Also, the thread can be awaken by timeout (if you use any, perhaps not in this case), System.Threading.Thread.Abort or System.Threading.Thread.Interrupt.

When all the tasks are complete, the thread should notify the UI via System.Threading.Dispatcher or System.Windows.Forms.Control Invoke or BeginInvoke (Dispatcher.Invoke works like Control.Invoke but also works for WPF, not just for Forms). One of the things done by UI on this notification would re-enabling of your Start button.

By the way your InvokeRequired is not required is you know that it is called from non-UI thread — it will always return true. This is just a fool-proof method, rarely really needed, only if it is called in some method which can be called from different thread.

And advanced variant of this EventWaitHandle technique is a blocking queue when you not only synchronize thread but also feed the data to be used for processing. It can be a delegate, to abstract our the task itself.

Please see my Tips/Tricks article on the topic. I provide a full source code and usage samples. You can also use the queue available in v.4.0, but my usage also works in this case. See:
Simple Blocking Queue for Thread Communication and Inter-thread Invocation.

For detailed explanation of invocation, see also my past Solutions:
Control.Invoke() vs. Control.BeginInvoke(),
Problem with Treeview Scanner And MD5.

For passing data to a thread I provide a very convenient wrapper; see my other past Solution:
How to pass ref parameter to the thread.

Here is a collection of the references to my past answers on the related topics:
How to get a keydown event to operate on a different thread in vb.net (perhaps nothing new compared to all the above links, look just in case).

—SA
 
Share this answer
 
v2
I've already tried solving this issue from a background thread (a permanent thread) which I just start if it's not already running. I can understand that creating the thread every time is a expensive process; but this is just a proof of concept which I've added in this forum to highlight the issue.

The core thing is; calling e.cancel on tab control's validating event from thread other that GUI thread is causing child controls stop responding to events.

I am not facing any issue with the enabling or disabling of the controls here
 
Share this answer
 
Here is a very simpler code which reproduce this issue. Hope, this will be easier to understand,
//Code Behind

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
namespace POCUI
{
    public partial class tabSimple : Form
    {
        AutoResetEvent _doneEvent;
        private Boolean IsCancelled { get; set; }
        public tabSimple()
        {
            InitializeComponent();
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            _doneEvent = new AutoResetEvent(false);
            IsCancelled = false;
            try
            {
                Thread mainThread = new Thread(new ThreadStart(DoSomeThing));
                mainThread.IsBackground = true;
                mainThread.Name = "Main Worker Thread";
                mainThread.Start();
            }
            catch (Exception ee)
            {
                this.SetControlProperty(lblError, "Text", ee.Message);
            } 
        }
        private void DoSomeThing()
        {
            while (!IsCancelled)
            {
                this.SetControlProperty(textBox1, "Text", DateTime.Now.Second.ToString());
                Thread.Sleep(1000);
            }
            _doneEvent.WaitOne();
        }
        private void btnCancel_Click(object sender, EventArgs e)
        {
            if (!IsCancelled)
            {
                IsCancelled = true;
                _doneEvent.Set();
            }
        }
        private delegate void ValidatingEvent(object sender, System.ComponentModel.CancelEventArgs e);        
        private delegate void ControlPropertyDel(Control control, string propertyName, object propertyValue);
        void SetControlProperty(Control cntrl, string propertyName, object propertyValue)
        {
            try
            {
                if (InvokeRequired)
                {
                    BeginInvoke(new ControlPropertyDel(SetControlProperty),
                        new object[] { cntrl, propertyName, propertyValue });
                }
                else
                    cntrl.GetType().InvokeMember(propertyName, BindingFlags.SetProperty,
                        null, cntrl, new object[] { propertyValue });
            }
            catch { }
        }
        delegate DialogResult ShowCustomMessage(String value);
        DialogResult ShowDialog(String value)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new ShowCustomMessage(ShowDialog), new object[] { value });
                return DialogResult.OK;
            }
            return MessageBox.Show(value, "Test Poc", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
        }
        void ActivateDeactivateUI(Boolean value)
        {
            try
            {
                this.SetControlProperty(btnStart, "Enabled", value);
            }
            catch (Exception ee) { throw ee; }
        }
        private void tabPage1_Validating(object sender, CancelEventArgs e)
        {
            if (tabPage1.InvokeRequired)
            {
                tabPage1.BeginInvoke(new ValidatingEvent(tabPage1_Validating),
                    new object[] { sender, e });
            }
            else
            {
                if (!this.IsCancelled)
                {
                    e.Cancel = true;
                    if (this.ShowDialog("Do you want to cancel") == DialogResult.OK)
                    {
                        IsCancelled = true;
                        _doneEvent.Set();
                    }
                }
            }
        }
    }
}





Designer

namespace POCUI
{
    partial class tabSimple
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.tabControl1 = new System.Windows.Forms.TabControl();
            this.tabPage1 = new System.Windows.Forms.TabPage();
            this.btnCancel = new System.Windows.Forms.Button();
            this.lblError = new System.Windows.Forms.Label();
            this.btnStart = new System.Windows.Forms.Button();
            this.tabPage2 = new System.Windows.Forms.TabPage();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.tabControl1.SuspendLayout();
            this.tabPage1.SuspendLayout();
            this.SuspendLayout();
            // 
            // tabControl1
            // 
            this.tabControl1.Controls.Add(this.tabPage1);
            this.tabControl1.Controls.Add(this.tabPage2);
            this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tabControl1.Location = new System.Drawing.Point(0, 0);
            this.tabControl1.Name = "tabControl1";
            this.tabControl1.SelectedIndex = 0;
            this.tabControl1.Size = new System.Drawing.Size(354, 83);
            this.tabControl1.TabIndex = 1;
            // 
            // tabPage1
            // 
            this.tabPage1.Controls.Add(this.textBox1);
            this.tabPage1.Controls.Add(this.btnCancel);
            this.tabPage1.Controls.Add(this.lblError);
            this.tabPage1.Controls.Add(this.btnStart);
            this.tabPage1.Location = new System.Drawing.Point(4, 22);
            this.tabPage1.Name = "tabPage1";
            this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
            this.tabPage1.Size = new System.Drawing.Size(346, 57);
            this.tabPage1.TabIndex = 0;
            this.tabPage1.Text = "tabPage1";
            this.tabPage1.UseVisualStyleBackColor = true;
            this.tabPage1.Validating += new System.ComponentModel.CancelEventHandler(this.tabPage1_Validating);
            // 
            // btnCancel
            // 
            this.btnCancel.Location = new System.Drawing.Point(147, 6);
            this.btnCancel.Name = "btnCancel";
            this.btnCancel.Size = new System.Drawing.Size(89, 23);
            this.btnCancel.TabIndex = 3;
            this.btnCancel.Text = "Cancel";
            this.btnCancel.UseVisualStyleBackColor = true;
            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
            // 
            // lblError
            // 
            this.lblError.AutoSize = true;
            this.lblError.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.lblError.ForeColor = System.Drawing.Color.Red;
            this.lblError.Location = new System.Drawing.Point(242, 11);
            this.lblError.Name = "lblError";
            this.lblError.Size = new System.Drawing.Size(0, 13);
            this.lblError.TabIndex = 2;
            // 
            // btnStart
            // 
            this.btnStart.Location = new System.Drawing.Point(3, 6);
            this.btnStart.Name = "btnStart";
            this.btnStart.Size = new System.Drawing.Size(138, 23);
            this.btnStart.TabIndex = 0;
            this.btnStart.Text = "Start Long Operation";
            this.btnStart.UseVisualStyleBackColor = true;
            this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
            // 
            // tabPage2
            // 
            this.tabPage2.Location = new System.Drawing.Point(4, 22);
            this.tabPage2.Name = "tabPage2";
            this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
            this.tabPage2.Size = new System.Drawing.Size(342, 35);
            this.tabPage2.TabIndex = 1;
            this.tabPage2.Text = "tabPage2";
            this.tabPage2.UseVisualStyleBackColor = true;
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(6, 35);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(100, 20);
            this.textBox1.TabIndex = 2;
            // 
            // tabSimple
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(354, 83);
            this.Controls.Add(this.tabControl1);
            this.Name = "tabSimple";
            this.Text = "tabSimple";
            this.tabControl1.ResumeLayout(false);
            this.tabPage1.ResumeLayout(false);
            this.tabPage1.PerformLayout();
            this.ResumeLayout(false);
        }
        #endregion
        private System.Windows.Forms.TabControl tabControl1;
        private System.Windows.Forms.TabPage tabPage1;
        private System.Windows.Forms.Button btnCancel;
        private System.Windows.Forms.Label lblError;
        private System.Windows.Forms.Button btnStart;
        private System.Windows.Forms.TabPage tabPage2;
        private System.Windows.Forms.TextBox textBox1;
    }
}
 
Share this answer
 
v2
This seems like a Bug in Microsoft control library. Following is a very simple code snippet, which demonstrates if we show dialog box in tab_validating event to prevent tab switching and do a e.cancel to prevent tab switching; controls on the tab page go in invalid state and stop responding to events.

What to do now???????

C#
private void btnStart_Click(object sender, EventArgs e)
{
    MessageBox.Show("Start Clicked");
}

private void tabPage1_Validating(object sender, CancelEventArgs e)
{
    DialogResult result = MessageBox.Show("Do you Want to Cancel tab switch", "Test Poc", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
    if (result == DialogResult.OK)
    {
        e.Cancel = true;
    }
}

private void btnCancel_Click(object sender, EventArgs e)
{
    MessageBox.Show("Cancel Clicked");
}
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900