65.9K
CodeProject 正在变化。 阅读更多。
Home

Tripous - 表单和代理

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2投票s)

2010年6月21日

CPOL

9分钟阅读

viewsIcon

18774

downloadIcon

358

本教程介绍如何使用Tripous数据录入表单来显示来自不同类型数据源的数据。

Tripous是什么?

Tripous 是一个用C#编写的开源应用程序框架,用于快速实现WinForms数据录入应用程序。

官方网站可在 http://tripous-net.com 找到。SourceForge上的项目页面可在 http://sourceforge.net/projects/tripous 找到。

CodeProject上的Tripous教程

  • Tripous简介:关于Tripous以及如何设置您的第一个Tripous数据录入应用程序的教程。
  • Tripous - 数据访问:关于如何使用Tripous数据访问类的教程。

引言

本教程介绍如何使用Tripous数据录入表单来显示来自不同类型数据源的数据。

正如Tripous简介教程所描述的,Tripous提供了两种类型的数据录入表单:主表单和列表表单。本教程是关于主表单的。

主数据录入表单包含两个部分:浏览(或列表)部分和编辑(或项)部分。浏览部分只是一个只读的DataGridView。编辑部分可能包含数据绑定控件,用于编辑单个数据行或项。

使用数据录入表单最简单的方法是与代理(Broker)结合使用,特别是SqlBroker。代理是Tripous中的基础业务类。大多数时候,表单和代理是协同工作的。但这并非唯一的情况。

Tripous表单类的简要层次结构如下。

  • BaseForm:提供了表单初始化和“最终化”逻辑的基础表单类。
  • DataEntryForm:数据录入表单的基类。提供了在列表中浏览和搜索,以及插入、编辑和删除行的所有逻辑。
  • DataEntryBrokerForm:与代理关联的数据录入表单的基类。

在本教程中,我们将探讨四种不同的情况

示例应用程序

示例应用程序不是一个完整的Tripous数据录入应用程序。主表单不继承自Tripous.Forms.SysMainForm。它只是一个普通的MDI容器主表单。下面是该表单的图片,显示了四种不同的表单情况作为菜单项。

MainForm.jpg

主表单在OnShown()方法中初始化。

protected override void OnShown(EventArgs e)
{
    base.OnShown(e);

    if (!DesignMode)
    {
        ObjectStore.Initialize();
        InitializeForm();
    }
}

ObjectStore是Tripous的一个静态类,它是一个对象注册表。ObjectStore能够搜索程序集中标记有ObjectStoreItemAttribute特性的类或方法,并将它们自动注册为对象工厂。由于这不是一个完整的Tripous应用程序,我们必须手动初始化ObjectStore

InitializeForm()属于主表单,并启动初始化序列。

void InitializeForm()
{
    Sys.Variables["Forms.MainForm"] = this;
    ObjectStore.Add("Synchronizer.Primary", this as object);

    Logger.Active = true;

    InitializeDatabase();
    InitializeDescriptors();

    /* assign MdiLayout values to menu item tags */
    mnuCascade.Tag = MdiLayout.Cascade;
    mnuTileHorizontal.Tag = MdiLayout.TileHorizontal;
    mnuTileVertical.Tag = MdiLayout.TileVertical;
    mnuArrangeIcons.Tag = MdiLayout.ArrangeIcons;

    /* events */
    mnuExit.Click += new EventHandler(AnyClick);
    mnuSqlMonitor.Click += new EventHandler(AnyClick);

    mnuCascade.Click += new EventHandler(AnyClick);
    mnuTileHorizontal.Click += new EventHandler(AnyClick);
    mnuTileVertical.Click += new EventHandler(AnyClick);
    mnuArrangeIcons.Click += new EventHandler(AnyClick);

    mnuDataEntryBrokerFormWithSqlBroker.Click += new EventHandler(AnyClick);
    mnuDataEntryFormWithASingleDataTable.Click += new EventHandler(AnyClick);
    mnuDataEntryFormWithAGenericBindingList.Click += new EventHandler(AnyClick);
    mnuDataEntryBrokerFormWithACustomBroker.Click += new EventHandler(AnyClick);
}

