/// <summary> /// Gets the new value of the property which will be passed /// into the model. /// </summary> /// <param name="cell">Cell which has been changed.</param> private object GetNewPropertyValue(GridCellChangedArgs cell) { VariableProperty property = properties[cell.ColIndex]; try { // Parse the new string to an object of the appropriate type. object value = ReflectionUtilities.StringToObject(property.DataType.GetElementType(), cell.NewValue, CultureInfo.CurrentCulture); // Clone the array stored in the model. This is necessary // because we need to modify an element of property.Value, // which is a shallow copy of the actual property value. Array array = Clone(property.Value as Array, property.DataType.GetElementType()); // Resize the array if necessary. if (cell.RowIndex >= array.Length) { Resize(ref array, cell.RowIndex + 1); } // Change the appropriate element in the array. array.SetValue(value, cell.RowIndex); if (!MathUtilities.ValuesInArray(array)) { return(null); } return(array); } catch (FormatException err) { throw new Exception($"Value '{cell.NewValue}' is invalid for property '{property.Name}' - {err.Message}."); } }
/// <summary> /// Gets the new value of the cell from a string containing the /// cell's new contents. /// </summary> /// <param name="cell">Cell which has been changed.</param> protected virtual object GetNewPropertyValue(IVariable property, GridCellChangedArgs cell) { if (typeof(IPlant).IsAssignableFrom(property.DataType)) { return(Apsim.Find(property.Object as IModel, cell.NewValue)); } if (property.Display != null && property.Display.Type == DisplayType.Model) { return(Apsim.Get(property.Object as IModel, cell.NewValue)); } try { if (property.DataType.IsEnum) { return(VariableProperty.ParseEnum(property.DataType, cell.NewValue)); } else { return(ReflectionUtilities.StringToObject(property.DataType, cell.NewValue, CultureInfo.CurrentCulture)); } } catch (FormatException err) { throw new Exception($"Value '{cell.NewValue}' is invalid for property '{property.Name}' - {err.Message}."); } }
/// <summary> /// Called when user clicks on a file name. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> private void OnFileBrowseClick(object sender, GridCellChangedArgs e) { // todo - add file extension paramter to display attribute? IFileDialog fileChooser = new FileDialog() { Action = FileDialog.FileActionType.Open, Prompt = "Select file path", InitialDirectory = e.OldValue }; if (properties[e.RowIndex].Display.Type == DisplayType.DirectoryName) { fileChooser.Action = FileDialog.FileActionType.SelectFolder; fileChooser.Prompt = "Select a folder"; } IGridCell cell = grid.GetCell(e.ColIndex, e.RowIndex); string fileName = properties[e.RowIndex].Display.Type == DisplayType.FileNames ? string.Join(", ", fileChooser.GetFiles()) : fileChooser.GetFile(); if (!string.IsNullOrWhiteSpace(fileName) && fileName != e.OldValue) { e.NewValue = fileName; OnCellsChanged(sender, new GridCellsChangedArgs(e)); PopulateGrid(model); } }
private void CheckRowCount(GridCellChangedArgs change) { while (change.RowIndex >= table.Rows.Count) { table.Rows.Add(table.NewRow()); } }
/// <summary> /// Called when user clicks on a file name. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> private void OnFileBrowseClick(object sender, GridCellChangedArgs e) { IFileDialog fileChooser = new FileDialog() { Action = FileDialog.FileActionType.Open, Prompt = "Select file path", InitialDirectory = e.OldValue }; string fileName = fileChooser.GetFile(); if (!string.IsNullOrWhiteSpace(fileName) && fileName != e.OldValue) { e.NewValue = fileName; OnCellValueChanged(sender, new GridCellsChangedArgs(e)); PopulateGrid(model); } }
/// <summary> /// Checks the lengths of all array properties. Resizes any /// array which is too short and fills new elements with NaN. /// This is needed when the user enters a new row of data. /// </summary> /// <param name="cell"></param> private List <ChangeProperty.Property> CheckArrayLengths(GridCellChangedArgs cell) { List <ChangeProperty.Property> changes = new List <ChangeProperty.Property>(); foreach (VariableProperty property in properties) { // If the property is not an array or if it's readonly, // ignore it. if (!property.DataType.IsArray || property.IsReadOnly) { continue; } // If the property is the property which has just been // changed by the user, ignore it - we don't want to // modify it twice. if (property == properties[cell.ColIndex]) { continue; } // If the property value is null, ignore it. Array arr = property.Value as Array; if (arr == null) { continue; } // If array is already long enough, ignore it. int n = arr?.Length ?? 0; if (n > cell.RowIndex) { continue; } // Array is too short - need to resize it. However, // this array is a reference to the value of the // property stored in the model, so we need to clone it // before making any changes, otherwise the changes // won't be undoable. Type elementType = property.DataType.GetElementType(); arr = Clone(arr, elementType); Resize(ref arr, cell.RowIndex + 1); // Unless this property is thickness, fill the new // values (if any) with NaN as per conversation with // Dean (blame him!). if ((elementType == typeof(double) || elementType == typeof(float)) && property.Name != "Thickness") { object nan = null; if (elementType == typeof(double)) { nan = double.NaN; } else if (elementType == typeof(float)) { nan = float.NaN; } for (int i = n; i < arr.Length; i++) { arr.SetValue(nan, i); } } changes.Add(new ChangeProperty.Property(property.Object, property.Name, arr)); } return(changes); }