见上图。这是Visual Studio选项表单的截图。
左侧基本上是TreeView。右侧是各种控件,可以更改程序选项。 选择TreeView中的节点后,右侧会更改,显示不同的选项。
你如何编程这样的东西?右侧是否只有50个重叠的面板,选择节点只会改变哪个面板可见?如果是这种情况,您将如何管理?这将是设计师的一个烂摊子。
答案 0 :(得分:6)
不,你不会制作50个重叠的面板。只需创建多个用户控件,例如,链接节点标记上的类型。您可以使用Activator来创建控件。 创建1个树视图和1个面板:( PSEUDO CODE)
// 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);
接下来的问题是,“我想在控件中调用save方法或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);
但这将是下一步。
答案 1 :(得分:0)
对我而言,其常见的设计是左侧的经典树视图和右侧的“内容区”。当用户在树视图中选择某些内容时,您将在内容区域中加载相关视图。在有很多不同的方法来实现这些东西之后,例如,自动生成基于对象列表的树视图,该对象列表包含要实例化的视图类型,并创建一个在选择项目时创建相关视图时调用的通用实例化器,无论如何,背景仍然是一样的。要恢复,请查看树视图,然后根据所选项目在内容区域中创建视图。 (我在工作中看过几个这样的画面,大部分时间都是这样的)
答案 2 :(得分:0)
在检查了几个选项之后,我的方法是继承TabControl组件,使得控件的页面可以用作分页面板,并添加功能,以便选项卡不会在运行时显示。然后,通过创建一个名为Pages的属性,该属性依赖于TabPages,我可以以语义正确的方式引用每个页面,这样可以将每个页面作为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中命名页面相同但前缀为#34; pg"。所以在树视图的AfterSelect事件中,我需要的只是当前节点的名称,我知道要显示的页面。