InitializeForm()方法通知Tripous此表单是主表单,并且是主同步器。我们的主表单实现了ISynchronizer接口,该接口用于同步线程调用。

接下来,激活日志记录器。Logger类用于记录任何类型的信息,不仅仅是异常。最终,日志记录器会通知任何订阅的监听器任何日志事件。日志记录器本身不持久化日志信息。这是特殊日志监听器的工作。一个完整的Tripous应用程序提供一个日志监听器,将日志信息保存到数据库表中。还有其他日志监听器,它们只是将日志信息显示给用户。SqlMonitorForm就是一个这样的监听器,它在Tripous执行SQL语句时显示这些语句。我们将使用SqlMonitorForm来检查其中一些语句。所以我们需要激活Logger类。

接下来是InitializeDatabase()InitializeDescriptors(),之后是连接事件到事件处理器的代码。这个示例应用程序的四个表单中有一个使用SQL数据库数据,所以我们需要一个数据库。我们将使用优秀的Sqlite作为我们的数据库服务器。Tripous已经集成了Sqlite。

void InitializeDatabase()
{
    /* construct the path to the database file */
    string FileName = Path.GetFullPath(@"..\..\TripousDemo.db3");

    /* get the proper DataProvider and create the database file */
    DataProvider Provider = DataProviders.Find(ConnectionStringBuilder.Sqlite);
    Provider.CreateDatabase("", FileName, "", "");

    /* construct the connection string to the database */
    string ConStr = ConnectionStringBuilder.FormatConnectionString("", 
                          ConnectionStringBuilder.Sqlite, FileName);

    /* create and add a Datastore object for the database */
    Datastore Datastore = Datastores.Add("MAIN", ConnectionStringBuilder.Sqlite, ConStr);


    /* this is the only table in the database */
    string CUSTOMER = @"
        create table Customer ( 
           Id      @PRIMARY_KEY 
          ,Code    varchar(32) 
          ,Name    varchar(64)   
        )
        ";

    /* create an Executor and use it to create the table in the database */
    Executor Executor = Datastore.CreateExecutor();
    Executor.CreateTable(CUSTOMER);
}

Tripous - 数据访问教程详细介绍了DataProviderDatastore等数据访问类。这里,此方法获取Sqlite Tripous DataProvider,如果数据库不存在则创建数据库,构建连接字符串,将Datastore添加到Datastores,创建一个Executor,并使用该Executor在数据库中创建表。

接下来是InitializeDescriptors()

void InitializeDescriptors()
{

    /* Create and add a BrokerDescriptor to the Registry.Brokers collection. 
       The minimum information required for a BrokerDescriptor 
       is the Name, the MainTableName and the TypeClassName.
       This particular Add() used here sets the Name, 
       MainTableName and Title properties of the broker descriptor
       to the passed in string, in this case Customer. 
       The TypeClassName property is set to SqlBroker.
       No other information is given to the descriptor, 
       so this is a very lazy initialization */
    BrokerDescriptor BrokerDes = Registry.Brokers.Add("Customer");


    /* Create and add a FormDescriptor to the Registry.Forms collection. 
       The minimum information required for a FormDescriptor 
       is the Name, the TypeClassName and the BrokerName.
       This particular Add() used here sets the Name and the BrokerName to Customer and
       the TypeClassName to an assembly qualified name of a demo form class.   */
    FormDescriptor FormDes = Registry.Forms.Add("Customer", 
           typeof(DataEntryBrokerFormWithSqlBroker).AssemblyQualifiedName);


    /* Create and add a Command to the Registry.MainProcessor. 
       The Command class provides the Kind property 
       which designates the function of the command.
       Here the Kind is set to CommandKind.Mdi, 
       which means that this commands should create an Mdi form.
       The Command.Name is required and here is set to Customer. 
       When a form command such as this command is executed, 
       it searches the Registry for a FormDescriptor
       with the same name as its own name. */
    Registry.MainProcessor.Add(CommandKind.Mdi, "Customer");
}

现在我们开始处理表单。

带SqlBroker的主表单

这是最简单的情况,因为我们已经通过InitializeDescriptors()注册了所有需要的东西。

当一个注册到Registry.MainProcessorKind属性设置为CommandKind.MdiCommandKind.ModalCommand对象被执行时,注册表将被搜索一个名称与其自身名称相同的FormDescriptor。然后它会创建实际的表单和实际的代理,连接两者,并显示表单。这一切在完整的Tripous应用程序中都是自动发生的。在我们这个小示例中,我们必须手动完成。所以这是主表单的AnyClick()方法中的一部分

else if (sender == mnuDataEntryBrokerFormWithSqlBroker)
{
    Command Cmd = Registry.MainProcessor["Customer"];
    DataEntryForm.Show(Cmd);
}

上面的代码创建了一个DataEntryBrokerFormWithSqlBroker的实例,该实例派生自DataEntryBrokerForm

当相关的菜单项被点击时,我们从注册表中获取Customer Command,然后调用DataEntryForm类的静态Show()方法。这就是我们要做的全部。DataEntryBrokerFormWithSqlBroker类的一个实例和SqlBroker类的一个实例被创建并连接,然后表单显示自身。这是一个数据录入表单,它读取和写入其数据到关系数据库。

我们可以使用SQL Monitor菜单项来显示SqlMonitorForm,然后再显示数据表单,以便检查Tripous在浏览、插入或搜索时执行的SQL。

由于这不是一个完整的Tripous应用程序,并非所有的表单功能都可用。例如,不支持报表。报表、语法高亮、脚本、RAPI等功能是使用外部插件模块支持的,这些模块需要ApplicationManager类来加载它们。尽管如此,几乎所有的功能都在。您甚至可以执行参数化查询。这是客户表单的条件部分

CustomerFormCriteria.jpg

在正常的Tripous应用程序中,主表单的编辑部分主要托管Tripous控件,这些控件提供了强大的数据绑定灵活性。这些控件需要完整的描述符信息。本示例使用标准的.NET控件,绑定由表单中的代码完成。

protected override void BindControls()
{
    base.BindControls();

    /* If you use the standard TextBox and not the TextBoxEx provided by Tripous,
       then you have to manually bind that text box as following */
    if (bsBrowser != null)
    {
        textBox1.DataBindings.Add(Ui.Bind("Text", bsItem, "Code"));
        textBox2.DataBindings.Add(Ui.Bind("Text", bsItem, "Name")); 
    } 
}

带自定义Broker的主表单

在此表单情况下,我们再次使用派生自DataEntryBrokerFormDataEntryBrokerFormWithCustomBrokerDataEntryBrokerForm需要一个Broker。我们将为该表单提供一个自定义Broker。一个对SQL数据和数据库一无所知的Broker。

创建自定义Broker类

Tripous.BusinessModel.Broker类是所有Broker的基础类。它只提供空的虚拟方法,可以在插入、编辑或删除数据时使用。Broker类的接口如下。

public class Broker : IBroker 
{
    static public readonly string BrowserPostfix = "__BROWSER";

    /* protected */
    protected Command processor = new Command();
    protected object owner;
    protected DataSet dataSet;
    protected Variables variables;
    protected Tables tables;
    protected CodeProducer codeProducer;
    protected DataMode state = DataMode.None;
    protected object lastEditedId;
    protected object lastCommitedId;
    protected object lastDeletedId;

    protected MemTable _tblBrowser;             // ref
    protected MemTable _tblItem;                // ref
    protected MemTable _tblLines;               // ref
    protected MemTable _tblSubLines;            // ref    
    protected MemTable _tblBackup;              // ref  

    /* flags */
    protected bool initialized;
    protected bool initializing;
    protected bool batchMode;
    protected bool browserSelected;
    protected bool selectBrowserOnce;
    protected bool browserSetupDone;
    protected bool isListBroker; 

    /* initialization */
    public virtual void Initialize(bool AsListBroker);
    protected virtual void DoInitializeBefore();
    protected virtual void DoInitialize();
    protected virtual void DoInitializeAfter(); 

    /* browser */
    public void BrowserSelect();
    public void BrowserCommit();
    public void BrowserCancel();

    /* browser DoXXX methods */
    protected virtual void DoBrowserSelect();
    protected virtual void DoBrowserCommit();
    protected virtual void DoBrowserSetup();

    /* browser checks */
    protected virtual void BrowserCheckCanCommit();

    /* browser miscs */
    protected void BrowserSetup();
    protected void BrowserAcceptChanges();
    protected void BrowserRejectChanges();
    protected virtual void DoBrowserAcceptChanges();
    protected virtual void DoBrowserRejectChanges();

    /* item */
    public void Insert();
    public void Edit(object RowId);
    public void Delete(object RowId);
    public object Commit(bool Reselect);
    public void Cancel();

    /* item DoXXX before and after methods */
    protected virtual void DoInsertBefore();
    protected virtual void DoInsert();
    protected virtual void DoInsertAfter();
    protected virtual void DoEditBefore(object RowId);
    protected virtual void DoEdit(object RowId);
    protected virtual void DoEditAfter(object RowId);
    protected virtual void DoDeleteBefore(object RowId);
    protected virtual void DoDelete(object RowId);
    protected virtual void DoDeleteAfter(object RowId);
    protected virtual void DoCommitBefore(bool Reselect);
    protected virtual object DoCommit(bool Reselect);
    protected virtual void DoCommitAfter(bool Reselect);
    protected virtual void DoCancelBefore();
    protected virtual void DoCancel();
    protected virtual void DoCancelAfter();

    /* item checks */
    protected virtual void CheckCanInsert();
    protected virtual void CheckCanEdit(object RowId);
    protected virtual void CheckCanDelete(object RowId);
    protected virtual void CheckCanCommit(bool Reselect);     

    /* item miscs */
    protected void AcceptChanges();
    protected void RejectChanges();
    protected virtual void DoAcceptChanges();
    protected virtual void DoRejectChanges();

    /* sending-posting data-related messages through Broadcaster */
    protected void Send(string EventName);
    protected void Send(string EventName, string[] Names, object[] Values);
    protected void Post(string EventName);
    protected void Post(string EventName, string[] Names, object[] Values);

    /* constructors */
    public Broker();


    /* static */
    static public Broker Create(BrokerDescriptor BrokerDes, 
                  bool Initialized, bool AsListBroker);
    static public Broker Create(BrokerDescriptor BrokerDes, bool Initialized);
    static public Broker Create(string Name, bool Initialized, bool AsListBroker);
    static public Broker Create(string Name, bool Initialized) ;

    /* local reports */
    public virtual void ReportsShowAdminDialog();
    public virtual void ReportsShowMenuDialog();
    public virtual bool ReportsExists(string Name);
    public virtual bool ReportsExecute(string Name);

    /* copy-paste */
    public virtual bool Copy();
    public virtual bool Paste();
    public virtual bool CanPaste();

    /* miscs */         
    public virtual string CurrentItemCodeName(int RowIndex);
    public virtual DataRow Locate(string FieldName, object Value);
    public DataRow Locate(object Value);
    public virtual void BackUp();
    public virtual TableDescriptor TableDescriptorOf(string TableName);
    public virtual FieldDescriptor FieldDescriptorOf(string TableName, 
                                   string FieldName);

    public virtual List<datarow> PickRows(string TargetTable, 
           string SourceSqlText, string[] VisibleColumns, 
           string TargetKeyName, string SourceKeyName);

    /* properties */
    public bool Initializing { get { return initializing; } }
    public bool Initialized { get { return initialized; } }
    public virtual int RowCount { get { return _tblBrowser == null ? 0 : 
                                               _tblBrowser.Rows.Count; } }
    public virtual bool BrowserIsEmpty { get { return RowCount == 0; } }
    public virtual bool IsBrowserModified { get { return _tblBrowser == null ? 
                   false : _tblBrowser.GetChanges() != null; } }
    public bool BatchMode { get; set; }

    public DataSet DataSet { get ; }
    public MemTable tblBrowser { get ; }
    public MemTable tblItem { get ; }
    public MemTable tblLines { get ; }
    public MemTable tblSubLines { get ; }
    public MemTable tblBackup { get ; }

    public Tables Tables { get ; }
    public CodeProducer CodeProducer { get ; }
    public Variables Variables { get ; }
    public Command Processor { get ; }
    public virtual bool IsListBroker { get ; }
    public virtual bool IsMasterBroker { get ; }
    public object Owner { get; set; }


    public DataMode State { get ; }
    public virtual object LastEditedId { get ; }
    public virtual object LastCommitedId { get ; }
    public virtual object LastDeletedId { get ; }

    public virtual string LinesTableName { get ; }
    public virtual string SubLinesTableName { get ; }
    public virtual string BackupTableName { get ; }
}

Broker类与表单类类似,将其逻辑分为两部分。浏览(或列表)部分和编辑(或项)部分。以“Browser”开头或包含“Browser”的方法用于浏览部分。方法如Commit()Insert()Delete()Edit()DoCommit()DoInsert()DoDelete()DoEdit()用于Broker的编辑部分。“Do”前缀表示一个虚拟方法,它被一个没有“Do”前缀的同名方法调用。Broker类的Commit()方法如下。

public object Commit(bool Reselect)
{
    DataMode OldState = State;
    try
    {
        DoCommitBefore(Reselect);
        CheckCanCommit(Reselect);
        lastCommitedId = DoCommit(Reselect);
        DoCommitAfter(Reselect);

        state = DataMode.Edit;
        return lastCommitedId;   
    }
    catch 
    {
        state = OldState;
        throw;
    }
}

如果您查看类似Broker方法的代码,您会发现它们遵循相同的模式。

try
{
    DoXXXXBefore();
    CheckCanXXXX();
    DoXXXX();
    DoXXXXAfter();

    ...
}
catch 
{
    ...
    throw;
}

Tripous.BusinessModel.SqlBroker派生自Broker类。SqlBroker使用BrokerDescriptor;它知道如何处理SQL数据,并为Broker父类的所有这些虚拟方法提供了合适的实现。最终,SqlBroker能够处理许多数据场景而无需额外的代码。但在这种表单情况下,我们不使用SqlBroker

相反,本示例提供了一个直接派生的Broker类。Broker类没有BrokerDescriptor。它依赖于代码。看一下。

/// A custom Broker. It is not a SqlBroker. It just uses
/// a plain xml file to save its data.
/// There is the tblSource DataTable that acts as the data container.
/// That tblSource is not part of the Broker.Tables. It is just
/// a static field used as a helper.
public class CustomBroker : Broker
{
    /* these static fields play the role of the source data */
    static string fileName = Path.GetFullPath(@"..\..\Customers2.XML");
    static DataSet DS = Db.CreateDataset();
    static MemTable tblSource = new MemTable("Customers");

    /* private */
    private void BrowserSelectInternal()
    {
        tblSource.CopyTo(_tblBrowser);
    }

    /* overrides */
    /// Initializes the broker
    protected override void DoInitialize()
    {
        base.DoInitialize();

        /* By convention the browser table is named after the main (top) table 
           of the broker, plus the BrowserPostfix */
        _tblBrowser = tables.Add("Customers" + BrowserPostfix);


        /* add schema to the browser table and copy data to it */
        tblSource.CopyStructureTo(_tblBrowser);
        tblSource.CopyTo(_tblBrowser);


        /* create the top table and add schema to it */
        _tblItem = tables.Add("Customers");
        tblSource.CopyStructureTo(_tblItem);
    }
    /// Called by the Broker.BrowserSelect method
    /// and it actually selects the browser.
    protected override void DoBrowserSelect()
    {
        BrowserSelectInternal();
    }
    /// Called by theInsert to actually start an insert operation.
    protected override void DoInsert()
    {
        tblItem.Rows.Clear();
        DataRow Row = tblItem.NewRow();
        tblItem.Rows.Add(Row);
    }
    /// Called by the Edit to actually starts an edit operation.
    protected override void DoEdit(object RowId)
    {
        DataRow SourceRow = null;

        if (!tblBrowser.Locate("Id", new object[] { RowId }, 
                                     LocateOptions.None, out SourceRow))
            Sys.Error("Can not edit a Customer. Row not found");

        tblItem.Rows.Clear();
        DataRow Row = tblItem.NewRow();
        tblItem.Rows.Add(Row);

        SourceRow.CopyTo(Row);
    }
    /// Called by the Commit and throws an exception if, for some reason, commiting
    /// item is considered invalid.
    protected override void CheckCanCommit(bool Reselect)
    {
        base.CheckCanCommit(Reselect);

        string S = tblItem.Rows[0].AsString("Code");

        if (string.IsNullOrEmpty(S))
            Sys.Error("No Code provided");
    } 
    /// Called by the Commit() to actually commit changes made by the Insert or Edit
    /// methods, to the underlying table tree (database).
    /// Returns the row id of the tblItem commited row.
    protected override object DoCommit(bool Reselect)
    {
        DataRow Row = tblItem.Rows[0];
        string Id = Row.AsString("Id");


        /* commit to our "datastore" */
        DataRow SourceRow = null;
        if (!tblSource.Locate("Id", new object[] { Id }, 
                       LocateOptions.None, out SourceRow))
        {
            SourceRow = tblSource.NewRow();
            tblSource.Rows.Add(SourceRow);
        }

        Row.CopyTo(SourceRow);

        /* save to file */
        tblSource.WriteXml(fileName, XmlWriteMode.WriteSchema);

        return Id;
    }
    /// Called by the Delete to actually delete
    /// a row to the underlying table tree (database).
    protected override void DoDelete(object RowId)
    {
        DataRow SourceRow = null;
        if (tblSource.Locate("Id", new object[] { RowId }, 
                      LocateOptions.None, out SourceRow))
        {
            tblSource.Rows.Remove(SourceRow);
            tblSource.WriteXml(fileName, XmlWriteMode.WriteSchema);
        }
    }

    /* construction */
    /// Static constructor
    static CustomBroker()
    {
        DS.Tables.Add(tblSource);

        if (File.Exists(fileName))
        {
            tblSource.ReadXml(fileName);
        }
        else
        {
            DataColumn Column = tblSource.Columns.Add("Id", typeof(System.String));
            tblSource.Columns.Add("Code", typeof(System.String));
            tblSource.Columns.Add("Name", typeof(System.String));
        }
    }
    /// Constructor
    public CustomBroker()
    {
    }

    /* public overrides */
    /// Locates a row in the tblBrowser and, if needed
    /// in the database by loading the row to the tblBrowser.
    /// The search is always performed to the tblBrowser or the main table of the broker.
    /// FieldName is the column name to search and Value the value to locate
    public override DataRow Locate(string FieldName, object Value)
    {
        DataRow Result = base.Locate(FieldName, Value);
        if (Result == null)
        {
            BrowserSelectInternal();
            Result = _tblBrowser.Locate(FieldName, new object[] { Value }, LocateOptions.None);
        }

        return Result;
    }
}

创建带有自定义Broker的DataEntryBrokerForm

当相关的菜单项被点击时会发生什么。这里没有Command对象。

else if (sender == mnuDataEntryBrokerFormWithACustomBroker)
{
    DataEntryBrokerFormWithCustomBroker Form = 
                 new DataEntryBrokerFormWithCustomBroker();
    Form.MdiParent = this;
    Form.Show();
}

与前面使用标准SqlBroker的表单情况相比,没有太大区别。这是表单的代码。

/// This is a form with a broker.
/// A DataEntryBrokerForm class used with a custom Broker descendant.
/// Since this form is not created by a Command we have to pass the proper
/// information to its InitInfo property.
public partial class DataEntryBrokerFormWithCustomBroker : DataEntryBrokerForm
{

    /* overrides */
    /// The virtual BindControls() is called by the form initialization sequence
    /// and it just binds controls to data.
    protected override void BindControls()
    {
        base.BindControls();

        /* If you use the standard TextBox and not the TextBoxEx provided by Tripous,
           then you have to manually bind that text box as following */
        if (bsItem != null)
        {
            textBox1.DataBindings.Add(Ui.Bind("Text", bsItem, "Code"));
            textBox2.DataBindings.Add(Ui.Bind("Text", bsItem, "Name"));
        }
    }

    /* construction */
    /// Constructor
    public DataEntryBrokerFormWithCustomBroker()
    {
        InitializeComponent();

        if (!DesignMode)
        {
            /* InitInfo is a property of the BaseForm class. It is used to convey 
               initialization information to the initialization sequence of the form.
               When a form is created by a Command class 
               with its Kind set to CommandKind.Mdi or Modal
               the Command prepares that InitInfo properly. 
               Here there is not a Command, so we just pass the minimum information. */
            InitInfo = new ArgList();
            InitInfo["Broker"] = new CustomBroker();
            InitInfo["DefaultTitle"] = "DataEntryBrokerForm with a custom-made Broker";
        }
    }
}

我们提供给InitInfo属性的最关键信息是“Broker”变量。我们只需创建一个CustomBroker类的实例并将该对象传递。我们从DataEntryBrokerForm继承的InitializeBroker()方法从InitInfo中提取Broker实例并赋值给一个成员字段。

protected virtual void InitializeBroker()
{
    if (initInfo != null)
    {
        broker = initInfo.ValueOf("Broker", broker);

        if (broker != null)
        {
           broker.Initialize(IsListForm);
        }
    } 
}

绑定到单个DataTable的主表单

相关的菜单显示表单。同样,没有Command对象。

else if (sender == mnuDataEntryFormWithASingleDataTable)
{
    DataEntryFormWithASingleDataTable Form = new DataEntryFormWithASingleDataTable();
    Form.MdiParent = this;
    Form.Show();
}

这是表单的代码

/// This form uses no broker at all.
/// A DataEntryForm class with a single table
/// used both as the browser and as the top table.
/// Table data is saved to a plain xml file.
/// 
/// Since this form is not created by a Command we have to pass the proper
/// information to its InitInfo property.
public partial class DataEntryFormWithASingleDataTable : Tripous.Forms.DataEntryForm
{
    string fileName = Path.GetFullPath(@"..\..\Customers.XML");
    DataSet DS = Db.CreateDataset();
    MemTable tblCustomers = new MemTable("Customers");

    /* private */
    void TablesSetup()
    {
        DS.Tables.Add(tblCustomers);

        if (File.Exists(fileName))
        {
            tblCustomers.ReadXml(fileName);
        }
        else
        {
            /* add schema to the table */
            DataColumn Column = tblCustomers.Columns.Add("Id", typeof(System.Int32));
            Column.AutoIncrement = true;
            Column.AutoIncrementSeed = 1;

            tblCustomers.Columns.Add("Code", typeof(System.String));
            tblCustomers.Columns.Add("Name", typeof(System.String));
        }

    }
        
    /* overrides */
    /// The virtual BindControls() is called by the form initialization sequence
    /// and it just binds controls to data.
    protected override void BindControls()
    {
        base.BindControls();

        /* Since there is no broker in this form and subsequentially no descriptors of any
           type, we have to manually bind our controls */
        if (bsBrowser != null)
        {
            textBox1.DataBindings.Add(Ui.Bind("Text", bsBrowser, "Code"));
            textBox2.DataBindings.Add(Ui.Bind("Text", bsBrowser, "Name"));
        }
    }
    /// Processes the Cmd. Cmd must be a "close" Cmd, that is OK, Cancel or Close.
    protected override void ProcessClose(StdCmd Cmd)
    {
        base.ProcessClose(Cmd);
        if (Bf.Member(ClosingStdCmd, StdCmd.OK | StdCmd.Close))
            tblCustomers.WriteXml(fileName, XmlWriteMode.WriteSchema);
    }
     
    /* construction */
    /// Constructor
    public DataEntryFormWithASingleDataTable()
    {
        InitializeComponent();

        if (!DesignMode)
        {
            TablesSetup();

            /* InitInfo is a property of the BaseForm class. It is used to convey 
               initialization information to the initialization sequence of the form.
               When a form is created by a Command class 
               with its Kind set to CommandKind.Mdi or Modal
               the Command prepares that InitInfo properly. 
               Here there is not a Command, so we just pass the minimum information. */
            InitInfo = new ArgList();
            InitInfo.Add("tblBrowser", tblCustomers);
            InitInfo.Add("tblItem", tblCustomers); 
            InitInfo["DefaultTitle"] = "DataEntryForm with a single DataTable";
        }
    }
}

只有一个DataTable,即tblCustomers,它同时扮演着浏览表和项表的作用。

我们的表单不是Broker表单。它继承自Tripous.Forms.DataEntryForm,该类对Broker一无所知。所以,由于在这种情况下没有Broker,我们将相同的tblCustomers作为tblBrowsertblItem传递给表单的InitInfo属性。tblCustomers的模式由TablesSetup()方法创建。当表单关闭时,ProcessClose()方法将tblCustomers保存到一个普通的XML文件中。

