Adapting a Grid to REP++

Similar documents
Representing Recursive Relationships Using REP++ TreeView

DataGridView FAQ.doc. DataGridView FAQ.doc

Inheriting Windows Forms with Visual C#.NET

CALCULATOR APPLICATION

Data Gr id Vie w C ont ro l

Bachelor s Thesis: Building Web Application for Mahabad University Graduate Affairs Afsaneh Nezami Savojbolaghi

Hierarchical inheritance: Contains one base class and multiple derived classes of the same base class.

IBSDK Quick Start Tutorial for C# 2010

10Tec igrid for.net 6.0 What's New in the Release

Introduce C# as Object Oriented programming language. Explain, tokens,

Item 18: Implement the Standard Dispose Pattern

User Filter State. Chapter 11. Overview of User Filter State. The PDSAUserFilterState Class

Final exam. Final exam will be 12 problems, drop any 2. Cumulative up to and including week 14 (emphasis on weeks 9-14: classes & pointers)

Form Properties Window

Siebel Web Services RAD Development Futures

UPDATING DATA WITH.NET CONTROLS AND A PROBINDINGSOURCE

Windows Database Updates

CSIS 1624 CLASS TEST 6

CSC 355 PROJECT 4 NETWORKED TIC TAC TOE WITH WPF INTERFACE

C#.Net. Course Contents. Course contents VT BizTalk. No exam, but laborations

C:\homeworks\PenAttention_v13_src\PenAttention_v13_src\PenAttention4\PenAttention\PenAttention.cs 1 using System; 2 using System.Diagnostics; 3 using

// Specify SEF file to load. oschema = (edischema) oedidoc.loadschema(spath + sseffilename, SchemaTypeIDConstants. Schema_Standard_Exchange_Format);

Writing Your First Autodesk Revit Model Review Plug-In

Click on the empty form and apply the following options to the properties Windows.

Introduction to Programming Using Java (98-388)

What are the characteristics of Object Oriented programming language?

C#: framework overview and in-the-small features

In-Class Worksheet #4

You can call the project anything you like I will be calling this one project slide show.

Lecture 3. COMP1006/1406 (the Java course) Summer M. Jason Hinek Carleton University

string spath; string sedifile = "277_005010X228.X12"; string sseffile = "277_005010X228.SemRef.EVAL0.SEF";

ADO.NET 2.0. database programming with

Mainly three tables namely Teacher, Student and Class for small database of a school. are used. The snapshots of all three tables are shown below.

Chapter 11. Categories of languages that support OOP: 1. OOP support is added to an existing language

private string sconnection = ConfigurationManager.ConnectionStrings["Development"].ConnectionString

Repository Pattern and Unit of Work with Entity Framework

Programming Language Concepts Object-Oriented Programming. Janyl Jumadinova 28 February, 2017

How to use data sources with databases (part 1)

Rules Engine Cookbook

AP COMPUTER SCIENCE JAVA CONCEPTS IV: RESERVED WORDS

TARGETPROCESS PLUGIN DEVELOPMENT GUIDE

Overriding Variables: Shadowing

Sub To Srt Converter. This is the source code of this program. It is made in C# with.net 2.0.

What property of a C# array indicates its allocated size? What keyword in the base class allows a method to be polymorphic?

Visual Studio.NET enables quick, drag-and-drop construction of form-based applications

// Precondition: None // Postcondition: The address' name has been set to the // specified value set;

Yes, this is still a listbox!

Note 12/1/ Review of Inheritance Practice: Please write down 10 most important facts you know about inheritance...

Data Structures and Other Objects Using C++

INTRODUCTION TO.NET. Domain of.net D.N.A. Architecture One Tier Two Tier Three Tier N-Tier THE COMMON LANGUAGE RUNTIME (C.L.R.)

The contents of this document are directly taken from the EPiServer SDK. Please see the SDK for further technical information about EPiServer.

Experiment 5 : Creating a Windows application to interface with 7-Segment LED display

C# winforms gridview

