/// <summary> /// Create an XAML element describing the field. /// </summary> /// <param name="fieldDefinition">The CLR description of the field.</param> public FieldDefinitionElement(ReportField fieldDefinition) : base(DynamicReport.namespacePresentation + "FieldDefinition") { // Initialize the object. Add(new XAttribute("ColumnId", fieldDefinition.ColumnId)); Add(new XAttribute("Description", fieldDefinition.Description)); Add(new XAttribute("Width", fieldDefinition.Width)); }
/// <summary> /// Create an XAML element describing the column. /// </summary> /// <param name="reportColumn">The CLR description of the column.</param> public ColumnDefinitionElement(ReportColumn reportColumn, ReportField fieldDefinition) : base(DynamicReport.namespacePresentation + "ColumnDefinition") { // The 'Width' attribute defaults to the width specified by the FieldDefinition. Add(new XAttribute("ColumnId", reportColumn.ColumnId)); if (reportColumn.Width != fieldDefinition.Width) { Add(new XAttribute("Width", reportColumn.Width)); } }
/// <summary> /// Handles a change to the Width property. /// </summary> /// <param name="dependencyObject">The object posessing the property that has changed.</param> /// <param name="dependencyPropertyChangedEventArgs">Information about the property change.</param> private static void OnWidthChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { if (dependencyObject is ReportField) { ReportField fieldDefinition = dependencyObject as ReportField; if (fieldDefinition.PropertyChanged != null) { fieldDefinition.PropertyChanged(fieldDefinition, new PropertyChangedEventArgs("Width")); } } }
/// <summary> /// Removes the element at the specified index of the MarkThree.Windows.Controls.ReportColumnCollection. /// </summary> /// <param name="index">The location where the element will be removed.</param> public void RemoveAt(int index) { // The ColumnDefinition events need to be unhooked from this collection when it is removed. ReportField fieldDefinition = this.list[index]; fieldDefinition.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(fieldDefinition_PropertyChanged); // The list and dictionary are updated at the same time to remove the element. this.list.RemoveAt(index); this.fieldDefinitionMap.Remove(fieldDefinition.ColumnId); // This will broadcast a notification that the collection has been modified. This event is typically used to // apply the changes to a persistent version of the user preferences, such as an XAML document. RaiseEvent(new CollectionChangedEventArgs(ReportFieldCollection.CollectionChangedEvent, UndoAction.Create, CollectionChangedAction.Remove, fieldDefinition)); }
/// <summary> /// Determins whether the MarkThree.Windows.Controls.ReportColumnCollection contains the specified key. /// </summary> /// <param name="value">A key to a ColumnDefinition item.</param> /// <returns>True if the collection contains an item with the specified key, false otherwise.</returns> public bool Contains(object value) { // The hashtable is used to indicate if the given key exists in the collection. if (value is ReportField) { ReportField fieldDefinition = value as ReportField; return(this.fieldDefinitionMap.ContainsKey(fieldDefinition.ColumnId)); } // The value can also be the key used to identify the field. if (value is string) { string columnId = value as string; return(this.fieldDefinitionMap.ContainsKey(columnId)); } // No other object type can be found in this collection. return(false); }
/// <summary> /// Gets or sets the ColumnDefinition at the specified index. /// </summary> /// <param name="index">The index of the element.</param> /// <returns>The object at the given index.</returns> public object this[int index] { get { return(this.list[index]); } set { // The list and the dictionary must be udpated at the same time. ReportField fieldDefinition = this.list[index]; this.list[index] = value as ReportField; this.fieldDefinitionMap[fieldDefinition.ColumnId] = value as ReportField; // This will broadcast a notification that the collection has been modified. This event is typically used to // apply the changes to a persistent version of the user preferences, such as an XAML document. RaiseEvent(new CollectionChangedEventArgs(ReportFieldCollection.CollectionChangedEvent, UndoAction.Create, CollectionChangedAction.Replace, value, fieldDefinition)); } }
/// <summary> /// Removes the first occurence of the specified element from the MarkThree.Windows.Controls.ReportColumnCollection. /// </summary> /// <param name="value">The element to be removed.</param> public void Remove(object value) { // The XAML parser only recognizes the generic IList interfaces, so incoming values need to be qualified to be added to // this collection. if (value is ReportField) { // The ColumnDefinition events need to be unhooked from this collection when it is removed. ReportField fieldDefinition = value as ReportField; fieldDefinition.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(fieldDefinition_PropertyChanged); // The list and dictionary are updated at the same time to remove the element. this.list.Remove(fieldDefinition); this.fieldDefinitionMap.Remove(fieldDefinition.ColumnId); // This will broadcast a notification that the collection has been modified. This event is typically used to // apply the changes to a persistent version of the user preferences, such as an XAML document. RaiseEvent(new CollectionChangedEventArgs(ReportFieldCollection.CollectionChangedEvent, UndoAction.Create, CollectionChangedAction.Remove, fieldDefinition)); } }
/// <summary> /// Inserts an element into the MarkThree.Windows.Controls.ReportColumnCollection at the specified index. /// </summary> /// <param name="index">The index of the new element.</param> /// <param name="value">The new element to be placed in the collection.</param> public void Insert(int index, object value) { // The XAML parser only recognizes the generic IList interfaces, so incoming values need to be qualified to be added to // this collection. if (value is ReportField) { // Column definitions are linked into the event handler for this collection so that any change to the individual // definition sets off a chain reaction of updates ReportField fieldDefinition = value as ReportField; fieldDefinition.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(fieldDefinition_PropertyChanged); // The list maintains the order for user interfaces and the dictionary is used for fast access to the column based // on the ColumnId. this.list.Insert(index, fieldDefinition); this.fieldDefinitionMap.Add(fieldDefinition.ColumnId, fieldDefinition); // This will broadcast a notification that the collection has been modified. This event is typically used to // apply the changes to a persistent version of the user preferences, such as an XAML document. RaiseEvent(new CollectionChangedEventArgs(ReportFieldCollection.CollectionChangedEvent, UndoAction.Create, CollectionChangedAction.Add, fieldDefinition, index)); } }
/// <summary> /// Adds a MarkThree.Windows.Controls.ColumnDefinition to the end of the collection. /// </summary> /// <param name="value">The value to be added to the end of the collection.</param> /// <returns>0</returns> public int Add(object value) { // The XAML parser only recognizes the generic IList interfaces, so incoming values need to be qualified to be added to // this collection. if (value is ReportField) { // Column definitions are linked into the event handler for this collection so that any change to the individual // definition sets off a chain reaction of updates ReportField fieldDefinition = value as ReportField; fieldDefinition.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(fieldDefinition_PropertyChanged); // The list maintains the order for user interfaces and the dictionary is used for fast access to the column based // on the ColumnId. this.list.Add(fieldDefinition); this.fieldDefinitionMap.Add(fieldDefinition.ColumnId, fieldDefinition); // This table maps the data type to a field that can display that data type. foreach (Type type in fieldDefinition.Types) { if (this.templateTypeColumnIdMap.ContainsKey(type)) { this.templateTypeColumnIdMap[type] = fieldDefinition.ColumnId; } else { this.templateTypeColumnIdMap.Add(type, fieldDefinition.ColumnId); } } // This will broadcast a notification that the collection has been modified. This event is typically used to // apply the changes to a persistent version of the user preferences, such as an XAML document. RaiseEvent(new CollectionChangedEventArgs(ReportFieldCollection.CollectionChangedEvent, UndoAction.Create, CollectionChangedAction.Add, fieldDefinition)); } // This is here to satisfy the interface specification. return(0); }
public bool TryGetValue(string key, out ReportField value) { return(this.fieldDefinitionMap.TryGetValue(key, out value)); }
/// <summary> /// Handles the mouse button being released over a column header. /// </summary> /// <param name="state">The thread initialization parameter.</param> protected override void OnMouseUp(MouseButtonEventArgs e) { // This gets the location of the mouse in document coordinates. Point mouseLocation = e.GetPosition(this); // Evaluate the state of the keyboard. Key combinations involving the shift and control keys will alter the areas that // are selected. bool isShiftKeyPressed = ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift); bool isControlKeyPressed = ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control); // The mouse state indications what action should be taken when the mouse button is released. switch (this.mouseState) { case MouseState.ResizingColumn: // At the conclusion of the resizing operation a decision is made to remove or change the width of a column. If // the size is reduced to zero (or less), this gesture is taken as a command to remove the column. Any positive // value for a width will result in a column change command. double columnWidth = this.anchorColumn.Width + (mouseLocation.X - this.anchorPoint.X); columnWidth = columnWidth < 0.0 ? 0.0 : columnWidth; if (this.ResizeMouseMove != null) { this.ResizeMouseMove(this, new ResizeColumnEventArgs(this.anchorColumn, columnWidth, true)); } if (columnWidth <= 0) { this.ReportGrid.Columns.Remove(this.anchorColumn); } else { this.ReportGrid.Columns.SetColumnWidth(this.anchorColumn, columnWidth); } // This will hide the popup until it is needed again. this.columnWidthPopup.IsOpen = false; // This is a momentary button: the column heading will loose the selection state when the button is released. foreach (ReportCell reportCell in this.headerCells) { reportCell.IsSelected = false; } break; case MouseState.ButtonDown: // This will sort the document by one or more selected columns. The control key is used to select multiple columns // similar to the selection mode of Microsoft Office. The first step to sorting is to find out which column in the // view has been selected for sorting. ReportColumn reportColumn = this.ReportGrid.Columns.FindColumnAt(mouseLocation.X); ReportField fieldDefinition = this.ReportGrid.Fields[reportColumn.ColumnId]; // The 'SortTemplate' attribute is used to distinguish columns that can be selected (usually columns that have user // input can be selected) versus columns that can be sorted. if (!fieldDefinition.IsSelectable) { // If the control key is kept pressed, then the selected sort columns will be combined. Otherwise, any // previously selected sort column is discarded. if (!isControlKeyPressed) { while (this.sortOrder.Count > 1 && this.sortOrder[this.sortOrder.Count - 1].Column != fieldDefinition) { this.sortOrder.Remove(this.sortOrder[0]); } } // The direction of the sorting in a column can be toggled each time it is selected. This requires a test to // make sure that the same column has been selected. Of course, if there is nothing in the list of sorting // columns, then the list is initialize with an ascending sort. if (this.sortOrder.Count != 0) { // Find the last sort column in the sort specification. If it matches the last column selected, then the // order of the sorting is toggled. If it doesn't match, then the column is added to the list of columns // when the control key is pressed or used to initialize the list when the control key is not pressed. SortItem sortItem = this.sortOrder[this.sortOrder.Count - 1]; if (sortItem.Column == fieldDefinition) { sortItem.SortOrder = sortItem.SortOrder == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; } else { if (!isControlKeyPressed) { this.sortOrder.Remove(sortItem); } this.sortOrder.Add(new SortItem(fieldDefinition, SortOrder.Ascending)); } } else { // This will initialize the list of sort columns when the list is empty. this.sortOrder.Add(new SortItem(fieldDefinition, SortOrder.Ascending)); } TeraqueCommands.SortReport.Execute(new SortEventArgs(this.sortOrder), this); } // This is a momentary button: the column heading will loose the selection state when the button is released. foreach (ReportCell reportCell in this.headerCells) { reportCell.IsSelected = false; } break; case MouseState.DraggingColumn: // The action taken when the dragging operation is complete depends on whether a valid destination is selected or // whether the column is meant to be deleted. switch (this.destinationState) { case DropAction.Select: // This will move the column from its current location to the desired location. if (this.destinationPopup.Visibility == Visibility.Visible) { // When the column is removed from the list, all the columns that appeared after the removed column will be shifted to // the left. This will adjust the target index so that the column will be re-inserted into the list at the desired // index after being removed. int newIndex = this.destinationColumn == null ? this.ReportGrid.Columns.Count : this.ReportGrid.Columns.IndexOf(this.destinationColumn); int oldIndex = this.ReportGrid.Columns.IndexOf(this.anchorColumn); newIndex = oldIndex < newIndex ? newIndex - 1 : newIndex; this.ReportGrid.Columns.Move(oldIndex, newIndex); } break; case DropAction.Delete: // This will delete the column from the view. this.ReportGrid.Columns.Remove(this.anchorColumn); break; } // This is a momentary button: the column heading will loose the selection state when the button is released. foreach (ReportCell reportCell in this.headerCells) { reportCell.IsSelected = false; } break; } // This resets the state of the mouse for the next operation. this.mouseState = MouseState.ButtonUp; if (this.headerPopup.IsOpen) { this.headerPopup.IsOpen = false; } // Hide the destination cursor when the mouse is released. if (this.destinationPopup.IsOpen) { this.destinationPopup.IsOpen = false; } // Release the Hounds, errr... mouse. Mouse.Capture(null); }