【问题标题】:Cannot set Enabled attribute of child control while parent is disabled禁用父控件时无法设置子控件的启用属性
【发布时间】:2015-09-23 21:09:17
【问题描述】:

背景资料

我的主窗体实例名为“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;
}

问题

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

我了解在禁用父控件的同时启用 的子控件是不可能的(例如,this question 要求的内容),这是强> 我正在尝试做的事情。我希望在启用其父控件 (contentPanel) 时启用子控件(类似于在单击提交按钮之前启用的其他子控件在backgroundWorker_RunWorkerCompleted() 中启用contentPanel 时重新启用的方式)。

【问题讨论】:

  • 你有一些奇怪的意大利面条代码,很难弄清楚你为什么要做你正在做的事情。我想简单的问题是,success 是真的吗?您没有很好地记录该变量。
  • @LarsTech 是的,success 通常是正确的。我已经使用断点来验证 childControl.Enabled = true; 确实被执行了。我选择这种架构是因为 (1) 我有一个长时间运行的提交过程,当在 UI 线程上执行时会导致应用程序挂起,直到提交完成,以及 (2) 我的应用程序中有多个面板都需要表现提交时相同。

标签: c# multithreading winforms c#-4.0


【解决方案1】:

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

要在另一个控件启用时启用一个控件,请使用EnableChanged 事件。例如

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

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

【讨论】:

  • 我不确定我是否理解。你提到Enabled 是一个环境属性,你能更详细地解释一下吗?我从未听说过环境属性,也找不到太多文档。
  • 另外,需要明确的是,我设置了childControl.Enabled = true;,但是当启用父级 (contentPanel) 时(例如,childControl 保持禁用状态),它不会受到尊重。感谢您对 EnabledChanged 事件的建议。
  • @ErikW 设置断点并调试您的代码。您可能正在将Enabled 设置在不同的控件上,或者其他易于修复的控件上。使用有关环境属性的更多信息编辑了答案。
【解决方案2】:

我发现隐藏在来自btnSubmit_Click() 的调用中的一些代码正在禁用childControl。调用堆栈如下所示:

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

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

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

感谢@Loathing 提供的专业知识。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-19
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    相关资源
    最近更新 更多