2

http://i.stack.imgur.com/v58ov.png

见上图。这是 Visual Studio 选项表单的屏幕截图。

左侧本质上是一个 TreeView。右侧是更改程序选项的各种控件。当 TreeView 中的节点被选中时,右侧会发生变化,显示不同的选项。

你如何编写这样的程序?右侧是否只有 50 个重叠的面板,节点的选择只是改变了哪个面板是可见的?如果是这种情况,您将如何管理这种情况?这将是一个混乱的设计师。

4

3 回答 3

6

不,您不会制作 50 个重叠的面板。只需创建几个用户控件,例如,链接节点标签上的类型。您可以使用激活器来创建控件。创建 1 个树视图和 1 个面板:(伪代码)

// create nodes:
TreeNode item = new TreeNode();

item.Tag = typeof(UserControl1);

TreeView.Nodes.Add( item );


// field currentControl
UserControl _currentControl;


// on selection:
TreeViewItem item = (TreeViewItem)sender;

if(_currentControl != null)
{
   _currentControl.Controls.Remove(_currentControl);
   _currentControl.Dispose();
}

// if no type is bound to the node, just leave the panel empty
if (item.Tag == null)
  return;

_currentControl = (UserControl)Activator.Create((Type)item.Tag);
Panel1.Controls.Add(_currentControl);

下一个问题是,“我想在控件中调用保存方法或 RequestClose 方法”。为此,您应该在控件上实现一个接口,并且当您切换节点时,只需尝试将 _currentusercontrol 转换为 IRequestClose 接口并调用例如 bool RequestClose(); 方法。

 // on selection:
 TreeViewItem item = (TreeViewItem)sender;

 if(_currentControl != null)
 {
    // if the _currentControl supports the IRequestClose interface:
    if(_currentControl is IRequestClose)
        // cast the _currentControl to IRequestCode and call the RequestClose method.
        if(!((IRequestClose)_currentControl).RequestClose())
             // now the usercontrol decides whether the control is closed/disposed or not.
             return;

    _currentControl.Controls.Remove(_currentControl);
    _currentControl.Dispose();
 }

 if (item.Tag == null)
   return;

_currentControl = (UserControl)Activator.Create(item.Tag);
Panel1.Controls.Add(_currentControl);

但这将是下一步。

于 2013-08-10T22:27:26.440 回答
0

对我来说,常见的设计是左侧的经典树视图和右侧的“内容区域”。当用户在树视图中选择某些内容时,您会在内容区域中加载相关视图。在实现这些内容的方法有很多不同之后,例如,自动化会根据一个对象列表生成树视图,该对象包含要进行安装的视图类型,并创建一个通用的实例化器,何时选择项目以创建相关视图,不管怎样,背景还是一样的。要恢复,树视图,只需根据所选项目在内容区域中创建视图。(我在工作中见过几个这样的屏幕,大多数时候都是这样)

于 2013-08-10T22:21:47.880 回答
0

在检查了几个选项后,我的方法是继承 TabControl 组件,使控件的页面可以用作分页面板,并添加功能以使选项卡在运行时不显示。然后,通过创建一个依赖于 TabPages 的名为 Pages 的属性,我可以以语义正确的方式引用每个页面,从而能够将每个页面作为 Pages 集合的一部分进行管理,并且还可以通过文档资源管理器进行分层管理。

该代码还隐藏了与常规 TabControl 相关的设计时属性,但这与分页面板无关。如果有人感兴趣,下面是代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace MyCustomControls
{
    public class PagedPanel : TabControl
    {
        //------------------------------------------------------------------------------------------------
        public PagedPanel()
        {
            base.Multiline = true;
            base.Appearance = TabAppearance.Buttons;
            base.ItemSize = new Size(0, 1);
            base.SizeMode = TabSizeMode.Fixed;
            base.TabStop = false;
        }
        //------------------------------------------------------------------------------------------------
        protected override void WndProc(ref Message m)
        {
            // Hide tabs by trapping the TCM_ADJUSTRECT message
            if (m.Msg == 0x1328 && !DesignMode) m.Result = (IntPtr)1;
            else base.WndProc(ref m);
        }
        //------------------------------------------------------------------------------------------------
        protected override void OnKeyDown(KeyEventArgs ke)
        {
            // Block Ctrl+Tab and Ctrl+Shift+Tab hotkeys
            if (ke.Control && ke.KeyCode == Keys.Tab)
                return;
            base.OnKeyDown(ke);
        }
        //------------------------------------------------------------------------------------------------
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DefaultValue(true)]
        public new bool Multiline
        {
            get { return base.Multiline; }
            set { base.Multiline = value; Invalidate(); }
        }
        //------------------------------------------------------------------------------------------------
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)
        , DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DefaultValue(TabAppearance.Buttons)]
        public new TabAppearance Appearance
        {
            get { return base.Appearance; }
            set { base.Appearance = value; Invalidate(); }
        }
        //------------------------------------------------------------------------------------------------
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)
        , DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DefaultValue(typeof(Size), "0, 1")]
        public new Size ItemSize
        {
            get { return base.ItemSize; }
            set { base.ItemSize = value; Invalidate(); }
        }
        //------------------------------------------------------------------------------------------------
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)
        , DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DefaultValue(TabSizeMode.Fixed)]
        public new TabSizeMode SizeMode
        {
            get { return base.SizeMode; }
            set { base.SizeMode = value; Invalidate(); }
        }
        //------------------------------------------------------------------------------------------------
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)
        , DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new TabPageCollection TabPages
        {
            get { return base.TabPages; }
        }
        //------------------------------------------------------------------------------------------------
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DefaultValue(false)]
        public new bool TabStop
        {
            get { return base.TabStop; }
            set { base.TabStop = value; Invalidate(); }
        }
        //------------------------------------------------------------------------------------------------
        public TabPageCollection Pages
        {
            get { return base.TabPages; }
        }
        //------------------------------------------------------------------------------------------------
    }
}

树视图将处理通过键或索引调用每个选项卡,这是一项相对微不足道的任务。为此,我使用前缀“tvn”命名树中的节点,然后将 PagedPanel 中的页面命名为相同但前缀为“pg”。因此,在树视图的 AfterSelect 事件中,我需要的只是当前节点的名称,并且我知道要显示哪个页面。

于 2015-12-17T15:55:32.673 回答