在XAF的帮助文档中的topic为How to: Create Information Panels(http://documentation.devexpress.com/#Xaf/CustomDocument3309) 讲述了怎样创建InfoPanel,如图:
该主题涉及了自定义模版的较高级的应用,基于FeatureCenter的例子,下面讲述一下怎样创建一个高级InfoPanel,效果如图:
该例子的代码基本来自FeatureCenter,修正了其中的几个bug,根据自己的理解加入了注释。
1.将MainForm模版添加到Model.Win工程下
在 %PROGRAMFILES%\DevExpress 2011.2\eXpressApp Framework\Sources\FrameTemplates 下找到MainForm的几个文件,复制到你的Model.Win下。并添加到工程。
2.使用视图设计器打开MainForm,添加SplitContainerControl
将viewSitePanel 添加到SplitContainerControl的Panel1中,然后设置SplitContainerControl的Dock属性为Fill,这部分操作帮助文档讲得很详细,不详述。
这里要注意的是帮助文档上没有说的两点:
1.SplitContainerControl的FixedPanel属性设置为Panel2,这样在缩放窗口时保证Panel2大小固定,更为美观;
2.SplitContainerControl的PanelVisibility属性设置为Panel1,这样通常情况下主窗口仅显示panel1,否则在不使用InfoPanel的窗口中会出现难看的空白分割线
3.继承一个IFrameTemplate接口,用于操作SplitContainerControl
using DevExpress.ExpressApp.Templates;
//...
public interface IInfoPanelTemplateWin : IFrameTemplate {
DevExpress.XtraEditors.SplitContainerControl SplitContainer { get; }
}
若自定义模版添加了其他控件,也需要定义一个类似接口获取这些新控件的引用。
在我们添加的MainForm中添加代码,使MainForm继承实现IInfoPanelTemplateWin接口
public partial class MainForm : MainFormTemplateBase, IDockManagerHolder, ISupportMdiContainer,
ISupportClassicToRibbonTransform, IInfoPanelTemplateWin
{
//...
public DevExpress.XtraEditors.SplitContainerControl SplitContainer {
get { return splitContainerControl1; }
}
}
为了支持MDI,还要修改Mainform的
UpdateMdiModeDependentProperties
方法:
public partial class MainForm : MainFormTemplateBase, IDockManagerHolder, ISupportMdiContainer,
ISupportClassicToRibbonTransform, IInfoPanelTemplateWin
{
//...
protected override void UpdateMdiModeDependentProperties() {
//viewSitePanel.Visible = !isMdi;
splitContainerControl1.Visible = !isMdi;
//...
}
}
4.修改Program.cs,使XAF使用自定义的模版而不是默认Mainform模版
static void Main()
{
//...
winApplication.CreateCustomTemplate += new EventHandler<CreateCustomTemplateEventArgs>(xafApplication_CreateCustomTemplate);
//...
}
static void xafApplication_CreateCustomTemplate(object sender, CreateCustomTemplateEventArgs e)
{
if (e.Context.Name == TemplateContext.ApplicationWindow)
{
e.Template = new DevExpress.ExpressApp.Win.CustomTemplates.MainForm();
}
}
5.继承CustomizeTemplateViewControllerBase,实现其虚拟方法
- AddControlsToTemplateCore(TemplateType template)
当Controller激活时,初始化控件,并添加到Template - RemoveControlsFromTemplateCore(TemplateType template)
当Controller禁用时,删除控件 - UpdateControls(View view)
当View改变时,更新控件 - UpdateControls(object currentObject)
下面直接给出代码,查看代码及注释应该能理解,稍做修改就能用于自己的场景。
--------------------------------------InfoPanelsViewControllerBase<TemplateType>-------------------------------------------------------
/// <summary>
/// InfoPanelsViewControllerBase类继承自CustomizeTemplateViewControllerBase
/// 并实现了其UpdateControls(View view),UpdateControls(object currentObject)方法
/// 其他方法和Control相关,故在InfoPanelsViewController中实现
/// 本基类放在Module中,故只实现了对象相关的逻辑:代表InfoPanel的relatedViewFrame和
/// PopupWindowShowAction按钮逻辑及显示文本的逻辑。
/// GetInfoText()获取要显示的文本
/// CreateRelatedViewControl()创建InfoPanel的Frame
/// </summary>
/// <typeparam name="TemplateType"></typeparam>
public abstract class InfoPanelsViewControllerBase<TemplateType> : CustomizeTemplateViewControllerBase<TemplateType> where TemplateType : IFrameTemplate
{
private PopupWindowShowAction action;
private Frame relatedViewFrame;
//获取ListView的当前TestObject的Name
private string GetInfoText()
{
string currentObjectRelatedInfo;
if (View is ListView && View.CurrentObject == null)
{
currentObjectRelatedInfo = "Empty";
}
else
{
currentObjectRelatedInfo = ((TestObject)View.CurrentObject).Name;
}
return currentObjectRelatedInfo;
}
//点击My Action弹出DetailView
private void action_CustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e)
{
IObjectSpace objectSpace = Application.CreateObjectSpace();
DetailView detailView = Application.CreateDetailView(objectSpace, objectSpace.GetObject(View.CurrentObject));
e.View = detailView;
e.Context = TemplateContext.PopupWindow;
}
private void view_ControlsCreated(object sender, EventArgs e)
{
((View)sender).ControlsCreated -= new EventHandler(view_ControlsCreated);
if (relatedViewFrame != null && relatedViewFrame.Template is ISupportStoreSettings)
{
ISupportStoreSettings storeSettings = (ISupportStoreSettings)relatedViewFrame.Template;
storeSettings.SetSettings(Application.GetTemplateCustomizationModel(relatedViewFrame.Template));
storeSettings.ReloadSettings();
}
}
private void View_ModelSaved(object sender, EventArgs e)
{
if (relatedViewFrame != null && relatedViewFrame.Template is ISupportStoreSettings)
{
((ISupportStoreSettings)relatedViewFrame.Template).SaveSettings();
}
}
protected abstract void SetInfoTextToControls(string text);
//创建Info Panel的Detail视图
protected object CreateRelatedViewControl()
{
if (relatedViewFrame == null)
{
#region 这部分代码展示了Frame和Template,ObjectSpace和View的关系
//为Frame赋值后必须调用CreateTemplate方法创建Template
relatedViewFrame = Application.CreateFrame(TemplateContext.NestedFrame);
relatedViewFrame.CreateTemplate();
IObjectSpace objectSpace = Application.CreateObjectSpace();
DetailView view = Application.CreateDetailView(objectSpace, "TestObject_DetailView_Copy", false, objectSpace.GetObject(View.CurrentObject));
view.ControlsCreated += new EventHandler(view_ControlsCreated);
view.AllowEdit["Demo"] = false;
relatedViewFrame.SetView(view);
#endregion
}
else
{
if (NeedRecreateRelatedViewFrameTemplate)
{
relatedViewFrame.View.BreakLinksToControls();
relatedViewFrame.SetTemplate(null);
relatedViewFrame.CreateTemplate();
}
}
return relatedViewFrame.Template;
}
protected override void UpdateControls(View view)
{
SetInfoTextToControls(GetInfoText());
}
protected override void UpdateControls(object currentObject)
{
SetInfoTextToControls(GetInfoText());
if (relatedViewFrame != null)
{
//若不刷新ObjectSpace,则无法及时显示修改的记录
relatedViewFrame.View.ObjectSpace.Refresh();
relatedViewFrame.View.CurrentObject = currentObject == null ? null : relatedViewFrame.View.ObjectSpace.GetObject(currentObject);
}
}
protected override void OnActivated()
{
base.OnActivated();
View.ModelSaved += new EventHandler(View_ModelSaved);
}
protected override void OnDeactivated()
{
base.OnDeactivated();
View.ModelSaved -= new EventHandler(View_ModelSaved);
}
public InfoPanelsViewControllerBase()
{
TargetObjectType = typeof(TestObject);
//该Action的Category为ContextActions,该ActionContainer将在InfoPanelsViewController创建
action = new PopupWindowShowAction(this, "ContextAction", "ContextActions");
action.Caption = "My Action";
action.SelectionDependencyType = SelectionDependencyType.RequireSingleObject;
action.CustomizePopupWindowParams += new CustomizePopupWindowParamsEventHandler(action_CustomizePopupWindowParams);
RegisterActions(action);
}
protected virtual bool NeedRecreateRelatedViewFrameTemplate
{
get { return false; }
}
}
--------------------------------------InfoPanelsViewControllerBase<TemplateType>-------------------------------------------------------
--------------------------------------InfoPanelsViewController-------------------------------------------------------
/// <summary>
/// InfoPanelsViewController放置于Module.Win中,继承了InfoPanelsViewControllerBase
/// 实现控件相关逻辑;实现了AddControlsToTemplateCore(IInfoPanelTemplateWin template)
/// 和RemoveControlsFromTemplateCore(IInfoPanelTemplateWin template)
/// 将文本,按钮,relatedView放置于GroupControl中分组显示
/// </summary>
public class InfoPanelsViewController : InfoPanelsViewControllerBase<IInfoPanelTemplateWin>
{
#region 创建模版上要显示的控件
private GroupControl textPanel;
private GroupControl actionConainersPanel;
private GroupControl relatedViewPanel;
private LabelControl literal;
//若SplitContainerControl的Panel2中不含控件,则隐藏Panel2
//由于自定义MainForm的Template后,所有MainForm都使用该模版
//若不控制SplitContainerControl的显示/隐藏,则会影响其他不需要多面板的
//Form,导致其他主Form也出现SplitContainerControl的分割线,使画面很难看
private void UpdateInfoPanelVisibility(SplitContainerControl splitContainer)
{
splitContainer.PanelVisibility = splitContainer.Panel2.Controls.Count > 0 ? SplitPanelVisibility.Both : SplitPanelVisibility.Panel1;
}
private void EnsureControls()
{
if (textPanel == null)
{
CreateTextPanel();
CreateActionContainerPanel();
CreateRelatedViewPanel();
}
}
private void CreateRelatedViewPanel()
{
relatedViewPanel = CreateGroupControl("View Panel");
System.Windows.Forms.Control viewControl = (System.Windows.Forms.Control)CreateRelatedViewControl();
viewControl.Dock = System.Windows.Forms.DockStyle.Top;
relatedViewPanel.Controls.Add(viewControl);
}
//在代码中创建一个ActionContainer
private void CreateActionContainerPanel()
{
actionConainersPanel = CreateGroupControl("Action Panel");
ButtonsContainer actionContainer = new ButtonsContainer();
actionContainer.Dock = System.Windows.Forms.DockStyle.Top;
actionContainer.ContainerId = "ContextActions";
actionConainersPanel.Controls.Add(actionContainer);
IDynamicContainersTemplate template = Frame.Template as IDynamicContainersTemplate;
if (template != null)
{
template.RegisterActionContainers(new[] { actionContainer });
}
}
private void CreateTextPanel()
{
textPanel = CreateGroupControl("Text Panel");
textPanel.Padding = new System.Windows.Forms.Padding(6);
literal = new LabelControl();
literal.AllowHtmlString = true;
literal.Dock = System.Windows.Forms.DockStyle.Top;
literal.AutoSizeMode = LabelAutoSizeMode.Vertical;
textPanel.Controls.Add(literal);
}
private GroupControl CreateGroupControl(string caption)
{
GroupControl panel = new GroupControl();
panel.AutoSize = true;
panel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
panel.Dock = System.Windows.Forms.DockStyle.Top;
panel.Text = caption;
return panel;
}
protected override void SetInfoTextToControls(string text)
{
if (literal != null)
{
literal.Text = text;
}
}
#endregion
#region 这两个方法继承自CustomizeTemplateViewControllerBase,在Controller激活/禁用时添加/删除控件
protected override void AddControlsToTemplateCore(IInfoPanelTemplateWin template)
{
EnsureControls();
template.SplitContainer.Panel2.Controls.Add(relatedViewPanel);
template.SplitContainer.Panel2.Controls.Add(actionConainersPanel);
template.SplitContainer.Panel2.Controls.Add(textPanel);
UpdateInfoPanelVisibility(template.SplitContainer);
}
protected override void RemoveControlsFromTemplateCore(IInfoPanelTemplateWin template)
{
template.SplitContainer.Panel2.Controls.Remove(relatedViewPanel);
template.SplitContainer.Panel2.Controls.Remove(actionConainersPanel);
template.SplitContainer.Panel2.Controls.Remove(textPanel);
UpdateInfoPanelVisibility(template.SplitContainer);
textPanel = null;
actionConainersPanel = null;
literal = null;
}
#endregion
public InfoPanelsViewController():base()
{
DevExpress.ExpressApp.Actions.SimpleAction showHideAction =
new DevExpress.ExpressApp.Actions.SimpleAction(this, "ShowHideInfoPanel", DevExpress.Persistent.Base.PredefinedCategory.View);
showHideAction.Execute += new DevExpress.ExpressApp.Actions.SimpleActionExecuteEventHandler(showHideAction_Execute);
}
void showHideAction_Execute(object sender, DevExpress.ExpressApp.Actions.SimpleActionExecuteEventArgs e)
{
SplitContainerControl splitContainer = ((IInfoPanelTemplateWin)Frame.Template).SplitContainer;
splitContainer.PanelVisibility = splitContainer.PanelVisibility == DevExpress.XtraEditors.SplitPanelVisibility.Both ? DevExpress.XtraEditors.SplitPanelVisibility.Panel1 : DevExpress.XtraEditors.SplitPanelVisibility.Both;
}
}
--------------------------------------InfoPanelsViewController-------------------------------------------------------