/// <summary> /// The DataList supports having a blank new row template like MS-Access does. This row isn't bound /// until it is actually focused. See RowTemplate_Enter for details. /// </summary> internal void AddNewRowTemplate() { int width, top = 0; if(!changePolicy.AllowAdditions || rowTemplate == null || listManager == null) return; if(pnlRows.Controls.Count != 0) top = pnlRows.Controls[pnlRows.Controls.Count - 1].Top + pnlRows.Controls[pnlRows.Controls.Count - 1].Height; ConstructorInfo ctor = rowTemplate.GetConstructor(Type.EmptyTypes); TemplateControl tc = (TemplateControl)ctor.Invoke(null); // This is going to get used right away so initialize it now tc.IsNewRowInternal = true; tc.TemplateParentInternal = this; tc.InitializeTemplate(); tc.HasBeenInitialized = true; tc.Enter += RowTemplate_Enter; tc.Location = new Point(pnlRows.AutoScrollPosition.X, top); if(rowHeight == -1) { rowHeight = tc.Height; if(showSep) rowHeight += sepHeight; this.CalculateGlyphPoints(); } pnlRows.Controls.Add(tc); if(showSep) { if(tc.Width < pnlRows.Width) width = pnlRows.Width; else width = tc.Width; width += (pnlRows.AutoScrollPosition.X * -1); Separator sep = new Separator(sepColor, sepHeight, width, pnlRows.AutoScrollPosition.X, top + tc.Height); pnlRows.Controls.Add(sep); } tc.Leave += RowTemplate_Leave; btnNext.Enabled = true; btnAdd.Enabled = changePolicy.AllowAdditions; btnDelete.Enabled = (changePolicy.AllowDeletes && listManager.Count > 0); if(rowHeadersVisible) { this.Invalidate(new Rectangle(0, 0, rowHeaderWidth, this.Height), false); this.Update(); } }
/// <summary> /// This is called when a row is added to the data source externally /// </summary> /// <remarks>If additions are allowed, the new row template is bound to the new row and the new row /// template is recreated. If additions are not allowed, it creates a new template and bind it to the /// new row.</remarks> private void AddRowInternal() { TemplateControl tc; int idx, width, top = 0; pnlRows.SuspendLayout(); if(changePolicy.AllowAdditions) { idx = pnlRows.Controls.Count - 1; if(showSep) idx--; tc = (TemplateControl)pnlRows.Controls[idx]; // If bound, get rid of the temporary new row if(tc.IsDataBound) { if(!isUndoing) this.CancelChanges(); tc.WirePropChangedEvents(false); } // Set the control's row source and add a new "new row" template tc.IsNewRowInternal = false; tc.SetRowSourceInternal(listManager.List[listManager.Count - 1]); AddNewRowTemplate(); } else { idx = listManager.Count - 1; if(pnlRows.Controls.Count != 0) top = pnlRows.Controls[pnlRows.Controls.Count - 1].Top + pnlRows.Controls[pnlRows.Controls.Count - 1].Height - 1; ConstructorInfo ctor = rowTemplate.GetConstructor(Type.EmptyTypes); tc = (TemplateControl)ctor.Invoke(null); tc.TemplateParentInternal = this; tc.InitializeTemplate(); tc.HasBeenInitialized = true; tc.Enter += RowTemplate_Enter; tc.Location = new Point(pnlRows.AutoScrollPosition.X, top); pnlRows.Controls.Add(tc); if(rowHeight == -1) { rowHeight = tc.Height; if(showSep) rowHeight += sepHeight; this.CalculateGlyphPoints(); } if(showSep) { if(tc.Width < pnlRows.Width) width = pnlRows.Width; else width = tc.Width; width += (pnlRows.AutoScrollPosition.X * -1); Separator sep = new Separator(sepColor, sepHeight, width, pnlRows.AutoScrollPosition.X, top + tc.Height); pnlRows.Controls.Add(sep); } // Set the control's row source tc.SetRowSourceInternal(listManager.List[idx]); } lblRowCount.Text = LR.GetString("DLNavRowCount", listManager.Count); btnDelete.Enabled = (changePolicy.AllowDeletes && listManager.Count > 0); pnlRows.ResumeLayout(); // Force the focus to the new row if necessary currentRow = -1; DataSource_PositionChanged(this, EventArgs.Empty); OnAddedRow(new DataListEventArgs(currentRow, tc)); }
/// <summary> /// This is used to create the rows and bind each one to a row in the data source /// </summary> private void BindData() { TemplateControl ctl; Separator sep; int idx, top = 0, sepTop = 0, sepWidth = pnlRows.Width; bool bindFailed = false; if(inBindData) return; Cursor oldCursor = this.Cursor; if(oldCursor != Cursors.WaitCursor) this.Cursor = Cursors.WaitCursor; inBindData = isBinding = true; try { pnlRows.Visible = false; pnlRows.SuspendLayout(); pnlRows.AutoScrollPosition = new Point(0, 0); RemoveRows(); this.Select(-1, -1, -1); // If we don't have both, there's nothing to do if(rowTemplate == null || listManager == null) return; // Bind the header and footer controls if(header != null) { header.SetRowSourceInternal(dataSource); header.Bind(); header.HasBeenBound = true; OnHeaderDataBound(new DataListEventArgs(-1, header)); } if(footer != null) { footer.SetRowSourceInternal(dataSource); footer.Bind(); footer.HasBeenBound = true; OnFooterDataBound(new DataListEventArgs(-1, footer)); } // Create the row template items ConstructorInfo ctor = rowTemplate.GetConstructor(Type.EmptyTypes); rowHeight = -1; for(idx = 0; idx < listManager.Count; idx++, top += rowHeight, sepTop += rowHeight) { ctl = (TemplateControl)ctor.Invoke(null); ctl.Enter += RowTemplate_Enter; ctl.TemplateParentInternal = this; if(rowHeight == -1) { ctl.InitializeTemplate(); ctl.HasBeenInitialized = true; sepTop = rowHeight = ctl.Height; if(showSep) rowHeight += sepHeight; if(ctl.Width > sepWidth) sepWidth = ctl.Width; } ctl.Location = new Point(0, top); pnlRows.Controls.Add(ctl); if(showSep) { sep = new Separator(sepColor, sepHeight, sepWidth, 0, sepTop); pnlRows.Controls.Add(sep); } // Set the control's row source ctl.SetRowSourceInternal(listManager.List[idx]); } } catch(Exception ex) { bindFailed = true; // Something in the data binding hierarchy tends to eat exceptions that occur during binding and // you never see them (i.e. bad field names in a binding). This logs them to the debugger if one // is attached. if(System.Diagnostics.Debugger.IsAttached) { // Can't use System.Diagnostics.Debug as it gets excluded from the release build. This does // the same thing though but is compiled into the release build. using(var dtl = new System.Diagnostics.DefaultTraceListener()) { dtl.WriteLine(LR.GetString("ExBindData1", this.Name, ex.Message)); } } } finally { this.CalculateGlyphPoints(); if(!bindFailed) if(!changePolicy.AllowAdditions) { this.Invalidate(new Rectangle(0, 0, rowHeaderWidth, this.Height), false); this.Update(); } else this.AddNewRowTemplate(); lblRowCount.Text = LR.GetString("DLNavRowCount", (listManager != null) ? listManager.Count : 0); if(oldCursor != Cursors.WaitCursor) this.Cursor = oldCursor; inBindData = false; // Problems with the bindings will manifest themselves here (i.e. bad field names, etc). try { pnlRows.ResumeLayout(); pnlRows.Visible = true; this.Invalidate(); this.Update(); } catch(Exception ex) { // As above. Log the exception so that we know it occurred. if(System.Diagnostics.Debugger.IsAttached) using(var dtl = new System.Diagnostics.DefaultTraceListener()) { dtl.WriteLine(LR.GetString("ExBindData2", this.Name, ex.Message)); } } finally { isBinding = false; } // Force the focus to the proper row currentRow = (dataSource == null) ? 0 : -1; DataSource_PositionChanged(this, EventArgs.Empty); if(listManager != null && listManager.Count == 0) OnNoRows(EventArgs.Empty); } }