信息系统开发平台OpenExpressApp - AutoUI自动生成界面

  下图为OpenExpressApp的系统架构图,其中在UI层支持WPF和ASP.NET MVC,目前首先实现了对WPF的支持。在《信息系统开发平台OpenExpressApp - 理解核心元素ObjectView》中的ObjectView的生成控件功能都是委托给AutoUI静态类库来完成的,本篇将讲解AutoUI功能。

应用模型贯穿于整个架构层

r_OpenExpressApp%20Framework.JPG

哪些地方调用了AutoUI静态类 

  •  

    ListObjectView中树形列表视图的TreeListEditor的CreateControl,调用了AutoUI.CreateTreeListControl生成TreeLi st控件

    2009110211163259.jpg

    public   class  TreeListEditor : ListEditor
    {
        public   override   object  CreateControl()
        {
            Control 
=  AutoUI.CreateTreeListControl(BOType, View);
      ...
   }
   }
  • ListObjectView中Grid列表视图的ListEditor的CreateControl,调用了AutoUI.CreateListControl生成Grid控件

    2009110211114944.jpg

   

  public   class  ListEditor
    {
            public   virtual   object  CreateControl()
        {
            Control 
=  AutoUI.CreateListControl(BOType, View);
      ...
     }
 }  
  • DetailObjectView的CreateControl调用AutoUI.CreateDetailView生成对象编辑详细面板

2009110515102135.jpg

ContractedBlock.gif  public class DetailObjectView : ObjectView
   {    
        public override object CreateControl()
        {
            var control 
= AutoUI.CreateDetailView(BOType, thistrue);
            
return control;
        }
   }
  • NavigateQueryObjectView的CreateControl调用AutoUI.CreateDetailView生成对象导航详细面板

    2009110515561216.jpg

ContractedBlock.gif  public class DetailObjectView : ObjectView
   {    
        public override object CreateControl()
        {
            var control 
= AutoUI.CreateDetailView(BOType, thistrue);
            
return control;
        }
   }
  • 模块和View通过CreateMainToolBar、CreateChildToolBar自动生成工具条

2009111112093617.jpg

2009111112095234.jpg

AutoUI静态类方法介绍

CreateDetailView

CreateDetailView生成详细信息视图,生成结果是一个DockPanel,分为上下两部分,上面部分是AutoGrid,用来显示详细属性编辑器控件,下面部分是子对象列表信息区域。

详细信息区域

通过对象标识【ShowInDetail】来判断是否需要显示该属性,如果需要显示,则通过属性编辑器来生成具体的控件,然后布局在AutoGrid中ContractedBlock.gif

ContractedBlock.gif ExpandedBlockStart.gif Code
         AutoGrid detailGrid = new AutoGrid();
            detailGrid.SetValue(DockPanel.DockProperty, Dock.Top);

            
//一般加四列,ConditionQuery/NavigateQuery加两列
            detailGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
            detailGrid.ColumnDefinitions.Add(
new ColumnDefinition());
            
if (RegionType.Data == detailView.RegionType)
            {
                detailGrid.ColumnDefinitions.Add(
new ColumnDefinition() { Width = GridLength.Auto });
                detailGrid.ColumnDefinitions.Add(
new ColumnDefinition());
            }

            
//加入所有标记了ShowInDetail的属性
            var typeInfo = ApplicationModel.GetBusinessObjectInfo(boType);
            
foreach (var p in typeInfo.BOPropertyInfos)
            {
                
if (p.ShowInDetail)
                {
                    
//detailGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
                    PropertyEditor editor = PropertyEditorsFactory.GetDefaultEditor(p.EditorName);
                    editor.CreateControl(p, detailView);
                    detailGrid.Children.Add(editor.LabelControl 
as UIElement);
                    detailGrid.Children.Add(editor.Control 
as UIElement);
                }
            }

子对象区域

如果有子对象,则生成一个子对象区域,现在是生成页签样式,每个子对象分别一个Tab页面,子对象又可以层级生成子对象。

ContractedBlock.gif ExpandedBlockStart.gif Code
           //生成子UIElement
            UIElement child = CreateChildObjectView(boType, detailView, detailGrid, recur);
            
if (null != child)
            {
                detailPanel.Children.Add(child);
            }
            
else
            {
                detailPanel.Children.Add(
new Label());
            }

在生成子对象时,需要考虑生成子对象工具条、导航面板、布局等

ContractedBlock.gif ExpandedBlockStart.gif Code
        /// <summary>
        
/// 生成子控件
        
/// </summary>
        
/// <param name="parentType">根据这个对象的孩子属性生成</param>
        
/// <param name="parentView">生成这个视图的子控件</param>
        
/// <param name="parentControl">已经生成好的父控件</param>
        
/// <param name="recur">是否递归生成下层的子控件</param>
        
/// <returns></returns>
        private static UIElement CreateChildObjectView(
            Type parentType, 
            ObjectView parentView,
            FrameworkElement parentControl, 
            
bool recur
            )
        {
            
//生成的控件都放在这个TabControl里面
            TabControl tab = null;
            BusinessObjectInfo parentBOInfo 
= ApplicationModel.GetBusinessObjectInfo(parentType);
            IList
<BusinessObjectsPropertyInfo> bosPropertyInfo = parentBOInfo.BOsPropertyInfos;

            
if ((bosPropertyInfo.Count == 1&& (null != parentBOInfo.TreeChildPropertyInfo))
            {
                
//递归在父对象的View对应的Toolbar上生成按钮
                BusinessObjectInfo treeChildBoInfo = parentBOInfo;
                
while (null != treeChildBoInfo.TreeChildPropertyInfo)
                {
                    treeChildBoInfo 
= treeChildBoInfo.TreeChildBoInfo;
                    AutoUI.CreateChildToolBar(parentView.ToolBar, treeChildBoInfo.BOType, parentView);
                }
            }
            
else if (((bosPropertyInfo.Count > 1&& (null != parentBOInfo.TreeChildPropertyInfo))
                
|| ((bosPropertyInfo.Count > 0&& (null == parentBOInfo.TreeChildPropertyInfo)))
            {
                
if (Direction.Horizontal == parentBOInfo.BusinessObjectAttribute.Direction)
                {
                    parentControl.SetValue(DockPanel.DockProperty, Dock.Left);
                    parentControl.SetValue(ResizingPanel.ResizeWidthProperty, 
new GridLength(200));
                }
                
//多个细表时设定细表高度
                else if (parentControl.GetType() != typeof(AutoGrid))
                {
                    parentControl.SetValue(DockPanel.DockProperty, Dock.Top);
                    parentControl.SetValue(ResizingPanel.ResizeHeightProperty, 
new GridLength(100));
                }

                tab 
= new TabControl();
                
foreach (var o in bosPropertyInfo)
                {
                    DockPanel rootDck 
= new DockPanel();//包含当前属性对应控件以及子属性对应控件

                    ToolBar childTb 
= null;
                    
//创建子Toolbar
                    if (parentView.RegionType != RegionType.NavigateQuery)
                    {
                        childTb 
= new ToolBar();
                        childTb.SetValue(DockPanel.DockProperty, Dock.Top);
                        rootDck.Children.Add(childTb);
                    }

                    ResizingPanel rootResizingPanel 
= new ResizingPanel();
                    rootDck.Children.Add(rootResizingPanel);

                    
if (Direction.Horizontal == ApplicationModel.GetBusinessObjectInfo(o.BOType).BusinessObjectAttribute.Direction)
                    {
                        rootResizingPanel.Orientation 
= Orientation.Horizontal;
                    }
                    
else
                    {
                        rootResizingPanel.Orientation 
= Orientation.Vertical;
                    }
                    
//创建列表
                    ListObjectView lv = new ListObjectView(o);
                    lv.PropertyName 
= o.Name;
                    lv.RegionType 
= parentView.RegionType;
                    parentView.AddChildView(lv);

                    DockPanel dck 
= new DockPanel();

                    
//添加导航面板
                    if (null != lv.NavigateQueryView)
                    {
                        
//增加一个ListViewController,以便导航查询数据
                        UIElement navigateControl = lv.NavigateQueryView.Control as UIElement;
                        
//初始化导航面板对象
                        lv.NavigateQueryView.Data = Activator.CreateInstance(lv.NavigateQueryView.BOType);
                        (lv.NavigateQueryView.CurrentObject 
as BusinessBase).BeginEdit();

                        ResizingPanel pnlNavigate 
= new ResizingPanel();
                        navigateControl.SetValue(ResizingPanel.ResizeWidthProperty, 
new GridLength(200));
                        pnlNavigate.Children.Add(navigateControl);
                        ListViewController lvController 
= new ListViewController(lv, null);
                        
//添加列表
                        pnlNavigate.Children.Add(lvController.Control as UIElement);
                        dck.Children.Add(pnlNavigate);
                    }
                    
else
                        
//添加列表
                        dck.Children.Add(lv.Control as UIElement);
                    rootResizingPanel.Children.Add(dck);
                    StackPanel tabHeader 
= new StackPanel() { Orientation = Orientation.Horizontal };
                    tabHeader.Children.Add(
new TextBlock() { Text = o.Label });
                    Button btnMax 
= new Button();
                    btnMax.CommandParameter 
= lv;
                    ButtonCommand.SetCommand(btnMax, CommandRepository.Commands[CommandNames.MaxShowView]);
                    tabHeader.Children.Add(btnMax);

                    TabItem ti 
= new TabItem()
                    {
                        Header 
= tabHeader,
                        Content 
= rootDck,
                    };
                    tab.Items.Add(ti);


                    
if (null != childTb)
                    {
                        AutoUI.CreateChildToolBar(childTb, o.BOType, lv);
                    }
                    
//递归查找子子对象
                    if (recur)
                    {
                        UIElement childchild 
= CreateChildObjectView(o.BOType, lv, dck, recur);
                        
if (null != childchild)
                        {
                            rootResizingPanel.Children.Add(childchild);
                        }
                    }
                }
            }
            
return tab;
        }

CreateListControl

CreateListControl生成DataGrid列表控件,通过对象类属性标识为【ShowInList】或者【ShowInLookup】来动态生成列,具体列编辑和显示控件由属性对应的GridColumn来完成。

ContractedBlock.gif ExpandedBlockStart.gif Code
        public static object CreateListControl(Type boType, ListObjectView view)
        {
            DataGrid dg 
= new SelectionDataGrid()
                {
                    CanUserAddRows 
= false,
                    AutoGenerateColumns 
= false,
                    VerticalGridLinesBrush 
= new SolidColorBrush(Colors.Gray),
                    HorizontalGridLinesBrush 
= new SolidColorBrush(Colors.Gray),
                };
            BusinessObjectInfo boInfo 
= ApplicationModel.GetBusinessObjectInfo(boType);
            
if (0 != boInfo.BusinessObjectAttribute.Height)
            {
                dg.Height 
= (int)boInfo.BusinessObjectAttribute.Height;
            }

            
//生成每一列
            foreach (var item in boInfo.BOPropertyInfos)
            {
                
bool generate;

                
if (view.RegionType == RegionType.LookupList)
                {
                    generate 
= item.ShowInLookup;
                }
                
else
                {
                    generate 
= item.ShowInList;
                }

                
if (generate)
                {
                    DataGridColumn c 
= item.CreateDefaultGridColumn(view);
                    dg.Columns.Add(c);
                }
            }

            
return dg;
        }

CreateTreeListControl

CreateTreeListControl生成树形控件。由于树形控件支持多对象显示,现在生成时是采用一种简便的算法,如果各对象的属性Name一样,则认为显示在同一列中;父对象的属性排在前面。

ContractedBlock.gif ExpandedBlockStart.gif Code
       /// <summary>
        
/// 自动生成树形列表UI
        
/// </summary>
        
/// <param name="boType"></param>
        
/// <returns></returns>
        public static object CreateTreeListControl(Type boType, ListObjectView view)
        {
            MultiObjectTreeView otv 
= new MultiObjectTreeView();
            otv.SelectNodesOnRightClick 
= true;
            
//都按懒加载关系处理
            
//if (ApplicationModel.GetBusinessObjectInfo(boType).LazyTreeNodeRelation) 
            
//    otv.LazyTreeNodeRelation = true;

            
//装载多个对象的属性,按照
            BusinessObjectInfo boInfo = ApplicationModel.GetBusinessObjectInfo(boType);
            IList
<BusinessObjectPropertyInfo> propInfos = new List<BusinessObjectPropertyInfo>();
            
foreach (var item in boInfo.BOPropertyInfos)
            {
                propInfos.Add(item);
            }

            
//把模型下的需要一同显示在树中的子模型的列,加入List中
            while (null != boInfo.TreeChildPropertyInfo)
            {
                boInfo 
= boInfo.TreeChildBoInfo;
                
foreach (var item in boInfo.BOPropertyInfos)
                {
                    
bool exist = false;
                    
foreach (var propInfo in propInfos)
                    {
                        
if (propInfo.Name == item.Name)
                        {
                            exist 
= true;
                            
break;
                        }
                    }
                    
if (!exist)
                    {
                        propInfos.Add(item);
                    }
                }
            }

            
//使用list里面的属性生成每一列
            foreach (var item in propInfos)
            {
                
bool generate;

                
if (view.RegionType == RegionType.LookupList)
                {
                    generate 
= item.ShowInLookup;
                }
                
else
                {
                    generate 
= item.ShowInList;
                }

                
if (generate)
                {
                    GridViewColumn c 
= item.CreateDefaultTreeColumn(view);
                    (otv.Tree 
as TreeListView).Columns.Add(c);
                }
            }

            
return otv;
        }

CreateMainToolBar、CreateChildToolBar

CreateMainToolBar生成根对象工具条,系统根据当前对象类型的相关设置在Command注册库中查找并自动添加

ContractedBlock.gif ExpandedBlockStart.gif Code
        /// <summary>
        
/// 生成主工具栏
        
/// </summary>
        
/// <param name="mainToolbar"></param>
        
/// <param name="boType"></param>
        
/// <param name="view"></param>
        
/// <param name="moduleType"></param>
        public static void CreateMainToolBar(ToolBar mainToolbar, Type boType, ObjectView view, ModuleType moduleType)
        {
            view.ToolBar 
= mainToolbar;

            
//找到对应这个toolbar的所有command
            var commands = ApplicationModel.Commands.Where(
                c 
=> ((c.TargetObjectType == boType) || (c.TargetObjectType == null)) &&
                    ((c.ModuleType 
== ModuleType.Unspecified) || (c.ModuleType == moduleType)) &&
                    ((c.ToolbarType 
== ToolbarType.Any) || (c.ToolbarType == ToolbarType.Main)));

            
//CommandCategory.Filter类型下的命令需要在一个下拉列表中显示
            Panel filterPanel = null;
            
//ComboBox cb = null;
            foreach (var c in commands)
            {
                
bool notVisible = ApplicationModel.IsNotVisibleCommand(c.Name, ApplicationModel.GetBusinessObjectInfo(boType));
                
if (notVisible == false && (c.CanVisible(view)))
                {
                    Button btn 
= new Button()
                    {
                        Name 
= "btn" + c.Name,
                    };

                    
//第一个
                    if ((null == filterPanel) && (CommandCategory.Filter == c.CommandCategory))
                    {
                        filterPanel 
= new StackPanel() { Orientation = Orientation.Horizontal };
                        mainToolbar.Items.Add(filterPanel);
                    }

                    btn.CommandParameter 
= view;
                    ButtonCommand.SetCommand(btn, CommandRepository.Commands[c.Name]);

                    
if (CommandCategory.Filter == c.CommandCategory)
                    {
                        filterPanel.Children.Add(btn);
                    }
                    
else
                    {
                        mainToolbar.Items.Add(btn);
                    }
                }
            }
            
if (0 == mainToolbar.Items.Count)
            {
                mainToolbar.Visibility 
= Visibility.Collapsed;
            }
        }

CreateChildToolBar生成子对象工具条,这个方法一般在前面介绍的CreateDetailView方法中生成子对象区域时使用。

具体编辑器控件生成

AutoUI静态类方法主要是生成Grid、TreeGrid、Panel等大的控件,具体针对每个属性的编辑和显示控件是由属性编辑器、GridColumn和TreeColumn来生成的,而GridColumn和TreeColumn的具体编辑控件又是由属性编辑器来生成的,所以属性编辑器是AutoUI内部的重要部分。

属性编辑器

在《内置支持的属性编辑方式》讲过支持的属性编辑器类型,每种类型都对应一个编辑器类。由于每个属性编辑器都比较类似,下面简单说明一下string属性编辑器。

每个属性编辑器都有一个方法CreateControlCore来生成编辑控件,StringPropertyEditor 生成了一个TextBox并绑定到对象属性上。还有一个方法SetControlReadOnly来控制只读时控件的状态改变。

ContractedBlock.gif ExpandedBlockStart.gif Code
    public class StringPropertyEditor : WPFPropertyEditor
    {
        
private TextBox tb;

        
public override void SetControlReadOnly()
        {
            tb.IsReadOnly 
= ReadOnly;
        }

        
protected override object CreateControlCore()
        {
            tb 
= new TextBox()
            {
                Name 
= PropertyInfo.Name,
            };
            
//绑定TextBox到对象属性
            Binding textBinding = new Binding(PropertyInfo.Name);
            
//如果是只读属性,则设置binding mode
            if (!PropertyInfo.PropertyInfo.CanWrite) textBinding.Mode = BindingMode.OneWay;
            tb.SetBinding(TextBox.TextProperty, textBinding);
            
return tb;
        }
    }

为了重用这些属性编辑器,GridColumn和TreeColumn的列的具体编辑控件都是由属性编辑器来生成,例如StringTreeColumn内部使用了StringPropertyEditor

ContractedBlock.gif ExpandedBlockStart.gif Code
    public class StringTreeColumn : TreeColumn
    {
        
private StringPropertyEditor _editor;

        
public StringTreeColumn(BusinessObjectPropertyInfo info, ListObjectView view)
            : 
base(info, view)
        {
            
this._editor = new StringPropertyEditor();
        }

        
public override PropertyEditor Editor
        {
            
get
            {
                
return this._editor;
            }
        }
    }

自定义对象编辑界面

前面讲的生成控件都是按照对象标识以及对象属性标识,以及相关的命令设置来生成。实际开发中,可能存在一些业务对象需要其他界面样式来显示(如使用报表控件ReportView来显示列表信息),而AutoUI是处理共性要求的界面表现,这时我们框架就需要提供一种扩展机制,允许用户自定义编辑界面来对应到业务对象。AutoUI生成各类UI时先判断业务对象该类型下的UI有没有自定义,如果有则直接生成对应的Type指定的UserControl,否则按照上面的AutoUI自定生成。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
    /// <summary>
    
/// 业务对象模型
    
/// </summary>
    public class BusinessObjectInfo
    {
        
/// <summary>
        
/// AutoUI不满足应用需要时,通过挂接此属性来自定义明细UI
        
/// </summary>
        public Type ModuleUIType { getprivate set; }
        
public Type ListViewUIType { getprivate set; }
        
public Type DetailViewUIType { getprivate set; }
       dot.gif 
    }


    /// <summary>
    
/// 业务对象模型
    
/// </summary>
    public class BusinessObjectInfo
    {       
        
/// <summary>
        
/// AutoUI不满足应用需要时,通过挂接此属性来自定义明细UI
        
/// </summary>
        public Type ModuleUIType { getprivate set; }
        
public Type ListViewUIType { getprivate set; }
        
public Type DetailViewUIType { getprivate set; }
    }

信息系统开发平台OpenExpressApp - 理解核心元素ObjectView


更多内容:productView-pdf_46x35.gif 开源信息系统开发平台之OpenExpressApp框架.pdf


欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值