Added SessionInfo property to dlgApproveProcedure and ApprovalInfo classes.

Added SessionInfo property to DlgPrintProcedure and added checks to print routines to notify user that another user has procedure checked out with a confirmation to continue printing.
Added code to support multiuser and security including initializing security, creating user if user does not exist in database, checking in and out DocVersions, Procedures and Documents and keeping the database notified that user is still active.
Added label to bottom of PROMS main form to indicate who user is and what security they have on open objects.
This commit is contained in:
Rich 2013-11-20 23:00:28 +00:00
parent 46a70899bd
commit b634967817
4 changed files with 357 additions and 5 deletions

View File

@ -15,6 +15,12 @@ namespace VEPROMS
{
public partial class DlgPrintProcedure : DevComponents.DotNetBar.Office2007Form
{
private SessionInfo _MySessionInfo;
public SessionInfo MySessionInfo
{
get { return _MySessionInfo; }
set { _MySessionInfo = value; }
}
private bool _Automatic;
public bool Automatic
{
@ -487,6 +493,21 @@ namespace VEPROMS
private string _MultiunitPdfLocation = string.Empty;
private void CreatePDFs()
{
StringBuilder sb = new StringBuilder();
foreach (ProcedureInfo myProc in _DocVersionInfo.Procedures)
{
string message = string.Empty;
if (!MySessionInfo.CanCheckOutItem(myProc.ItemID, CheckOutType.Procedure, ref message))
{
sb.AppendLine(message);
}
}
if (sb.Length > 0)
{
if (MessageBox.Show(sb.ToString() + Environment.NewLine + Environment.NewLine + "Do you want to continue to print all procedures?", "Procedures Already Checked Out", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
return;
}
CreateDebugFiles();
// If file exists, determine if overwrite checkbox allows overwrite, if not prompt.
@ -600,6 +621,12 @@ namespace VEPROMS
}
private void CreatePDF()
{
string message = string.Empty;
if (!MySessionInfo.CanCheckOutItem(MyProcedure.ItemID, CheckOutType.Procedure, ref message))
{
if (MessageBox.Show(this, message + Environment.NewLine + Environment.NewLine + "Do you want to continue to print the procedure?", "Procedure Is Checked Out", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
return;
}
CreateDebugFiles();
// If file exists, determine if overwrite checkbox allows overwrite, if not prompt.

View File

@ -39,6 +39,16 @@ namespace VEPROMS
get { return _ApplicabilityIndex; }
set { _ApplicabilityIndex = value; }
}
private SessionInfo _MySessionInfo;
public SessionInfo MySessionInfo
{
get { return _MySessionInfo; }
set
{
_MySessionInfo = value;
_MyApproval.MySessionInfo = _MySessionInfo;
}
}
private ApprovalInfo _MyApproval = new ApprovalInfo();
private bool _CheckForMore = false;
private DocVersionInfo _MyDocVersion;
@ -703,6 +713,12 @@ namespace VEPROMS
if (StatusUpdated != null)
StatusUpdated(sender, e);
}
private SessionInfo _MySessionInfo;
public SessionInfo MySessionInfo
{
get { return _MySessionInfo; }
set { _MySessionInfo = value; }
}
private int _RevType;
public int RevType
{

View File

@ -71,6 +71,7 @@ namespace VEPROMS
this.btnItemInfo = new DevComponents.DotNetBar.ButtonItem();
this.lblItemID = new DevComponents.DotNetBar.LabelItem();
this.lblResolution = new DevComponents.DotNetBar.LabelItem();
this.lblUser = new DevComponents.DotNetBar.LabelItem();
this.btnEditItem = new DevComponents.DotNetBar.ButtonItem();
this.btnFixMSWord = new DevComponents.DotNetBar.ButtonItem();
this.epAnnotations = new DevComponents.DotNetBar.ExpandablePanel();
@ -494,6 +495,7 @@ namespace VEPROMS
this.lblItemID,
this.lblResolution,
this.btnEditItem,
this.lblUser,
this.btnFixMSWord});
this.bottomBar.Location = new System.Drawing.Point(5, 569);
this.bottomBar.Name = "bottomBar";
@ -585,6 +587,13 @@ namespace VEPROMS
this.lblResolution.Text = "Edit";
this.lblResolution.Click += new System.EventHandler(this.lblResolution_Click);
//
// lblUser
//
this.lblUser.BackColor = System.Drawing.Color.Transparent;
this.lblUser.ForeColor = System.Drawing.SystemColors.MenuText;
this.lblUser.Name = "lblUser";
this.lblUser.Text = "User";
//
// btnEditItem
//
this.btnEditItem.ForeColor = System.Drawing.Color.Blue;
@ -1600,6 +1609,7 @@ namespace VEPROMS
private DevComponents.DotNetBar.LabelItem lblItemID;
private System.Windows.Forms.ComboBox cmbFont;
private DevComponents.DotNetBar.LabelItem lblResolution;
private DevComponents.DotNetBar.LabelItem lblUser;
private DevComponents.DotNetBar.ButtonItem btnEditItem;
private DevComponents.DotNetBar.TabControlPanel tabControlPanel1;
private DevComponents.DotNetBar.TabItem infotabHistory;

View File

@ -32,6 +32,7 @@ namespace VEPROMS
private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
#endregion
#region PropertiesVariables
private int securityRole;
private bool _panelExpandedChanging = false;
Color _CommentTitleBckColor;
DocVersionInfo _SelectedDVI = null;
@ -269,6 +270,8 @@ namespace VEPROMS
tv.ApproveAllProcedures += new vlnTreeViewEvent(tv_ApproveAllProcedures);
tv.ApproveSomeProcedures += new vlnTreeViewEvent(tv_ApproveSomeProcedures);
tv.ReportAllProceduresInconsistencies += new vlnTreeViewEvent(tv_ReportAllProceduresInconsistencies);
tv.RefreshCheckedOutProcedures += new vlnTreeViewEvent(tv_RefreshCheckedOutProcedures);
tv.ProcedureCheckedOutTo += new vlnTreeViewEvent(tv_ProcedureCheckedOutTo);
tv.ViewPDF += new vlnTreeViewPdfEvent(tv_ViewPDF);
displayApplicability.ApplicabilityViewModeChanged += new DisplayApplicability.DisplayApplicabilityEvent(displayApplicability_ApplicabilityViewModeChanged);
}
@ -396,11 +399,20 @@ namespace VEPROMS
DocVersionInfo dvi = (args.Node as VETreeNode).VEObject as DocVersionInfo;
if (dvi == null) return;
tc.SaveCurrentEditItem();
string message = string.Empty;
if (!MySessionInfo.CanCheckOutItem(dvi.VersionID, CheckOutType.DocVersion, ref message))
{
MessageBox.Show(this, message, "Working Draft Has Items Already Checked Out", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
int ownerid = MySessionInfo.CheckOutItem(dvi.VersionID, CheckOutType.DocVersion);
dvi.DocVersionConfig.SelectedSlave = args.UnitIndex;
dlgApproveProcedure dlg = new dlgApproveProcedure(dvi, true);
dlg.MySessionInfo = MySessionInfo;
dlg.ShowDialog(this);
displayHistory.RefreshList();
dvi.DocVersionConfig.SelectedSlave = 0;
MySessionInfo.CheckInItem(ownerid);
}
void tv_ApproveAllProcedures(object sender, vlnTreeEventArgs args)
@ -408,11 +420,75 @@ namespace VEPROMS
DocVersionInfo dvi = (args.Node as VETreeNode).VEObject as DocVersionInfo;
if (dvi == null) return;
tc.SaveCurrentEditItem();
string message = string.Empty;
if (!MySessionInfo.CanCheckOutItem(dvi.VersionID, CheckOutType.DocVersion, ref message))
{
MessageBox.Show(this, message, "Working Draft Has Items Already Checked Out", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
int ownerid = MySessionInfo.CheckOutItem(dvi.VersionID, CheckOutType.DocVersion);
dvi.DocVersionConfig.SelectedSlave = args.UnitIndex;
dlgApproveProcedure dlg = new dlgApproveProcedure(dvi);
dlg.MySessionInfo = MySessionInfo;
dlg.ShowDialog(this);
displayHistory.RefreshList();
dvi.DocVersionConfig.SelectedSlave = 0;
MySessionInfo.CheckInItem(ownerid);
}
void tv_RefreshCheckedOutProcedures(object sender, vlnTreeEventArgs args)
{
OwnerInfoList.Reset();
OwnerInfoList oil = OwnerInfoList.Get();
Dictionary<int, int> dicProcCheckedOut = new Dictionary<int, int>();
Dictionary<int, int> dicDocCheckedOut = new Dictionary<int, int>();
foreach (OwnerInfo oi in oil)
{
if (oi.SessionID != MySessionInfo.SessionID && oi.OwnerType == (byte)CheckOutType.Procedure)
dicProcCheckedOut.Add(oi.OwnerItemID, oi.OwnerID);
else if (oi.SessionID != MySessionInfo.SessionID && oi.OwnerType == (byte)CheckOutType.Document)
dicDocCheckedOut.Add(oi.OwnerItemID, oi.OwnerID);
}
if (args.Node.IsExpanded)
{
foreach (TreeNode tn in args.Node.Nodes)
{
ProcedureInfo pi = (tn as VETreeNode).VEObject as ProcedureInfo;
if (pi != null && dicProcCheckedOut.ContainsKey(pi.ItemID))
tn.ForeColor = Color.Red;
else
tn.ForeColor = Color.Black;
bool expanded = tn.IsExpanded;
if (!expanded)
tn.Expand();
foreach (TreeNode tnn in tn.Nodes)
{
SectionInfo si = (tnn as VETreeNode).VEObject as SectionInfo;
if (si != null && si.MyContent.MyEntry != null)
{
if (dicDocCheckedOut.ContainsKey(si.MyContent.MyEntry.DocID))
tnn.ForeColor = Color.Red;
else
tnn.ForeColor = Color.Black;
}
}
if (!expanded)
tn.Collapse();
}
}
}
void tv_ProcedureCheckedOutTo(object sender, vlnTreeEventArgs args)
{
ProcedureInfo pi = null;
SectionInfo si = null;
pi = (args.Node as VETreeNode).VEObject as ProcedureInfo;
if(pi == null)
si = (args.Node as VETreeNode).VEObject as SectionInfo;
UserInfo ui = UserInfo.GetByUserID(MySessionInfo.UserID);
dlgCheckedOutProcedure cop = new dlgCheckedOutProcedure(pi, si, ui);
cop.ShowDialog(this);
tv_RefreshCheckedOutProcedures(sender, new vlnTreeEventArgs(args.Node.Parent, null, 0));
}
void tv_ApproveProcedure(object sender, vlnTreeEventArgs args)
@ -421,10 +497,19 @@ namespace VEPROMS
pi.MyDocVersion.DocVersionConfig.SelectedSlave = args.UnitIndex;
if (pi == null) return;
tc.SaveCurrentEditItem(pi);
string message = string.Empty;
if (!MySessionInfo.CanCheckOutItem(pi.ItemID, CheckOutType.Procedure, ref message))
{
MessageBox.Show(this, message, "Procedure Already Checked Out", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
int ownerid = MySessionInfo.CheckOutItem(pi.ItemID, 0);
dlgApproveProcedure dlg = new dlgApproveProcedure(pi);
dlg.MySessionInfo = MySessionInfo;
dlg.ShowDialog(this);
displayHistory.RefreshList();
pi.MyDocVersion.DocVersionConfig.SelectedSlave = 0;
MySessionInfo.CheckInItem(ownerid);
}
void tv_PrintAllProcedures(object sender, vlnTreeEventArgs args)
@ -433,6 +518,7 @@ namespace VEPROMS
if (dvi == null) return;
tc.SaveCurrentEditItem();
DlgPrintProcedure prnDlg = new DlgPrintProcedure(dvi);
prnDlg.MySessionInfo = MySessionInfo;
prnDlg.SelectedSlave = args.UnitIndex;
prnDlg.ShowDialog(this); // RHM 20120925 - Center dialog over PROMS window
}
@ -443,6 +529,7 @@ namespace VEPROMS
if (pi == null) return;
tc.SaveCurrentEditItem(pi);
DlgPrintProcedure prnDlg = new DlgPrintProcedure(pi);
prnDlg.MySessionInfo = MySessionInfo;
prnDlg.SelectedSlave = args.UnitIndex;
// prnDlg.Show(this); // RHM 20120925 - Center dialog over PROMS window
prnDlg.ShowDialog(this); // RHM 20120925 - Center dialog over PROMS window
@ -471,8 +558,17 @@ namespace VEPROMS
VETreeNode vNode = (VETreeNode)args.Node;
IVEDrillDownReadOnly veObj = vNode.VEObject;
ProcedureInfo myProc = veObj as ProcedureInfo;
string message = string.Empty;
if (!MySessionInfo.CanCheckOutItem(myProc.ItemID, CheckOutType.Procedure, ref message))
{
MessageBox.Show(this, message, "Item Already Checked Out", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return DialogResult.None;
}
int ownerID = MySessionInfo.CheckOutItem(myProc.ItemID, 0);
frmPSI fpsi = new frmPSI(myProc);
return fpsi.ShowDialog(this); ;
DialogResult dr = fpsi.ShowDialog(this);
MySessionInfo.CheckInItem(ownerID);
return dr;
}
/// <summary>
/// Activate tmrTreeView so that the newly created Step recieves focus
@ -503,6 +599,7 @@ namespace VEPROMS
DlgPrintProcedure prnDlg = new DlgPrintProcedure(pi);
//added by jcb 20130718 to support create pdf button when multiunit and user selects a unit
prnDlg.SelectedSlave = pi.ProcedureConfig.SelectedSlave == 0 ? -1 : pi.ProcedureConfig.SelectedSlave;
prnDlg.MySessionInfo = MySessionInfo;
//end added by jcb 20130718
prnDlg.ShowDialog(this); // RHM 20120925 - Center dialog over PROMS window
//added by jcb 20130718 to support create pdf button when multiunit and user selects a unit
@ -559,6 +656,10 @@ namespace VEPROMS
}
private void frmVEPROMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (MyActivityTimer != null)
{
MyActivityTimer.Dispose();
MySessionInfo.EndSession();
// Save the location and size of the VE-PROMS appication for this user
if (this.WindowState == FormWindowState.Normal)
{
@ -568,6 +669,7 @@ namespace VEPROMS
Settings.Default.WindowState = this.WindowState;
Settings.Default.QATItems = ribbonControl1.QatLayout;
SaveMRU();
}
//Settings.Default.Save();
Volian.Base.Library.DebugPagination.Close();
Volian.Base.Library.DebugText.Close();
@ -591,8 +693,64 @@ namespace VEPROMS
return ((FolderConfig)jj_vetn.VEObject.MyConfig).Title; // get the panel heading
}
private SessionInfo MySessionInfo;
private System.Threading.Timer MyActivityTimer;
private DevComponents.DotNetBar.ButtonItem btnManageSecurity;
private TabItemsToClose _MyCloseTabList = new TabItemsToClose();
public TabItemsToClose MyCloseTabList
{
get { return _MyCloseTabList; }
}
private void PingSession(Object obj)
{
List<int> myList = MySessionInfo.PingSession();
foreach (DisplayTabItem dti in tc.MyBar.Items)
{
if (!myList.Contains(dti.OwnerID))
MyCloseTabList.PushDTI(dti);
}
}
public Timer tmrCloseTabItems;
private void frmVEPROMS_Load(object sender, EventArgs e)
{
InitializeSecurity();
UpdateUser();
btnManageSecurity = new ButtonItem("btnManageSecurity", "Manage Security");
btnAdmin.SubItems.Add(btnManageSecurity);
btnManageSecurity.Click += new EventHandler(btnManageSecurity_Click);
UserInfo ui = null;
try
{
ui = UserInfo.GetByUserID(VlnSettings.UserID);
}
catch
{
MessageBox.Show("This database is not compatible with this version of PROMS. The PROMS program will terminate. Please contact Volian to assist in resolution.");
Application.Exit();
}
if (ui == null)
{
User u = User.MakeUser(VlnSettings.UserID, "", "", "", "", "", "", "", "", "", "", DateTime.Now, VlnSettings.UserID);
Group g = Group.Get(securityRole);
Membership.MakeMembership(u, g, null, "");
ui = UserInfo.Get(u.UID);
}
ctrlAnnotationDetails.MyUserInfo = ui;
bool isVisible = ui.IsAdministrator();
btnManageSecurity.Visible = isVisible;
btnUpdateFormats.Visible = isVisible;
tmrCloseTabItems = new Timer();
tmrCloseTabItems.Interval = 100;
tmrCloseTabItems.Tick += new EventHandler(tmrCloseTabItems_Tick);
tmrCloseTabItems.Enabled = true;
MySessionInfo = SessionInfo.BeginSession(Environment.MachineName, System.Diagnostics.Process.GetCurrentProcess().Id);
tc.MySessionInfo = MySessionInfo;
tv.MySessionInfo = MySessionInfo;
System.Threading.AutoResetEvent autoEvent = new System.Threading.AutoResetEvent(false);
//System.Threading.TimerCallback timerDelegate = new System.Threading.TimerCallback(MySessionInfo.PingSession);
System.Threading.TimerCallback timerDelegate = new System.Threading.TimerCallback(this.PingSession);
MyActivityTimer = new System.Threading.Timer(timerDelegate, autoEvent, 10000, 10000);
//string debugMode = ConfigurationManager.AppSettings["Debug"];
//VlnSettings.DebugMode = bool.Parse(debugMode); // set debug for the Volian.Controls.Library
// get the saved location and size of the VE-PROMS appication for this user
@ -651,12 +809,111 @@ namespace VEPROMS
}
else
tmrAutomatic.Enabled = true;
// Shutoff UpdateFormats for Production Mode
if (Volian.Base.Library.VlnSettings.ProductionMode)
btnAdmin.Visible = false;
//// Shutoff UpdateFormats for Production Mode
//if (Volian.Base.Library.VlnSettings.ProductionMode)
// btnAdmin.Visible = false;
StepTabRibbon.PasteNoReturnsSetting = Properties.Settings.Default.PasteNoReturns;
StepTabRibbon.PastePlainTextSetting = Properties.Settings.Default.PastePlainText;
}
void tmrCloseTabItems_Tick(object sender, EventArgs e)
{
while(MyCloseTabList.CountDTI > 0)
{
DisplayTabItem dti = MyCloseTabList.PopDTI();
if (dti.MyDSOTabPanel != null)
dti.MyDSOTabPanel.OverrideClose = true;
tc.CloseTabItem(dti);
}
}
private void InitializeSecurity()
{
Folder f = Folder.Get(1);
GroupInfo gi = GroupInfo.Get(1);
if (f.FolderConfig.Security_Group == 0)
{
f.FolderConfig.Security_Group = gi.GID;
f.Save();
}
securityRole = f.FolderConfig.Security_Group;
}
private string proxyUser;
private void UpdateUser()
{
string[] parameters = System.Environment.CommandLine.Split(" ".ToCharArray());
foreach (string parameter in parameters)
{
if (parameter.ToUpper().StartsWith("/U=")) //this is for testing purposes on same machine to emulate different users
{
VlnSettings.UserID = parameter.Substring(3);
}
else if (parameter.StartsWith("/VeauLeeAnn")) //this is used by volian personnel to act as an existing user
{
//pop up user list to select from
ContextMenuStrip cms = BuildUserMenu();
while (proxyUser == null)
{
cms.Show(new System.Drawing.Point((System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width - cms.Width) / 2, (System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height - cms.Height) / 2));
System.Windows.Forms.Application.DoEvents();
}
VlnSettings.UserID = proxyUser;
}
else if (parameter.StartsWith("/V3Pr0m5=")) //this is a backdoor to create another administrator
{
VlnSettings.UserID = parameter.Substring(9);
User u = User.MakeUser(VlnSettings.UserID, "", "", "", "", "", "", "", "", "", "", DateTime.Now, VlnSettings.UserID);
Group g = Group.GetByGroupName("Administrators");
Membership.MakeMembership(u, g, null, "");
}
}
lblUser.Text = VlnSettings.UserID;
}
private ContextMenuStrip BuildUserMenu()
{
System.Windows.Forms.ContextMenuStrip cms = new System.Windows.Forms.ContextMenuStrip();
cms.Items.Add("Choose User");
System.Windows.Forms.ToolStripMenuItem tsmi = cms.Items[0] as System.Windows.Forms.ToolStripMenuItem;
tsmi.BackColor = System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.ActiveCaption);// System.Drawing.Color.Pink;
tsmi.ForeColor = System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.ActiveCaptionText);
tsmi.Font = new System.Drawing.Font(tsmi.Font, System.Drawing.FontStyle.Bold);
UserInfoList uil = UserInfoList.Get();
foreach (UserInfo ui in uil)
{
if (ui.UserMembershipCount > 0)
{
foreach (MembershipInfo mi in ui.UserMemberships)
{
if (mi.EndDate == string.Empty)
{
string txt = string.Format("{0} - {1}", ui.UserID, mi.MyGroup.GroupName);
ToolStripItem tsi = cms.Items.Add(txt, null, new EventHandler(User_Click));
tsi.Tag = ui;
break;
}
}
}
}
return cms;
}
private void User_Click(object sender, EventArgs e)
{
ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
if (tsmi != null)
{
UserInfo ui = tsmi.Tag as UserInfo;
proxyUser = ui.UserID;
}
}
void btnManageSecurity_Click(object sender, EventArgs e)
{
dlgManageSecurity dlg = new dlgManageSecurity();
dlg.ShowDialog(this);
}
void tc_StatusChanged(object sender, DisplayTabControlStatusEventArgs args)
{
switch (args.Type)
@ -1032,8 +1289,17 @@ namespace VEPROMS
}
else if (args.ProcedureConfig != null)
{
string message = string.Empty;
if (!MySessionInfo.CanCheckOutItem(args.ProcedureConfig.MyProcedure.ItemID, CheckOutType.Procedure, ref message))
{
MessageBox.Show(this, message, "Procedure Already Checked Out", MessageBoxButtons.OK, MessageBoxIcon.Warning);
this.Cursor = Cursors.Default;
return DialogResult.None;
}
int ownerID = MySessionInfo.CheckOutItem(args.ProcedureConfig.MyProcedure.ItemID, 0);
frmProcedureProperties frmproc = new frmProcedureProperties(args.ProcedureConfig);
dr = frmproc.ShowDialog();
MySessionInfo.CheckInItem(ownerID);
}
else if (args.SectionConfig != null)
{
@ -1534,6 +1800,8 @@ namespace VEPROMS
}
SetCaption(tv.SelectedNode as VETreeNode);
displayApplicability.MyDisplayTabItem = tc.SelectedDisplayTabItem;
Console.WriteLine("tc_SelectedDisplayTabItemChanged");
lblUser.Text = tc.SelectedDisplayTabItem.MyUserRole;
}
private void tc_StepPanelModeChange(object sender, StepRTBModeChangeEventArgs args)
{
@ -2088,6 +2356,7 @@ namespace VEPROMS
//}
//string pnum = DisplayText.StaticStripRtfCommands(this._CurrentItem.MyProcedure.ProcedureConfig.Number).Replace("\\u8209?", "-");
DlgPrintProcedure prnDlg = new DlgPrintProcedure(this._CurrentItem.MyProcedure);//dvi.DocVersionConfig,pnum);
prnDlg.MySessionInfo = MySessionInfo;
prnDlg.ShowDialog(this); // RHM 20120925 - Center dialog over PROMS window
}
@ -2190,4 +2459,34 @@ namespace VEPROMS
}
}
}
#region Lock stuff
public class TabItemsToClose : Stack<DisplayTabItem>
{
public void PushDTI(DisplayTabItem dti)
{
lock (this)
{
if(!this.Contains(dti))
this.Push(dti);
}
}
public DisplayTabItem PopDTI()
{
lock (this)
{
return this.Pop();
}
}
public int CountDTI
{
get
{
lock (this)
{
return this.Count;
}
}
}
}
#endregion
}