Adding Contracts to C#

Appendix A Programkod

9 A Preview of.net 2.0

Visual Basic/C# Programming (330)

This is the empty form we will be working with in this game. Look under the properties window and find the following and change them.

Technical Bulletin 1002 RFgen 5.1 Perfecting Your Presentation with the PanelList Control

C++ Inheritance and Encapsulation

Start Visual Studio, create a new project called Helicopter Game and press OK

NetAdvantage for WPF 13.1 Service Release Notes August 2013

CS 251 Intermediate Programming Inheritance

Ignite UI Release Notes

Professional ASP.NET Web Services : Asynchronous Programming

The Open Core Interface SDK has to be installed on your development computer. The SDK can be downloaded at:

Visual Element Migrator

Using KE IMu's.Net API

INFRAGISTICS Silverlight 15.1 Volume Release Notes 2015

COOKBOOK Sending an in Response to Actions

Chapter 1: Object-Oriented Programming Using C++

- 1 - Handout #22S May 24, 2013 Practice Second Midterm Exam Solutions. CS106B Spring 2013

Jordan University of Science & Technology Department of Computer Science CS 211 Exam #1 (23/10/2010) -- Form A

Main Game Code. //ok honestly im not sure, if i guess its a class ment for this page called methodtimer that //either uses the timer or set to timer..

Program Contents: DOTNET TRAINING IN CHENNAI

Ignite UI Release Notes

II. Programming Technologies

We are going to use some graphics and found a nice little batman running GIF, off course you can use any image you want for the project.

Volume CREATIVE DATA TECHNOLOGIES, INC. DATALAYER.NET. Getting Started Guide

ECE 449 OOP and Computer Simulation Lecture 11 Design Patterns

GENESIS64 Using IRepository to Access Configuration Databases

Chapter 4. Windows Database Using Related Tables The McGraw-Hill Companies, Inc. All rights reserved. McGraw-Hill

// Specify SEF file to load. edischema oschema = oedidoc.loadschema(spath + sseffilename, SchemaTypeIDConstants. Schema_Standard_Exchange_Format);

Programming with ADO.NET

namespace csharp_gen277x214 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }

S.Sakthi Vinayagam Sr. AP/CSE, C.Arun AP/IT

Classes in C# namespace classtest { public class myclass { public myclass() { } } }

LAMPIRAN. 1. Source Code Data Buku. using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.

How to work with data sources and datasets

Copyright...3. Plug-In Development Guide Creating Widgets for Dashboards... 5

VIRTUAL FUNCTIONS Chapter 10

10Tec igrid for.net 3.0 What's New in the Control

Chapter 3. Windows Database Applications The McGraw-Hill Companies, Inc. All rights reserved. McGraw-Hill

C# Programming: From Problem Analysis to Program Design 2nd Edition. David McDonald, Ph.D. Director of Emerging Technologies. Objectives (1 of 2)

Day 4. COMP1006/1406 Summer M. Jason Hinek Carleton University

10Tec igrid for.net What's New in the Control

.Net Technologies. Components of.net Framework

Task Graph. Name: Problem: Context: D B. C Antecedent. Task Graph

Advanced Programming C# Lecture 2. dr inż. Małgorzata Janik

private string sconnection = ConfigurationManager.ConnectionStrings["Development"].ConnectionString

Transcription:

Adapting a Grid to REP++ Author: R&D Department Publication date: April 28 2006 2006 Consyst SQL Inc. All rights reserved.

Adapting a Grid to REP++ Overview The REP++toolkit for Windows provides a good amount of Windows Forms controls. These controls normally inherit from a.net counterpart and attach them to the REP++ data and metadata. It is quite common to adapt other Windows Forms controls to REP++. The REP++toolkit for Windows already includes a subclass for the.net Windows Forms DataGridView control. This article describes how this adaptation was done. The DataGridView control The DataGridView control appears in version 2 of.net. This grid, which supersedes the previous DataGrid control, is more powerful and more flexible. To adapt this grid, the following tasks were done: Subclassing the DataGridView class. Binding the grid to a REP++ group instance data. Binding the grid to the related REP++ group metadata. Validating the user s data. Adapting the grid so it can be used in the REP++framework for Windows. To adapt a grid, we must also consider implementing design time support. Design time support provides a way for the grid to be attached to a REP++ source from a list. It also supports a redraw of the grid when its properties are changed. Subclassing the DataGridView class The first step is to define a new class that inherits from the DataGridView class. The class also implements the CrdGrpControlUtil.ICrdGrpControl and ILineListHandler interface. The CrdGrpControlUtil.ICrdGrpControl interface is used so the class can embed the CrdGrpControlUtil object. This object is used to help implement design time support (explained later in the document). using System; using System.Collections.Generic; using System.Text; using System.ComponentModel; using System.ComponentModel.Design; using System.Windows.Forms; using System.Windows.Forms.Design; using RepPP; using RepPP.Toolkit; namespace RepPP.Toolkit.Window { public class DataGridViewGInst : DataGridView, CrdGrpControlUtil.ICrdGrpControl, ILineListHandler { Adapting a Grid to REP++ 1

Binding data to the grid The DataGridView control supports the standard Windows Forms data binding model. The programmer can use a variety of data sources. Alternatively, the programmer can add rows and columns to the control and manually populate it with data (virtual mode). The DataGridView subclass in the REP++toolkit for Windows adopts the DataSource approach. In the future, the subclass may be extended to also use the grid virtual mode to provide the data to it. The REP++toolkit already provides a data source component that connects a control to a group instance (DataSourceGInst). The DataGridView grid can easily be directly bound with the DataSourceGInst without any additional codes. However, in this implementation, the user of the grid doesn t need to define a DataSourceGInst and attach it to the grid. Instead, the grid is embedding its own DataSourceGInst. The user can attach the grid at design time with a REP++ card group. At runtime, the DataGridView is attached directly to a group instance. To implement this behavior, the class must include a DataSourceGInst object and implement some design time support. The following code embeds a DataSourceGInst in the class: private DataSourceGInst m_datasourceginst; public DataGridViewGInst() : base() { m_datasourceginst = new DataSourceGInst(this, false); base.datasource = m_datasourceginst; protected override void Dispose(bool disposing) { if (disposing){ if (m_datasourceginst!= null) { m_datasourceginst.dispose(); m_datasourceginst = null; base.dispose(disposing); Embedding the DataSourceGInst is not enough. Some properties that are accessible by the DataSourceGInst must now be accessible directly by the grid. [Browsable(false)] [Description("Data Source attached to a group instance")] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] protected virtual DataSourceGInst DataSourceGInst { return(m_datasourceginst); [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Browsable(false)] RepPP.Application CrdGrpControlUtil.ICrdGrpControl.Application { return(datasourceginst.application); [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [Editor(typeof(CrdGrpControlUtil.CrdGrpControlEditor), typeof(system.drawing.design.uitypeeditor))] [Browsable(true)] [Bindable(true)] [Category("Data")] Adapting a Grid to REP++ 2

[Description("Name of the CardGroup attached to the source")] public CrdGrpFullName CardGroupFullName { return(datasourceginst.cardgroupfullname); set { DataSourceGInst.CardGroupFullName = value; if (DesignMode) { base.datasource = null; base.datasource = m_datasourceginst; [Browsable(false)] [Description("Group which will be represented by this Data Source")] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] public virtual Group Group { return(datasourceginst.group); [Browsable(false)] [Description("GroupInstance represented by this Data Source")] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] public virtual GroupInstance GroupInstance { return(datasourceginst.groupinstance); set { DataSourceGInst.GroupInstance = value; base.datasource = DataSourceGInst; [Browsable(true)] [Category("Behavior")] [Description("How to display a choice value")] public bool ShowDescription { return(datasourceginst.showdescription == DataSourceGInst.ShowDescriptionE.Always); set { DataSourceGInst.ShowDescription = (value)? DataSourceGInst.ShowDescriptionE.Always : DataSourceGInst.ShowDescriptionE.Never; When the user attaches the grid to a card group, a list of cards and a list of groups in the associated card are proposed. To implement this behavior, some design time support must be implemented. This design time support is already done in part in the CrdGroupControlUtil class, and this class is already embedded in the DataSourceGInst class. To attach the design time support to the property, the following attribute has been included in its definition: [Editor(typeof(CrdGrpControlUtil.CrdGrpControlEditor), typeof(system.drawing.design.uitypeeditor))] The class also implements the CrdGrpControlUtil.ICrdGrpControl interface. This interface is called by the embedded CrdGrpControlUtil object (which is embedded by the DataSourceGInst class). Adapting a Grid to REP++ 3

void CrdGrpControlUtil.ICrdGrpControl.TriggerComponentChange() { DataSourceGInst.TriggerComponentChange(); // Used only in design time. void ControlUtil.IRepControl.RepPPReInit() { DataSourceGInst.RepPPReInit(); // Reinitialize REP++ Metadata. Use only in design time when REP++ is reinitialized. The final step to embed the DataSourceGInst is to forbid the change of the data source at design time. [Browsable(false)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] public new object DataSource { return(datasourceginst); set { // Do nothing The property is redefined with the new modifier because the base property is not specified as virtual. The property effectively disappears from the designer. Setting the property at runtime also does nothing. However, the DataGridView control has a design time interface that permits the change of the DataSource. There is not easy way to forbid that. Binding the grid to the related REP++ group metadata REP++ provides metadata that can be used to control the grid. If a column of a grid is represented by a combo box, the REP++ metadata can be used to populate its choice list. If the attached REP++ field is not accessible or invisible, the related column can be set as readonly or hidden. The following routine is doing so for a column: protected virtual void SetColumnInfo(DataGridViewColumn col, Field fld, bool bshowdescription) { RepPP.ChoiceList choicelist; string strchoice; DataGridViewComboBoxColumn cb; if (col is DataGridViewComboBoxColumn) { cb = (DataGridViewComboBoxColumn)col; choicelist = fld.choicelist; cb.items.clear(); for (int iindex = 0; iindex < choicelist.count; iindex++) { if (bshowdescription) { strchoice = choicelist.getdesc(iindex); if (strchoice == null strchoice == String.Empty) { strchoice = choicelist.getcode(iindex); else { strchoice = choicelist.getcode(iindex); cb.items.add(strchoice); else if (fld.type == RepPP.FieldType.sdFieldMoney) { col.defaultcellstyle.alignment = DataGridViewContentAlignment.MiddleRight; if (col is DataGridViewTextBoxColumn) { ((DataGridViewTextBoxColumn)col).MaxInputLength = fld.maxsize; col.readonly =!fld.isselectable fld.isprimarykey; Adapting a Grid to REP++ 4

col.visible = fld.isvisible; The following routine iterates over the list of columns of the grid and calls the previous routine for each column attached to a REP++ field: protected virtual void SetColumnsInfo() { RepPP.Group grp; RepPP.Field fld; string strpropname; bool bshowdescription; bshowdescription = ShowDescription; grp = Group; if (grp!= null) { foreach (DataGridViewColumn col in Columns) { strpropname = col.datapropertyname; fld = (strpropname == null)? null : grp.fields[col.datapropertyname]; if (fld!= null) { SetColumnInfo(col, fld, bshowdescription); This routine has to be called at strategic times: When the control is created. When a new card group is assigned. When REP++ is refreshed. protected override void OnCreateControl() { base.oncreatecontrol(); SetColumnsInfo(); The following code must be added to these routines: protected override void OnCreateControl() { base.oncreatecontrol(); SetColumnsInfo(); [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [Editor(typeof(CrdGrpControlUtil.CrdGrpControlEditor), typeof(system.drawing.design.uitypeeditor))] [Browsable(true)] [Bindable(true)] [Category("Data")] [Description("Name of the CardGroup attached to the source")] public CrdGrpFullName CardGroupFullName { return(datasourceginst.cardgroupfullname); set { DataSourceGInst.CardGroupFullName = value; if (DesignMode) { base.datasource = null; base.datasource = m_datasourceginst; SetColumnsInfo(); Adapting a Grid to REP++ 5

The grid must implement a special behavior for columns attached to a field member of the primary key. The column must be editable if the line is new. Otherwise, the column must be set to read only. The following code implements this behavior: private int FindColumnIndex(Field fld) { int iretval = 1; foreach (DataGridViewColumn col in Columns) { if (col.datapropertyname == fld.name) { iretval = col.index; break; return(iretval); private int GetGInstLineFromRowIndex(int irowindex){ GroupInstance gi; DataSourceGInst datasourceginst; DataRowGInst rowginst; int iretval = 1; gi = GroupInstance; datasourceginst = DataSourceGInst; if (irowindex >= 0 && irowindex < datasourceginst.count){ rowginst = (datasourceginst == null)? null : datasourceginst[irowindex] as DataRowGInst; if (gi!= null && rowginst!= null) { iretval = gi.linefrombookmark(rowginst.bookmark); return(iretval); private void SetRowState(int ilineindex, int irowindex){ DataSourceGInst datasourceginst; int icolumnindex; if (GroupInstance.ThisLineState(iLineIndex) == LineState.sdLineNew){ datasourceginst = DataSourceGInst; foreach(field fld in datasourceginst.fields) { if (fld.isprimarykey) { icolumnindex = FindColumnIndex(fld); if (icolumnindex!= 1) { Rows[iRowIndex].Cells[iColumnIndex].ReadOnly = false; protected override void OnRowEnter(DataGridViewCellEventArgs e) { int inewline = 1; base.onrowenter(e); inewline = GetGInstLineFromRowIndex(e.RowIndex); SetRowState(iNewLine, e.rowindex); Validating the user s data It is very important to be able to validate the data entered by the user. REP++ already provides a good mechanism to validate data. The grid must be able to call the REP++ validation routine at strategic times and to display the error message if necessary. Adapting a Grid to REP++ 6

private string m_strerror; protected override void OnRowValidating(DataGridViewCellCancelEventArgs e) { GroupInstance gi; DataGridViewRow row; int ilineindex; string strerror; int icolindex; base.onrowvalidating(e); if (!e.cancel) { gi = GroupInstance; ilineindex = GetGInstLineFromRowIndex(e.RowIndex); if (gi!= null && ilineindex!= 1) { if (gi.thislinestate(ilineindex)!= LineState.sdLineDeleted) { gi.group.saveactivegroupinstance(); gi.savelinepos(); try { gi.select(false, false); gi.selectline(ilineindex, true, false); row = Rows[e.RowIndex]; row.errortext = ""; foreach (DataGridViewCell cell in row.cells) { cell.errortext = ""; strerror = ""; gi.application.fldonerror += new FldOnErrorEventHandler(Application_FldOnError); foreach (FieldInstance fi in gi.fieldinstances) { m_strerror = ""; if (fi.field.validate()!= 0) { e.cancel = true; icolindex = FindColumnIndex(fi.Field); if (icolindex!= 1) { row.cells[icolindex].errortext = m_strerror; if (strerror!= String.Empty) { strerror += "\r\n"; strerror += fi.field.prompt + ": " + m_strerror; gi.application.fldonerror = new FldOnErrorEventHandler(Application_FldOnError); if (e.cancel) { row.errortext = strerror; else { if (gi.validactiveline(true)!= 0) { e.cancel = true; finally { gi.restorelinepos(true); gi.group.restoreactivegroupinstance(true); void Application_FldOnError(object sender, FieldGenEventArgs e) { m_strerror = e.errortext; The main goal of this routine is to validate each field attached to a cell. If an error is found, the error text is attached to the cell. The error text is also concatenated to a row error list. If any error occurs, the row is flagged as being in error. If no error occurs, the ValidActiveLine is called to ensure that all active child data are also valid. One strange thing about this routine Adapting a Grid to REP++ 7

is the necessity to trap the REP++ FldOnError event. Actually, this is the only way to validate a field and receive the error message. Adapting the grid so it can be used in the REP++framework for Windows The REP++framework for Windows application is built to accept compatible grids. A grid must implement the ILineListHandler interface to be compatible. This interface defines the minimum functionalities a grid must include to be used to display and edit data. The ILineListHandler is defined as follows: public interface ILineListHandler { event LineSelectedInListEventHandler LineSelectedInList; bool SelectLine(int ipos); bool InsertLine(bool batend); bool DuplicateLine(); bool DeleteCurrentLine(); void CommitEdit(); void Refresh(); void AssociateGroupInstance(GroupInstance ginst); void OnLineSelectedInList(LineSelectedInListEventArgs e); The event is used to inform the framework that a row in the grid is being selected. The SelectLine, InsertLine, DuplicateLine, DeleteCurrentLine and Refresh methods are used so the framework can do the corresponding function on the grid. CommitEdit is called to ensure the edit is done in a row before a validation occurs. Finally, the AssociateGroupInstance method associates a new group instance to the grid when a parent line changes. private LineSelectedInListEventArgs m_evtarglastrowchange = null; public event LineSelectedInListEventHandler LineSelectedInList; protected override void OnSelectionChanged(EventArgs e) { base.onselectionchanged(e); if (m_evtarglastrowchange!= null) { OnLineSelectedInList(m_evtArgLastRowChange); m_evtarglastrowchange = null; public bool SelectLine(int ipos) { DataGridViewRow row; bool bretval; if (GroupInstance == null) { else { ClearSelection(); row = Rows[iPos]; if (row.cells.count > 0) { CurrentCell = row.cells[0]; row.selected = true; bretval = true; return(bretval); public bool InsertLine(bool batend) { DataGridViewRow row; bool bretval; Adapting a Grid to REP++ 8

if (GroupInstance == null) { else { if (!AllowUserToAddRows) { DataSourceGInst.AddNew(); row = Rows[Rows.Count 1]; if (row.cells.count > 0) { CurrentCell = row.cells[0]; CurrentCell.Selected = true; bretval = true; return(bretval); public bool DuplicateLine() { bool bretval; DataGridViewRow row; if (GroupInstance == null) { else { if (CurrentRow == null) { else { DataSourceGInst.AddDuplicate(); row = Rows[Rows.Count 1]; if (row.cells.count > 0) { CurrentCell = row.cells[0]; CurrentCell.Selected = true; bretval = true; return(bretval); public bool DeleteCurrentLine() { bool bretval; if (GroupInstance == null) { else { if (CurrentRow!= null) { Rows.Remove(CurrentRow); bretval = true; else { return(bretval); public void CommitEdit() { CommitEdit(DataGridViewDataErrorContexts.Commit); void ILineListHandler.Refresh() { GroupInstance ginst; ginst = GroupInstance; GroupInstance = null; GroupInstance = ginst; public void AssociateGroupInstance(GroupInstance ginst) { GroupInstance = ginst; Adapting a Grid to REP++ 9

public void OnLineSelectedInList(LineSelectedInListEventArgs e) { if (LineSelectedInList!= null) { LineSelectedInList(this, e); Finally, the following routine needs to be changed as follow: protected override void OnRowEnter(DataGridViewCellEventArgs e) { int ioldline = 1; int inewline = 1; base.onrowenter(e); if (CurrentRow!= null) { ioldline = GetGInstLineFromRowIndex(CurrentRow.Index); inewline = GetGInstLineFromRowIndex(e.RowIndex); m_evtarglastrowchange = new LineSelectedInListEventArgs(iOldLine, inewline); SetRowState(iNewLine, e.rowindex); The full source of the DataGridViewGInst class can be found in the RepPP.Toolkit.V1 project. Adapting a Grid to REP++ 10