分享在winform下實現左右布局多窗口界面-續篇


之前的這篇文章《分享在winform下實現左右布局多窗口界面》已經實現了左右布局多窗口界面,今天本來是研究基於winform的插件編程,沒想到順便又找到了另一種實現方案,這種實現方案更簡單,要寫的代碼也很少,具體實現如下。

可視化設計部份:

1.父窗口:ParentForm的IsMdiContainer 設置為 true,即:this.IsMdiContainer=true;

2.在父窗口中添加一個頂部菜單:menuStrip1,並新增一個菜單項:Windows,且將menuStrip1的MdiWindowListItem設置為該Windows菜單對象,即: this.menuStrip1.MdiWindowListItem = this.windowsToolStripMenuItem;

3.在父窗口中添加一個樹形菜單:treeView1,並將其Dock設為左靠齊,即:this.treeView1.Dock = System.Windows.Forms.DockStyle.Left;且將margin設為0;

4.在父窗口中添加一個Panel:panel1,且將其width設為3;

以下是設計后自動生成的代碼:

namespace WinFormTest
{
    partial class ParentForm
    {
        /// <summary>
        /// 必需的設計器變量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的資源。
        /// </summary>
        /// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗體設計器生成的代碼

        /// <summary>
        /// 設計器支持所需的方法 - 不要
        /// 使用代碼編輯器修改此方法的內容。
        /// </summary>
        private void InitializeComponent()
        {
            this.menuStrip1 = new System.Windows.Forms.MenuStrip();
            this.windowsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.treeView1 = new System.Windows.Forms.TreeView();
            this.panel1 = new System.Windows.Forms.Panel();
            this.menuStrip1.SuspendLayout();
            this.SuspendLayout();
            // 
            // menuStrip1
            // 
            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.windowsToolStripMenuItem});
            this.menuStrip1.Location = new System.Drawing.Point(0, 0);
            this.menuStrip1.MdiWindowListItem = this.windowsToolStripMenuItem;
            this.menuStrip1.Name = "menuStrip1";
            this.menuStrip1.Size = new System.Drawing.Size(684, 25);
            this.menuStrip1.TabIndex = 0;
            this.menuStrip1.Text = "menuStrip1";
            // 
            // windowsToolStripMenuItem
            // 
            this.windowsToolStripMenuItem.Name = "windowsToolStripMenuItem";
            this.windowsToolStripMenuItem.Size = new System.Drawing.Size(73, 21);
            this.windowsToolStripMenuItem.Text = "Windows";
            // 
            // treeView1
            // 
            this.treeView1.Dock = System.Windows.Forms.DockStyle.Left;
            this.treeView1.Location = new System.Drawing.Point(0, 25);
            this.treeView1.Margin = new System.Windows.Forms.Padding(0);
            this.treeView1.Name = "treeView1";
            this.treeView1.Size = new System.Drawing.Size(228, 380);
            this.treeView1.TabIndex = 3;
            this.treeView1.NodeMouseDoubleClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView1_NodeMouseDoubleClick);
            
            // 
            // panel1
            // 
            this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left)));
            this.panel1.BackColor = System.Drawing.Color.Red;
            this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.panel1.Cursor = System.Windows.Forms.Cursors.VSplit;
            this.panel1.Location = new System.Drawing.Point(230, 28);
            this.panel1.Margin = new System.Windows.Forms.Padding(0);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(3, 100);
            this.panel1.TabIndex = 5;
            
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(684, 405);
            this.Controls.Add(this.panel1);
            this.Controls.Add(this.treeView1);
            this.Controls.Add(this.menuStrip1);
            this.IsMdiContainer = true;
            this.MainMenuStrip = this.menuStrip1;
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.Resize += new System.EventHandler(this.Form1_Resize);
            this.menuStrip1.ResumeLayout(false);
            this.menuStrip1.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.MenuStrip menuStrip1;
        private System.Windows.Forms.ToolStripMenuItem windowsToolStripMenuItem;
        private System.Windows.Forms.TreeView treeView1;
        private System.Windows.Forms.Panel panel1;
    }
}

編碼部份:

其實上面的設計后,如果通過以下定義的方法打開一個子窗口,則直接實現了左右布局且包含多子窗口的界面。

        private void ShowChildForm<TForm>() where TForm : Form, new()
        {
            Form childForm = new TForm();
            childForm.MdiParent = this;
            childForm.Name = "ChildForm - " + DateTime.Now.Millisecond.ToString();
            childForm.Text = childForm.Name;
            childForm.Show();
        }

當然仍然有不完美的地方,那就是左邊菜單欄寬度不能動態調整,而又沒有用到splitContainer,故我們只有自己來實現,其實也很簡單,步驟如下: 

1.在父窗口構造函數中加入初始化panel1(用作分割器)位置及訂閱相關事件,代碼如下:

        public ParentForm()
        {
            InitializeComponent();

            panel1.MouseDown += panel1_MouseDown;
            panel1.MouseUp += panel1_MouseUp;
            panel1.MouseMove += panel1_MouseMove;

            panel1.Top = menuStrip1.Height;
            panel1.Left = treeView1.Left + treeView1.Width;
            panel1.Height = panel1.Parent.Height;
        }