绑定到通用BindingList的主表单

显示表单没有什么特别之处。

else if (sender == mnuDataEntryFormWithAGenericBindingList)
{
    DataEntryFormWithBindingList Form = new DataEntryFormWithBindingList();
    Form.MdiParent = this;
    Form.Show();
}

在此表单情况下,我们使用BindingListEx实例作为数据存储。BindingListEx继承自泛型BindingList并提供了一些额外的功能。该泛型列表中的类型参数是一个简单的Person类。没有什么特别之处,但足以满足这个描述如何将Tripous DataEntryForm绑定到通用列表的示例。

public class Person
{
    public Person()
    {
    }

    public string Code { get; set; }
    public string Name { get; set; }
}

这是表单的代码。

/// This form uses no broker at all.
/// 
/// A DataEntryForm class with no DataTable at all.
/// It uses a BindingList, actually a BindingListEx which is a Tripous class.
/// BindindListEx is a bindable, sortable and searchable
/// generic BindingList with overridable methods.
public partial class DataEntryFormWithBindingList : DataEntryForm
{
    string fileName = Path.GetFullPath(@"..\..\Persons.XML");
    BindingListEx<Person> persons = new BindingListEx<Person>();

    /* overrides */
    /// The virtual BindControls() is called by the form initialization sequence
    /// and it just binds controls to data.
    protected override void BindControls()
    {
        base.BindControls();

        /* Since there is no broker in this form and subsequentially no descriptors of any
           type, we have to manually bind our controls */
        if (bsBrowser != null)
        {
            textBox1.DataBindings.Add(Ui.Bind("Text", bsBrowser, "Code"));
            textBox2.DataBindings.Add(Ui.Bind("Text", bsBrowser, "Name"));
        }
    }

    /// Processes the Cmd. Cmd must be a "close" Cmd, that is OK, Cancel or Close.
    protected override void ProcessClose(StdCmd Cmd)
    {
        base.ProcessClose(Cmd);

        /* Pass the persons BindingListEx to the XmlPersistor and ask it to save it */
        if (Bf.Member(ClosingStdCmd, StdCmd.OK | StdCmd.Close))
            XmlPersistor.SaveToFile(persons, fileName);

    }

    /* construction */
    /// Constructor
    public DataEntryFormWithBindingList()
    {
        InitializeComponent();

        if (!DesignMode)
        {
            /* prepare column information for the browser grid */
            ColumnInfoList BrowserColumnList = new ColumnInfoList();
            BrowserColumnList.Add(new ColumnInfo("Code"));
            BrowserColumnList.Add(new ColumnInfo("Name"));

            persons.IsBound = true;
            InitInfo = new ArgList();
            InitInfo.Add("DataList", persons);
            InitInfo["BrowserColumnList"] = BrowserColumnList;
            InitInfo["DefaultTitle"] = "DataEntryForm and a generic BindingList";

            /* load the persons BindingListEx using the XmlPersistor */
            XmlPersistor.LoadFromFile(persons, fileName);
        }
    }
}

同样,没有Broker,没有Command。一切都是编码的。我们的表单继承DataEntryForm,该类对Broker一无所知。

实际上,由于没有DataTable,我们必须提供有关表单浏览部分(只读DataGridView)的列的信息。我们通过创建一个Tripous.Data.ColumnInfoList实例和一些ColumnInfo对象来做到这一点。我们将ColumnInfoList作为InitInfo属性的“BrowserColumnList”变量传递。我们从父类DataEntryForm继承的DoBrowserSetupGridColumns()方法现在拥有足够的信息来完成其工作,并在DataGridView中创建列。

由于没有Broker或DataTable可以传递给InitInfo,我们只需赋值“DataList”变量,传递PersonBindingListEx对象。DataEntryForm将使用该列表对象作为其数据存储。

静态Tripous.XmlPersistor类用于将该列表序列化和反序列化到XML文件。XmlPersistor和Tripous的XML持久化功能值得单独教程。

结论

Tripous的DataEntryFormDataEntryBrokerForm类非常灵活,可以与各种数据源一起用作数据录入表单:SqlBroker、自定义Broker、DataTables,甚至通用列表。

© . All rights reserved.