0

我有一个 C# Form 应用程序,在主窗体中有一个 TabControl。此 TabControl 用于显示包含 CustomControl 的多个 TabPage。这个CustomControl 只是一个带有几个按钮和一个PictureBox 的面板。

这是我的应用程序启动时的图片。如您所见,选项卡控件(白色区域)为空:

应用程序以空选项卡控件开始

如果用户单击“添加图像”按钮,他们会看到一个 OpenFileDialog 来选择图像,然后使用所选文件调用addImage方法:

private void doAddImage()
{
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.Filter = Constants.Global.IMAGE_FILE_FILTER();
    if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        string imageFileName = openFileDialog.FileName;
        addImage(imageFileName);
    }
}

private void addImage(string imageFileName)
{
    // Create a new bitmap and image preview custom control. Then create a new tab
    // page and add the custom control to the tab page.
    Bitmap bitMap = new Bitmap(imageFileName);
    ImagePreviewCustomControl previewControl = new ImagePreviewCustomControl(bitMap);
    previewControl.Dock = DockStyle.Fill;
    TabPage tabPage = new TabPage(Path.GetFileNameWithoutExtension(imageFileName));
    tabPage.Controls.Add(previewControl);

    // Insert the new tab page to the right of the currently selected tab page
    int selectedTabIndex = imagesTabControl.SelectedIndex;
    imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage);
    imagesTabControl.SelectedIndex = selectedTabIndex + 1;
}

如您所见,在addImage方法中,我创建了 Bitmap、CustomControl 和 TabPage,然后将其插入到 TabControl 中。

我启动我的应用程序,单击“添加图像”按钮,一切正常。

这是一张添加了标签页的图片:

添加了标签页的应用程序

当我测试我的应用程序时,我不想每次都使用 OpenFileDialog 手动添加图像,所以在我的构造函数中,我只需使用一些我想测试的固定图像文件名调用addImage :

public ImageViewerApp()
{
    InitializeComponent();           
    addImage(@"C:\MyImages\Calculator-3-icon.png");
}

我遇到的问题是,当我尝试在构造函数中添加图像时,它不会显示在 TabControl 中。应用程序启动时是空白的(如第一张图片)。

如上所述,当应用程序已经运行并且我单击“添加图像”按钮时,它被添加就好了。

我在 TabControl 类中找到了一个名为Created的属性,其中指出:

"Gets a value indicating whether the control has been created"

因此,为了弄清楚发生了什么,我在构造函数中调用addImage之前将Created的值写入控制台。(我有一个自定义控制台来调试我的表单应用程序。)

public ImageViewerApp()
{
    InitializeComponent();
    TestConsole.WriteLine(imagesTabControl.Created);
    addImage(@"D:\Development\Work\Other\Stardock\Start8\_downloaded\Calculator-3-icon.png");
}

在构造函数中调用addImage之前Created的值是:

False

我在addImage方法中放置了另一个控制台输出:

private void doAddImage()
{
    TestConsole.WriteLine(imagesTabControl.Created);
    OpenFileDialog openFileDialog = new OpenFileDialog();
    ...
    ...
}

应用程序启动并且用户按下“添加图像”按钮后Created的值是:

真的

为什么 TabControl 没有在我的构造函数中创建(即使在 InitializeComponent() 调用之后)并且一旦应用程序运行它就是Created

=UPDATE================================================= ======================== 根据Hans Passant的建议,我在addImage方法中添加了以下代码:

int selectedTabIndex = -1;
if (imagesTabControl.TabCount > 0)
{
    selectedTabIndex = imagesTabControl.SelectedIndex;
}
else
{
    selectedTabIndex = imagesTabControl.SelectedIndex + 1;
}

imagesTabControl.TabPages.Insert(selectedTabIndex, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex;

这行不通。 ==================================================== ==============================

=UPDATE2================================================= ========================

int selectedTabIndex = imagesTabControl.SelectedIndex;
if (imagesTabControl.TabCount == 0) selectedTabIndex = -1;

imagesTabControl.TabPages.Insert(selectedTabIndex, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex;

这会导致以下异常:

{"InvalidArgument=Value of '-1' is not valid for 'index'.\r\nParameter name: index"}

==================================================== ==============================

=UPDATE3================================================= ========================

我尝试了以下代码:

int selectedTabIndex = imagesTabControl.SelectedIndex;
if (imagesTabControl.TabCount == 0) selectedTabIndex = -1;

imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex + 1;

这不会引发异常,但在构造函数中调用 addImage后再次没有添加标签页。 ==================================================== ==============================

=UPDATE4================================================= ========================

我有点放弃在构造函数中添加图像。因此,我使用的是枚举 RunMode 和该类型的变量 RUN_MODE。然后,如果 RUN_MODE == RunMode.TESTI 在我单击按钮时调用一个方法来添加随机图像。(没有使用 OpenFileDialog。我只是解析了固定目录 IMAGE_DIRECTORY 中的所有图像文件。

enum RunMode { NORMAL, TEST }

private static string IMAGE_DIRECTORY = @"D:\\Work\Images";
...
...
private void doAddImage()
{
    if (RUN_MODE == RunMode.TEST)
    {
        addRandomImage();
        return;
    }
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.Filter = Constants.Global.IMAGE_FILE_FILTER();
    if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        string imageFileName = openFileDialog.FileName;
        addImage(imageFileName);
    }
}
    
private void addRandomImage()
{
    string[] allFiles = Directory.GetFiles(IMAGE_DIRECTORY);
    List<string> imageFileNames = new List<string>();
    foreach (string file in allFiles)
    {
        bool isImageFile = Constants.Global.IMAGE_EXTENSIONS.Contains(Path.GetExtension(file));
        if (isImageFile)
        {
            imageFileNames.Add(file);
        }
    }
    int randomIndex = new Random().Next(imageFileNames.Count);
    addImage(imageFileNames.ElementAt(randomIndex));
}    

这行得通。现在,当我在 TEST_MODE 期间单击“添加图像”按钮时,我会跳过 OpenFileDialog 并添加一个随机图像。

我想了解 TabControl 的问题,但此时我只需要继续开发。我目前的解决方案效果很好。

作为一个喜欢了解一切的人,我想使用其他人的建议,所以我会继续关注这个问题以寻求解决方案。 ==================================================== ==============================

4

3 回答 3

2

JonP 的回答让我想到在插入选项卡之前等待创建窗口句柄,所以我尝试了在表单构造和选项卡控件显示之间发生的一些事件。

我发现它适用于LoadorShown事件:

  1. 右键单击设计器视图中的表单(根控件,而不是子控件)> 属性 > 事件(闪烁图标)> 行为 > 输入LoadShown事件的方法名称并确认。要生成Load事件回调,您还可以双击表单本身。这应该生成如下内容:

    this.Load += new System.EventHandler(this.Form1_Load);
    // or
    this.Shown += new System.EventHandler(this.Form1_Shown);
    
  2. 在回调中设置选项卡:

    private void Form1_Load(object sender, EventArgs e)
    {
        // Add image (this will call imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage))
        // This must be done on Load event because Insert requires
        // the window handle, which is not ready in the constructor
        addImage(@"path_to_image.png");
    }
    
于 2018-11-27T17:04:55.730 回答
1

我也遇到过这个问题并找到了解决方法;我认为这一定是一个错误Insert()

  1. 不要使用Insert(),它通常什么都不做,Add()而是使用;这可靠地将 TabPage 添加到集合的末尾。

  2. 添加后将其与您实际需要的选项卡位置交换。

imagesTabControl.TabPages.Add(tabPage);
// Now swap the two tabs:
imagesTabControl.TabPages[imagesTabControl.TabCount - 1] = imagesTabControl.TabPages[selectedTabIndex + 1];
imagesTabControl.TabPage[selectedTabIndex + 1] = tabPage;

当然,您的里程可能会有所不同:-)


停止按!更好的解决方法是Handle在调用之前读取类的成员Insert()

var handle = imagesTabControl.Handle;

Insert()完成后完美运行。是不是很明显????Handle 的帮助页面有这个可能的相关备注,表明该对象在您阅读时确实做了一些事情Handle

Handle 属性的值是 Windows HWND。如果尚未创建句柄,则引用此属性将强制创建句柄。

于 2015-12-11T12:23:57.940 回答
0

您可以从设计器中删除 TabControl,然后只需以编程方式手动创建 TabControl 并在 InitializeComponent() 之后立即将其添加到窗体中。然后在创建 TabControl 之后,调用 addImage()。就像是:

    InitializeComponent();

    TabControl tc = new TabControl();
    tc.Location = new Point(10, 10);
    tc.Size = new Size(100, 100);           
    tc.Visible = true;
    tc.Anchor = (AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Left |           AnchorStyles.Top);
    this.Controls.Add(tc)
    addImage("c:\pathToImage\image.bmp");
于 2013-10-08T05:31:40.083 回答