上述代碼的作用是:1.保證panel1的高度與位置與左側樹形菜單控件相匹配;2.訂閱的三個Mouse事件主要是為了后面實現移動panel1。

2.實現訂閱的三個Mouse事件所對應的方法,分別為鼠標按下、鼠標移動、鼠標松開,代碼如下:

private bool startMove = false; //用於標記是否在移動中

        void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (startMove)
            {
                panel1.Left += e.X;
            }
        }

        void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            if (startMove)
            {
                panel1.Left += e.X;
                startMove = false;
                this.treeView1.Width = panel1.Left;
            }
        }

        void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            startMove = true;
        }

上述代碼作用:按下鼠標標記為開始移動,然后移動鼠標,若是標記移動中,說明是要移動panel1,故直接將鼠標當前的X坐標位置累加到panel1.Left屬性上,從而實現移動,當鼠標彈起后,則將樹形菜單的寬度設置為panel1.Left,從而實現樹形菜單隨panel1的移動而改變大小。

同時為了保證panel1的高度始終與樹形菜單相同,在父窗口的Resize方法加入動態調整panel1的高度,代碼如下:

        private void ParentForm_Resize(object sender, EventArgs e)
        {
            panel1.Height = panel1.Parent.Height;
        }

到此就完成了整個的實現方案,為了便於模擬在樹形菜單中雙擊打開子窗口的效果,同時也添加了如下代碼:

        private void ParentForm_Load(object sender, EventArgs e)
        {
            LoadMenuNodes();
        }


        private void LoadMenuNodes() //實現情況應該是從數據庫及用戶權限來進行動態創建菜單項
        {
            this.treeView1.Nodes.Clear();
            var root = this.treeView1.Nodes.Add("Root");
            for (int i = 1; i <= 10; i++)
            {
                var section = root.Nodes.Add("Section-" + i);
                int maxNodes = new Random(i).Next(1, 10);
                for (int n = 1; n <= maxNodes; n++)
                {
                    section.Nodes.Add(string.Format("Level-{0}-{1}", i, n));
                }
            }
        }


        private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Nodes.Count <= 0)//當非父節點(即:實際的功能節點)
            {
                ShowChildForm<ChildForm>();
            }
        }

上完整的實現代碼

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 WinFormTest
{
    public partial class ParentForm : Form
    {
        private bool startMove = false;

        public ParentForm()
        {
            InitializeComponent();

            panel1.MouseDown += panel1_MouseDown;
            panel1.MouseUp += panel1_MouseUp;
            panel1.MouseMove += panel1_MouseMove;

            panel1.Top = menuStrip1.Height;
            panel1.Left = treeView1.Left + treeView1.Width;
            panel1.Height = panel1.Parent.Height;
        }

        void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (startMove)
            {
                panel1.Left += e.X;
            }
        }

        void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            if (startMove)
            {
                panel1.Left += e.X;
                startMove = false;
                this.treeView1.Width = panel1.Left;
            }
        }

        void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            startMove = true;
        }

        private void ParentForm_Load(object sender, EventArgs e)
        {
            LoadMenuNodes();
        }



        private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Nodes.Count <= 0)//當非父節點(即:實際的功能節點)
            {
                ShowChildForm<ChildForm>();
            }
        }

        private void ParentForm_Resize(object sender, EventArgs e)
        {
            panel1.Height = panel1.Parent.Height;
        }

        private void LoadMenuNodes() //實現情況應該是從數據庫及用戶權限來進行動態創建菜單項
        {
            this.treeView1.Nodes.Clear();
            var root = this.treeView1.Nodes.Add("Root");
            for (int i = 1; i <= 10; i++)
            {
                var section = root.Nodes.Add("Section-" + i);
                int maxNodes = new Random(i).Next(1, 10);
                for (int n = 1; n <= maxNodes; n++)
                {
                    section.Nodes.Add(string.Format("Level-{0}-{1}", i, n));
                }
            }
        }


        private void ShowChildForm<TForm>() where TForm : Form, new()
        {
            Form childForm = new TForm();
            childForm.MdiParent = this;
            childForm.Name = "ChildForm - " + DateTime.Now.Millisecond.ToString();
            childForm.Text = childForm.Name;
            childForm.Show();
        }
    }
}

最終效果如下圖示:

 

說明:我這里為了體現分割器,故將其背景色設為紅色,便於大家觀察,這種解決方案與之前的解決方案功能上是相同的,但有一點小小區別,之前的解決方案中子窗口的標題欄是在父窗口的容器內,而本文的解決方案中子窗口在最大化后,子窗口的標題欄會與父窗口合並,如下圖示,至於大家用哪種依實際場景。

后續時間我會繼續研究winform關於插件式編程(近期工作任務要求),到時候同樣會分享給大家,也歡迎大家一起交流,當然高手可以無視。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM