using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using System.ComponentModel; using System.ComponentModel.Design; using System.Windows.Forms; using System.Reflection; namespace Volian.Base.Library { // The PropGridCollEditor expands the functionality of the CollectionEditor (the collection editor comes up when in a // property grid, and the current selected item is a collection, and the user selects the '...'. public class PropGridCollEditor : CollectionEditor { // Define a static event to expose the inner PropertyGrid's // PropertyValueChanged event args... public delegate void MyPropertyValueChangedEventHandler(object sender, PropertyValueChangedEventArgs e); public static event MyPropertyValueChangedEventHandler MyPropertyValueChanged; private bool AllowAddDel = false; // flags whether the Add/Delete buttons should be displayed: // Inherit the default constructor from the standard // Collection Editor... private Type _origType; public PropGridCollEditor(Type type) : base(type) { AllowAddDel = false; _origType = type; if (type.Name == "ReplaceStrData") AllowAddDel = true; // Defaults to not having the 'Add' & 'Remove' buttons. } protected override Type CreateCollectionItemType() { return base.CreateCollectionItemType(); } private Button resetbtn = null; // Override this method in order to access the containing user controls // from the default Collection Editor form or to add new ones... protected override CollectionForm CreateCollectionForm() { // Getting the default layout of the Collection Editor... CollectionForm collectionForm = base.CreateCollectionForm(); Form frmCollectionEditorForm = collectionForm as Form; // The Add/Remove buttons are made invisible: if (!AllowAddDel) HideAddRemoveButtons(0, frmCollectionEditorForm); Button okbtn = FindOkButton(frmCollectionEditorForm); if (!AllowAddDel) { // add a reset button and put next to ok button: resetbtn = new Button(); resetbtn.Text = "Reset"; resetbtn.Location = new System.Drawing.Point(okbtn.Location.X - 20, okbtn.Location.Y); resetbtn.Width = 250; resetbtn.Visible = true; resetbtn.Enabled = false; // only enabled on data change resetbtn.Click += resetbtn_Click; okbtn.Parent.Controls.Add(resetbtn); } SetMembersLabel(collectionForm); TableLayoutPanel tlpLayout = frmCollectionEditorForm.Controls[0] as TableLayoutPanel; if (tlpLayout != null) { // Get a reference to the inner PropertyGrid and hook an event handler to it. if (tlpLayout.Controls[5] is PropertyGrid) { propertyGrid = tlpLayout.Controls[5] as PropertyGrid; propertyGrid.PropertyValueChanged += new PropertyValueChangedEventHandler(propertyGrid_PropertyValueChanged); propertyGrid.SelectedGridItemChanged += PG_SelectedGridItemChanged; } } return collectionForm; } // when the reset button is clicked the data will be reset to the data from the original format file. Note that if // data is added to the UCF that is part of a collection, code will need to be added here to reset the value. void resetbtn_Click(object sender, EventArgs e) { resetbtn.Text = "Reset"; resetbtn.Enabled = false; if (SelectedGridField.Contains("Left Margin")) ResetValue(propertyGrid.SelectedGridItem.Parent.Value, "LeftMargin"); else if (SelectedGridField.Contains("Page Length")) ResetValue(propertyGrid.SelectedGridItem.Parent.Value, "PageLength"); else if (SelectedGridField.Contains("WindowsFont")) ResetValue(propertyGrid.SelectedGridItem.Parent.Value, "WindowsFont"); // B2019-100: for headers, use Parent's parent and also for both header & checkoffs the field name is 'Active' (not 'Inactive') else if (SelectedGridField.Contains("Active CheckOff Header")) ResetValue(propertyGrid.SelectedGridItem.Parent.Parent.Value, "Active"); else if (SelectedGridField.Contains("Active CheckOff")) ResetValue(propertyGrid.SelectedGridItem.Parent.Parent.Value, "Active"); } private void ShowReflection(Object data) { if (data == null) return; //Object data = new A(); FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); String str = ""; foreach (FieldInfo f in fields) { str += f.Name + " = " + f.GetValue(data) + "\r\n"; } Console.WriteLine("reflection = {0}", str); } PropertyGrid propertyGrid = null; private string SelectedGridField = ""; // The following method is used to enable and set text on the 'Reset' button. When a grid item is selected, if it has // UCF data, then put the original value as part of the button text & enable it: void PG_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e) { if (resetbtn == null) return; if (propertyGrid != null) Console.WriteLine(LabelPath(propertyGrid.SelectedGridItem)); // PG.SelectedGridItem.Label + " : " + PG.SelectedGridItem.Value; // see if data has changed, and if so, enable the Reset button. bool enabled = false; resetbtn.Text = "Reset"; SelectedGridField = LabelPath(propertyGrid.SelectedGridItem); if (SelectedGridField.Contains("WindowsFont")) { string origForButton = OrigValue(propertyGrid.SelectedGridItem.Parent.Value, "WindowsFont"); if (origForButton != null) { resetbtn.Text = "Reset to " + origForButton; enabled = true; } } else if (SelectedGridField.Contains("Left Margin")) { string origForButton = OrigValue(propertyGrid.SelectedGridItem.Parent.Value, "LeftMargin"); if (origForButton != null) { resetbtn.Text = "Reset to " + origForButton; enabled = true; } } else if (SelectedGridField.Contains("Page Length")) { string origForButton = OrigValue(propertyGrid.SelectedGridItem.Parent.Value, "PageLength"); if (origForButton != null) { resetbtn.Text = "Reset to " + origForButton; enabled = true; } } else if (SelectedGridField.Contains("Active CheckOff Header")) { string origForButton = OrigValue(propertyGrid.SelectedGridItem.Parent.Parent.Value, "Active"); if (origForButton != null) { resetbtn.Text = "Reset to " + origForButton; enabled = true; } } else if (SelectedGridField.Contains("Active CheckOff")) { string origForButton = OrigValue(propertyGrid.SelectedGridItem.Parent.Parent.Value, "Active"); if (origForButton != null) { resetbtn.Text = "Reset to " + origForButton; enabled = true; } } else enabled = false; resetbtn.Enabled = enabled; } // This code,using data reflection, will determine the if there is UCF (changed) data, and if so // will return its value as a string for concatenation of Reset button text. private string OrigValue(object data, string fieldName) { FieldInfo fldVal = null; FieldInfo fldOrig = null; if (data == null) return null; FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); // Go through the fields in the data structure, looking to match that passed in. Also look for the original // field to compare the 2 to see if a change was made, i.e. UCF data exists. foreach (FieldInfo f in fields) { if (f.Name == "_" + fieldName) fldVal = f; if (f.Name == "_Orig" + fieldName) fldOrig = f; } if (fldVal != null && fldOrig != null) { try { // see if values are different: string orig = fldOrig.GetValue(data).ToString(); string newv = fldVal.GetValue(data).ToString(); string retval = fldOrig.GetValue(data).ToString(); if (retval.StartsWith("[Font:")) { retval = retval.Replace("[Font: Name=", "").Replace(", Size=", ","); } if (orig != newv) return retval; else return null; } catch (Exception ex) { return null; } } return null; } // The following Resets the format variable's value from the original format (as stored in the 'OrigXXX' field in FormatConfig private void ResetValue(object data, string fieldName) { FieldInfo fldVal = null; FieldInfo fldOrig = null; if (data == null) return; FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (FieldInfo f in fields) { if (f.Name == "_" + fieldName) fldVal = f; if (f.Name == "_Orig" + fieldName) fldOrig = f; } if (fldVal != null && fldOrig != null) { fldVal.SetValue(data, fldOrig.GetValue(data)); propertyGrid.Refresh(); } } // Remove this on release, and any uses of it. private string LabelPath(GridItem gi) { return (gi.Parent == null ? "" : LabelPath(gi.Parent) + ":" + gi.Label); } // set the 'members' label to better reflect what is displayed: private bool SetMembersLabel(Control myControl) { if (myControl is Label && myControl.Text.ToUpper().Contains("MEMBER")) { string dt = myControl.TopLevelControl.Text; if (dt.ToUpper().Contains("DOCSTYL")) myControl.Text = "Section Types"; else if (dt.ToUpper().Contains("REPLACE")) myControl.Text = "Replace Words"; else if (dt.ToUpper().Contains("CHECKOFFHEADER")) myControl.Text = "CheckOff Headers"; else if (dt.ToUpper().Contains("CHECKOFF")) myControl.Text = "CheckOffs"; else if (dt.ToUpper().Contains("STEP")) myControl.Text = "Steps"; return true; } if (myControl.Controls != null && myControl.Controls.Count > 0) { foreach (Control con in myControl.Controls) { bool found = SetMembersLabel(con); if (found == true) return true; } } return false; } // This code looks for the 'OK' button, so that the 'Reset' button can be placed by it. private Button FindOkButton(Control myControl) { if (myControl is Button && myControl.Text == "OK") { return myControl as Button; } if (myControl.Controls != null && myControl.Controls.Count > 0) { foreach (Control con in myControl.Controls) { Button found = FindOkButton(con); if (found != null) return found; } } return null; } // Find the 'Add' & 'Remove' buttons based on their text, and then make invisible. private void HideAddRemoveButtons(int level, Control myControl) { if (myControl.Text == "&Add" || myControl.Text == "&Remove") { myControl.Visible = false; return; } if (myControl.Controls != null && myControl.Controls.Count > 0) { foreach (Control con in myControl.Controls) HideAddRemoveButtons(level + 1, con); } } void propertyGrid_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e) { // Fire our customized collection event... if (PropGridCollEditor.MyPropertyValueChanged != null) { PropGridCollEditor.MyPropertyValueChanged(this, e); } } } }