【发布时间】:2022-02-05 17:49:02
【问题描述】:
这是 winforms 的 .net 问题,而不是 asp.net。
我有一个带有多个选项卡的 Windows 窗体。我在加载表单时设置了所有控件的数据绑定。但我注意到第二个选项卡上控件的数据绑定不起作用。这些绑定仅在加载表单并选择第二个选项卡时才起作用。这让我产生了怀疑:数据绑定只有在绑定控件变得可见时才起作用。
谁能告诉我这是真的还是假的?测试这个并不难,但我想知道一些确认。
谢谢
【问题讨论】:
这是 winforms 的 .net 问题,而不是 asp.net。
我有一个带有多个选项卡的 Windows 窗体。我在加载表单时设置了所有控件的数据绑定。但我注意到第二个选项卡上控件的数据绑定不起作用。这些绑定仅在加载表单并选择第二个选项卡时才起作用。这让我产生了怀疑:数据绑定只有在绑定控件变得可见时才起作用。
谁能告诉我这是真的还是假的?测试这个并不难,但我想知道一些确认。
谢谢
【问题讨论】:
你是对的。在控件可见之前,不会更新数据绑定控件。
目前我能找到的唯一参考是this MSDN thread。
【讨论】:
您的问题与 TabControl 的行为有关。见Microsoft bug report。我针对该问题发布了一个解决方法,该问题将 TabControl 子类化并在创建控件或创建句柄时“初始化”所有选项卡页。以下是解决方法的代码。
public partial class TabControl : System.Windows.Forms.TabControl
{
protected override void OnHandleCreated(EventArgs e_)
{
base.OnHandleCreated(e_);
foreach (System.Windows.Forms.TabPage tabPage in TabPages)
{
InitializeTabPage(tabPage, true, Created);
}
}
protected override void OnControlAdded(ControlEventArgs e_)
{
base.OnControlAdded(e_);
System.Windows.Forms.TabPage page = e_.Control as System.Windows.Forms.TabPage;
if ((page != null) && (page.Parent == this) && (IsHandleCreated || Created))
{
InitializeTabPage(page, IsHandleCreated, Created);
}
}
protected override void OnCreateControl()
{
base.OnCreateControl();
foreach (System.Windows.Forms.TabPage tabPage in TabPages)
{
InitializeTabPage(tabPage, IsHandleCreated, true);
}
}
//PRB: Exception thrown during Windows Forms data binding if bound control is on a tab page with uncreated handle
//FIX: Make sure all tab pages are created when the tabcontrol is created.
//https://connect.microsoft.com/VisualStudio/feedback/details/351177
private void InitializeTabPage(System.Windows.Forms.TabPage page_, bool createHandle_, bool createControl_)
{
if (!createControl_ && !createHandle_)
{
return;
}
if (createHandle_ && !page_.IsHandleCreated)
{
IntPtr handle = page_.Handle;
}
if (!page_.Created && createControl_)
{
return;
}
bool visible = page_.Visible;
if (!visible)
{
page_.Visible = true;
}
page_.CreateControl();
if (!visible)
{
page_.Visible = false;
}
}
}
【讨论】:
我们遇到了类似的问题。我们正在尝试写入 2 个绑定的、不可见的字段,以便我们可以更改写入数据集的格式。这在对象可见时工作正常,但在可见属性更改为 false 时停止工作。
为了解决这个问题,我添加了以下代码:
// Stop our screen flickering.
chSplitContainer.Panel2.SuspendLayout();
// Make the bound fields visible or the binding doesn't work.
tbxValueCr.Visible = true;
tbxValueDb.Visible = true;
// Update the fields here.
<DO STUFF>
// Restore settings to how they were, so you don't know we're here.
tbxValueCr.Visible = false;
tbxValueDb.Visible = false;
chSplitContainer.Panel2.ResumeLayout();
【讨论】:
我自己也为此苦苦挣扎,并得出结论,除了显然进行子类化(请参阅 hjb417 的答案)之外,唯一的解决方法是使另一个选项卡可见。切换到另一个选项卡并在表单可见之前立即返回上一个选项卡不起作用。如果您不想让第二个选项卡可见,我使用以下代码作为解决方法:
this.tabControl.SelectedTab = this.tabPageB;
this.tabPageB.BindingContextChanged += (object sender, EventArgs e) => {
this.tabContainerMain.SelectedTab = this.tabPageA;
};
假设 tabPageA 是可见选项卡,而 tabPageB 是您要初始化的不可见选项卡。这将切换到 pageB,并在数据绑定完成后切换回来。这对表单中的用户是不可见的。
仍然是一个丑陋的黑客,但至少这是可行的。当然,当你有多个标签时,他的代码会变得更加丑陋。
【讨论】:
这不是我直接遇到的。但是,您可能会遇到BindingContext 的问题。没有更多细节很难说,但如果我是你,我会设置一个断点并确保所有控件都绑定在同一个上下文中。
【讨论】:
根据答案,我制定了适合我的方法:
public partial class Form1: Form
{
private void Form1_Load(object sender, EventArgs e)
{
...
forceBindTabs(tabControl1);
}
private void forceBindTabs(TabControl ctl)
{
ctl.SuspendLayout();
foreach (TabPage tab in ctl.TabPages)
tab.Visible = true;
ctl.ResumeLayout();
}
}
除了解决问题之外,选项卡在开始时加载,当用户点击它们时显示更快。
【讨论】:
很抱歉对这个线程进行了死灵处理,但是使用这种方法很容易强制不可见控件的数据绑定/句柄准备好:
简单地说,假设您的控件位于标签页tpg_Second(或tabCtl.TabPages[1])中,在您对其数据进行任何操作之前,请先调用它:
tpg_Second.Show()
这不会激活任何标签页,但是 viola,控件的数据绑定现在应该可以工作了。
【讨论】: