Panel doesn't fill form when using dock fill

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

32 Replies - 6362 Views - Last Post: 30 August 2012 - 04:29 AM Rate Topic: -----

#1 RandomlyKnighted  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 116
  • View blog
  • Posts: 1,358
  • Joined: 14-January 10

Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 08:21 AM

I have a panel on my form with a tab control inside the panel. I've set the panel dock property to fill so that it would take up the entire form, but for some reason it stops once it gets larger than the tab control. Here is a screenshot of what is happening.

Posted Image

As you can see there is still a lot of space left that is not covered by the panel. I've been searching online for a solution to this and the answer that came up the most was to right click on the panel and click Bring to Front, however, that solution does not apply to my problem. Any ideas?



Spoiler


Is This A Good Question/Topic? 0
  • +

Replies To: Panel doesn't fill form when using dock fill

#2 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5464
  • View blog
  • Posts: 11,736
  • Joined: 02-June 10

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 08:27 AM

I'm sure the PANEL is full size. It just lacks content or a color your can test. But your tabcontrol is not filling out the full panel.

Set the background color of the panel to bright blue and recompile.
Was This Post Helpful? 0
  • +
  • -

#3 RandomlyKnighted  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 116
  • View blog
  • Posts: 1,358
  • Joined: 14-January 10

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 08:33 AM

Posted Image[/URL]

You were right. The panel is in fact full size, the tab control just isn't resizing like it's supposed to. Currently here is what I'm doing to make the tab control take up the space in the panel, it's just not doing it.

ltcTabControl.Height = ltcPanel.Height - 40;
ltcTabControl.Width = ltcPanel.Width;



So the width of the tab control should be the full width of the panel and the height should be enough to leave room for the button. Though as you can see in the screenshot that's not happening.
Was This Post Helpful? 0
  • +
  • -

#4 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5464
  • View blog
  • Posts: 11,736
  • Joined: 02-June 10

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 08:40 AM

Unless you are running that code on the Panel.SizeChanged event then you should expect it is only running one time; I would guess on .Load. Picture the sequence:
  • Form changes size.
  • Panel stays docked so it resizes
  • But what mechinism is telling the TabControl to keep resizing with the parent?


Take a look at the .Anchor properties of the TabConrol. You can set them to anchor all 4 sides relative to the parent. That way it will always adjust itself to being... 4 pixels within each side for example.


If you're just starting out in Windows/C#/WinForms and it is all new to you anyway, you might consider shifting to WPF instead of WinForms. Stuff like this is much better supported and WPF is the direction MS is pushing everyone into.
Was This Post Helpful? 1
  • +
  • -

#5 RandomlyKnighted  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 116
  • View blog
  • Posts: 1,358
  • Joined: 14-January 10

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 08:46 AM

Putting the code in a size changed event worked perfectly! Thank you very much!

I've been programming with C# and WinForms for a couple years just never on a project this large. Usually it's small projects to help my friends and family. This is my first freelance project so I'm learning a lot. I'll have to remember to check into WPF.
Was This Post Helpful? 0
  • +
  • -

#6 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5464
  • View blog
  • Posts: 11,736
  • Joined: 02-June 10

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 08:54 AM

I'll keep my subscription to this thread alive.
So if you have something else on this same project just add on.
Was This Post Helpful? 1
  • +
  • -

#7 RandomlyKnighted  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 116
  • View blog
  • Posts: 1,358
  • Joined: 14-January 10

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 03:44 PM

I'm currently working on a string builder that gets data from each of the tabs, but is there a way to know if the user doesn't interact with anything in a tab? Say they use the first four tabs then skip the fifth one is a there a way to know if they did anything? The only way I know is to make an if statement for each control but I'd rather do it another way if you have a better solution.
Was This Post Helpful? 0
  • +
  • -

#8 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3530
  • View blog
  • Posts: 10,933
  • Joined: 05-May 12

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 04:21 PM

Sounds like you are using the tabs as a sort of wizard. I think there are some ready made frameworks that do this for .NET. Unfortunately, even though the .NET TabControl uses the same Win32 TabControl which is used to implement the Wizard97 built into Windows, implementing a .NET wrapper around the wizard functionality was not considered a priority in .NET 1.1 and 2.0. And with no new work going into WinForms control, there probably won't be a solution coming from Microsoft unless an employee posts something in CodePlex.

Anyway, back to your issue. Your question is already hinting that you've broken encapsulation between your tabs. The outside form seems to know about the contents of tabs and is pulling the data out directly. The correct way to handle this would have been to maintain encapsulation. Something like this:
class InfoTab : TabPage
{
    // Gets set to true when text change events come in
    // from child controls on the tab page.
    // $TODO: Hook up events in sub classes
    public bool Visited { get; private set; }

    public abstract void GetPatientInfo(StringBuilder sb);
}

class CardioVascular : InfoTab
{
    public override void GetPatientInfo(StringBuilder sb)
    {
        if (!Visited)
            return;

        sb.Append(lastExamDate.ToString());
        sb.Append(attendingPhysician);
        :
    }
}

:
var sb = new StringBuilder();
foreach(var tab in tabControl.TabPages)
{
    var infoTab = (InfoTab) tab;
    infoTab.GetPatientInfo(sb);
}
var patientHistory = sb.ToString(); 


This post has been edited by Skydiver: 26 August 2012 - 04:22 PM

Was This Post Helpful? 0
  • +
  • -

#9 RandomlyKnighted  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 116
  • View blog
  • Posts: 1,358
  • Joined: 14-January 10

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 07:22 PM

You said that the visited is set to true when a text based event occurs (I'm guessing you mean like if a user enters something into a textbox). Would it also be set to true if a checkbox is checked by the user?
Was This Post Helpful? 0
  • +
  • -

#10 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3530
  • View blog
  • Posts: 10,933
  • Joined: 05-May 12

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 07:33 PM

Yes. Basically each InfoPage knows about its child controls and registers for change notifications. When they come in, the Visited boolean will be set to true.

It may sound tedious, but it's actually not that hard. Something like this C# pseudo code:
class InfoPage : TabPage
{
    private HookUpChangedEvents()
    {
        foreach(Control control in this.Controls)
        {
            if(control is TextBox)
            {
                var textBox = (TextBox) control;
                control.TextChanged += (obj, e) => { Visited = true; };
            }
            if(control is CheckBox)
            {
                var checkBox = (CheckBox) control;
                control.CheckedChanged += (obj, e) => { Visited = true; };
            }
            :
        }
    }
}



An untested alternative is to capture the Validating/Validated event on the TabPage itself. As I understand the WinForms event model, whenever the user changes focus from a field, the Validating/Validated events are fired. I know it fires for the textboxes and other controls, but I don't know if it also fires for the containing control like the TabPage. Assuming it does fire, the hard part is determining if the data changed, or that the Validating/Validated events just simply fired because of the focus change.

This post has been edited by Skydiver: 26 August 2012 - 07:39 PM

Was This Post Helpful? 0
  • +
  • -

#11 RandomlyKnighted  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 116
  • View blog
  • Posts: 1,358
  • Joined: 14-January 10

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 08:01 PM

This may sound like a dumb question, because I'm just trying to read through your code and make sure I understand what you're doing. Is what you've just shown me 2 different methods of doing this or is it 2 parts of the same solution?

You're 2nd post makes a little more sense than the 1st post, though I don't understand lines 10 and 15 after the = sign.
Was This Post Helpful? 0
  • +
  • -

#12 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3530
  • View blog
  • Posts: 10,933
  • Joined: 05-May 12

Re: Panel doesn't fill form when using dock fill

Posted 26 August 2012 - 09:44 PM

They are part of the same solution.

The lines 10 and 15 take advantage of anonymous functions. It is just a lazy way of writing:
textBox.TextChanged += new EventHandler(TextBox_TextChanged);
:
private void TextBox_TextChanged(object sender, EventArgs e)
{
    Visited = true;
}


Was This Post Helpful? 0
  • +
  • -

#13 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3530
  • View blog
  • Posts: 10,933
  • Joined: 05-May 12

Re: Panel doesn't fill form when using dock fill

Posted 27 August 2012 - 12:05 AM

Attached is a toy example that I put together quickly. You should be able to paste everything into Program.cs in a brand new project and it should just run.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CharacterSheet
{
    abstract class InfoTab : TabPage
    {
        protected TableLayoutPanel _tlp = new TableLayoutPanel();

        public bool Changed { get; set; }

        public abstract void GetInformation(StringBuilder sb);

        protected InfoTab()
        {
            _tlp.AutoSize = true;
            _tlp.Dock = DockStyle.Fill;
            _tlp.ColumnCount = 2;
            _tlp.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            _tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));

            Controls.Add(_tlp);
        }

        protected void AddControl(string label, Control control)
        {
            var lbl = new Label();
            lbl.Text = label;
            lbl.AutoSize = true;
            lbl.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Bottom;

            _tlp.Controls.Add(lbl);
            _tlp.Controls.Add(control);
        }

        protected void HookUpChangedEvents(ControlCollection controls)
        {
            foreach (Control control in controls)
            {
                if (control is TextBox)
                {
                    var tb = control as TextBox;
                    tb.TextChanged += control_Changed;
                }

                if (control is CheckBox)
                {
                    var chk = control as CheckBox;
                    chk.CheckedChanged += control_Changed;
                }

                HookUpChangedEvents(control.Controls);
            }
        }

        void control_Changed(object sender, EventArgs e)
        {
            Changed = true;
        }
    }

    class AttributesTab : InfoTab
    {
        TextBox tbStrength = new TextBox();
        TextBox tbDexterity = new TextBox();
        TextBox tbIntelligence = new TextBox();
        TextBox tbConstitution = new TextBox();
        TextBox tbWisdom = new TextBox();
        TextBox tbCharisma = new TextBox();

        public AttributesTab()
        {
            Text = "Attributes";

            AddControl("Strength", tbStrength);
            AddControl("Dexterity", tbDexterity);
            AddControl("Intelligence", tbIntelligence);
            AddControl("Constitution", tbConstitution);
            AddControl("Wisdom", tbWisdom);
            AddControl("Charisma", tbCharisma);

            HookUpChangedEvents(Controls);
        }

        public override void GetInformation(StringBuilder sb)
        {
            if (!Changed)
                return;

            sb.AppendFormat("Strength: {0}, ", tbStrength.Text);
            sb.AppendFormat("Dexterity: {0}, ", tbDexterity.Text);
            sb.AppendFormat("Intelligence: {0}, ", tbIntelligence.Text);
            sb.AppendFormat("Constitution: {0}, ", tbConstitution.Text);
            sb.AppendFormat("Wisdom: {0}, ", tbWisdom.Text);
            sb.AppendFormat("Charisma: {0}", tbCharisma.Text);
            sb.AppendLine();
        }
    }

    class DescriptionTab : InfoTab
    {
        TextBox tbDescription = new TextBox();

        public DescriptionTab()
        {
            Text = "Description";

            tbDescription.Multiline = true;
            tbDescription.Dock = DockStyle.Fill;

            AddControl("", tbDescription);

            HookUpChangedEvents(Controls);
        }

        public override void GetInformation(StringBuilder sb)
        {
            if (!Changed)
                return;

            sb.AppendFormat("Physical Description:\n{0}\n\n", tbDescription.Text);
        }
    }

    class SpellsTab : InfoTab
    {
        CheckBox chkIsMagicUser = new CheckBox();
        TextBox tbSpells = new TextBox();

        public SpellsTab()
        {
            Text = "Spells";

            tbSpells.Multiline = true;
            tbSpells.Dock = DockStyle.Fill;

            AddControl("Magic User", chkIsMagicUser);
            AddControl("Known Spells", tbSpells);

            HookUpChangedEvents(Controls);
        }

        public override void GetInformation(StringBuilder sb)
        {
            if (!Changed)
                return;

            if (chkIsMagicUser.Checked)
                sb.AppendFormat("Magic User Spells: {0}\n", tbSpells.Text);
        }
    }

    public class CharacterForm : Form
    {
        TabControl _tab = new TabControl();
        Button _btnSummarize = new Button();
        TextBox _tbSummary = new TextBox();

        public CharacterForm()
        {
            InitializeComponents();
        }

        IEnumerable<InfoTab> InfoTabs
        {
            get 
            {
                foreach (var tab in _tab.TabPages)
                    yield return (InfoTab)tab;
            }
        }

        void FillSummary()
        {
            StringBuilder sb = new StringBuilder();
            foreach (var infoTab in InfoTabs)
                infoTab.GetInformation(sb);
            _tbSummary.Text = sb.ToString();
        }

        void ResetChanged()
        {
            foreach (var infoTab in InfoTabs)
                infoTab.Changed = false;
        }

        void InitializeComponents()
        {
            Text = "Character Form";
            Size = new Size(680, 480);

            var tlpMain = new TableLayoutPanel();
            tlpMain.AutoSize = true;
            tlpMain.Dock = DockStyle.Fill;
            tlpMain.RowStyles.Add(new RowStyle(SizeType.Percent, 75));
            tlpMain.RowStyles.Add(new RowStyle(SizeType.AutoSize));
            Controls.Add(tlpMain);

            _tab.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
            tlpMain.Controls.Add(_tab);

            var tlpControls = new TableLayoutPanel();
            tlpControls.AutoSize = true;
            tlpControls.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
            tlpControls.RowStyles.Add(new RowStyle(SizeType.Percent, 1));
            tlpControls.RowStyles.Add(new RowStyle(SizeType.Percent, 3));
            tlpMain.Controls.Add(tlpControls);

            var flp = new FlowLayoutPanel();
            flp.AutoSize = true;
            flp.Anchor = AnchorStyles.Left | AnchorStyles.Right;
            tlpControls.Controls.Add(flp);

            _btnSummarize.Text = "Summarize";
            _btnSummarize.Click += (obj, e) => { FillSummary(); };
            flp.Controls.Add(_btnSummarize);

            var btnReset = new Button();
            btnReset.Text = "Reset Changed";
            btnReset.Click += (obj, e) => { ResetChanged(); };
            flp.Controls.Add(btnReset);

            _tbSummary.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
            _tbSummary.Multiline = true;
            tlpControls.Controls.Add(_tbSummary);

            _tab.TabPages.Add(new AttributesTab());
            _tab.TabPages.Add(new DescriptionTab());
            _tab.TabPages.Add(new SpellsTab());
        }

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new CharacterForm());
        }
    }
}


