禁用父级时,无法设置子控件的Enabled属性

时间:2015-09-23 21:09:17

标签: c# multithreading winforms c#-4.0

背景资料

我的主要Form实例名为' MainView'并包含以下内容:

  • 一个名为contentPanel的面板,其中包含各种输入控件(包括childControl,启动时禁用)。
  • BackgroundWorker控件。
单击“提交”按钮时会调用

backgroundWorker_DoWork(3-arg)contentPanel已停用,因此用户无法在处理提交内容时进行更改,垃圾邮件按钮等。如果提交成功,则还需要进行某些UI更改(下面将在“问题”部分中详细介绍)。

contentPanel相关代码

private void btnSubmit_Click(object sender, EventArgs e)
{
    ...

    Type[] parameterTypes = new Type[] { suiteRel.GetType() };

    MethodInfo method = this.GetType().GetMethod("btnSubmit_Click", parameterTypes);
    mainView.backgroundWorker_DoWork(this, method, myData);
}

/// <summary>
/// Commits changes to the database.
/// 
/// Note: This method will be executed from a non-UI thread.  As such 
/// accessing or modifying UI controls must be done via an Invoke() call.
/// </summary>
public void btnSubmit_Click(Object myData)
{
    ...

    if (success)
    {
        this.Invoke(new Action(
            () => {
                childControl.Enabled = true;
            }
        ));
    }
}

BackgroundWorker相关代码

/// <summary>
/// Starts another thread to perform a potentially long-running task (e.g. validation, database commits, etc).
/// </summary>
/// <param name="reference">
/// A reference to the control instance that owns the method to be called.
/// </param>
/// <param name="method">
/// The method to be called that will perform the work.
/// </param>
/// <param name="parameters">
/// Parameters to pass to the method when it is called.
/// </param>
public void backgroundWorker_DoWork(object reference, MethodInfo method, params object[] parameters)
{
    List<object> methodAndArgs = new List<object>();
    methodAndArgs.Add(reference);
    methodAndArgs.Add(method);
    methodAndArgs.Add(parameters);

    contentPanel.Enabled = false;
    this.UseWaitCursor = true;
    backgroundWorker.RunWorkerAsync(methodAndArgs);
}

/// <summary>
/// Starting point of a worker thread (i.e. not on the UI thread).
/// </summary>
/// <param name="sender">
/// The object that initiated the work request.
/// </param>
/// <param name="e">
/// The arguments that dictate what work to do.  In particular, e.Argument 
/// contains the parameters passed to the public backgroundWorker_DoWork().
/// </param>
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    List<object> methodAndArgs = (List<object>)e.Argument;
    object reference = methodAndArgs[0];
    MethodInfo method = (MethodInfo)methodAndArgs[1];
    object[] parameters = (object[])methodAndArgs[2];

    // call method with its parameters.
    // a.k.a. "method(param1, param2, ...);"
    method.Invoke(reference, parameters);
}

/// <summary>
/// Called on the UI thread after backgroundWorker_DoWork() completes.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    contentPanel.Enabled = true;
    this.UseWaitCursor = false;
}

问题

当&#39;方法&#39;在backgroundWorker_DoWork(2-arg)中执行,我将contentPanel中的子控件的Enabled属性设置为true。目的是在调用contentPanel时启用backgroundWorker_RunWorkerCompleted()时启用子控件。但是,在调用backgroundWorker_RunWorkerCompleted()后,子控件仍然处于禁用状态。

据我所知,在禁用其父级(例如this question要求的内容)时,无法启用 的子控件,这是 not 我想做的事情。我希望在启用其父级(contentPanel)时启用子控件(类似于在contentPanel中启用backgroundWorker_RunWorkerCompleted()时,在单击“提交”按钮之前启用的其他子控件的启用方式{1}})。

2 个答案:

答案 0 :(得分:0)

Enabled是环境属性。因此,如果您设置了子控件Enabled = false,那么即使您设置了父控件Enabled = true,如果在某个时刻显式设置了子控件,您仍然需要对子控件执行相同操作。

要在启用另一个控件时启用一个控件,请使用EnableChanged事件。 E.g。

Control c1 = ...;
Control c2 = ...;
c1.EnabledChanged += delegate {
    if (c1.Enabled)
        c2.Enabled = true;
};
  

环境属性是一个控件属性,如果没有设置,则为   从父控件中检索。例如,一个Button就有了   默认情况下,BackColor与其父Form相同。欲获得更多信息   关于环境属性,请参阅AmbientProperties类或   控制类概述。   https://msdn.microsoft.com/en-us/library/system.windows.forms.control.font%28v=vs.110%29.aspx

答案 1 :(得分:0)

我发现btnSubmit_Click()拨打的电话中隐藏了一些代码,导致childControl停用。调用堆栈看起来像这样:

btnSubmit_Click()
combobox_SelectionChangeCommitted()
clearForm()
setEnabled()

setEnabled()然后将childControl的Enabled属性设置为combobox的Enabled属性。由于contentPanel已停用,combobox报告已停用(其Enabled属性设置为true,但检索EnabledcontentPanel被禁用后,属性值返回false,这会导致childControl.Enabled被分配false

private void setEnabled(bool enabled)
{
    ...
    combobox.Enabled = enabled;
    childControl.Enabled = combobox.Enabled;
    ...
}

感谢@Loathing的专业知识。