Attached Image
Was This Post Helpful? 2
  • +
  • -

#14 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5464
  • View blog
  • Posts: 11,736
  • Joined: 02-June 10

Re: Panel doesn't fill form when using dock fill

Posted 27 August 2012 - 06:42 AM

View PostRandomlyKnighted, on 26 August 2012 - 04:44 PM, said:

I'm currently working on a string builder that gets data from each of the tabs, but is there a way to know if the user doesn't interact with anything in a tab? Say they use the first four tabs then skip the fifth one is a there a way to know if they did anything? The only way I know is to make an if statement for each control but I'd rather do it another way if you have a better solution.


With single forms or UserControls I keep a bool for IsDirty. As soon as any value is changed then IsDirty becomes true. I usually do this through the INotifyProperyChanged event. Every property is coded to raise it. Its handler marks IsDirty as true. Saving the settings then sets it back to false.

If you want to do it on a tab by tab basis there are a couple ways you could go.
One is to make UserControls for the contents of each Tab. The nice thing about that is that you can simply check if a given UserControl is dirty. If you don't want to rework all your tabs, then you would take the IsDirty idea and multiply it by 10 tabs. IsGeneralDirty, IsNetworkDirty, IsPatientDirty...

If SkyDiver is right about you using this more like a Wizard, then make a Wizard. Give the user the experience they are used to.

Was This Post Helpful? 0
  • +
  • -

#15 RandomlyKnighted  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 116
  • View blog
  • Posts: 1,358
  • Joined: 14-January 10

Re: Panel doesn't fill form when using dock fill

Posted 27 August 2012 - 07:09 AM

I'm not exactly sure what you both mean by using it like a wizard. Could you clarify that and I'll let you know if that's what I'm trying to do or not?
Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3