/// <summary> /// Gets collection of selected elements in necessary Gantt item. /// </summary> /// <param name="selectedType">TYpe of elements which can be added to selection.</param> /// <param name="ganttItem">Parent gantt item.</param> /// <param name="firstSelectedElement">First element in global selection.</param> /// <param name="lastSelectedElement">Last element in global selection.</param> /// <returns>Collection of selected elements.</returns> private ICollection <IGanttItemElement> _GetSelectedElementsByGanttItem(Type selectedType, IGanttItem ganttItem, IGanttItemElement firstSelectedElement, IGanttItemElement lastSelectedElement) { Collection <IGanttItemElement> selectedElements = new Collection <IGanttItemElement>(); int startIndex = 0; int endIndex = ganttItem.GanttItemElements.Count; if (ganttItem.GanttItemElements.Contains(firstSelectedElement)) { startIndex = ganttItem.GanttItemElements.IndexOf(firstSelectedElement); } if (ganttItem.GanttItemElements.Contains(lastSelectedElement)) { endIndex = ganttItem.GanttItemElements.IndexOf(lastSelectedElement) + 1; } for (int i = startIndex; i < endIndex; i++) { if (ganttItem.GanttItemElements[i].Tag.GetType() == selectedType) { selectedElements.Add(ganttItem.GanttItemElements[i]); } } return(selectedElements); }
/// <summary> /// Called when one of the elements raised time range event. /// </summary> /// <param name="sender">Event source.</param> /// <param name="e">Event arguments.</param> private void _ElementTimeRangeChanged(object sender, EventArgs e) { IGanttItemElement changedElement = sender as IGanttItemElement; Debug.Assert(changedElement != null); bool needToRaiseEvent = false; // Check whether new end time is later then saved value: if (changedElement.EndTime > EndTime) { _endTime = changedElement.EndTime; needToRaiseEvent = true; } // Check whether new start time is earlier then saved value: if (changedElement.StartTime < StartTime) { _startTime = changedElement.StartTime; needToRaiseEvent = true; } // Raise event if necessary. if (needToRaiseEvent && TimeRangeChanged != null) { TimeRangeChanged(this, EventArgs.Empty); } }
/// <summary> /// Selection logic if "Shift" button was pressed in selection. /// </summary> /// <param name="pressedElement">Last clicked element.</param> /// <returns>New selection collection. If selection shouldn't be changed - returns null.</returns> private ICollection <IGanttItemElement> _SelectItemsByShift(IGanttItemElement clickedElement) { Debug.Assert(_selectedElements.Count > 0); // Collection should contain at least one element. Otherwise we use _SelectItem method. // If user clicked to element in other GanttItem - do nothing. if (_selectedElements.First().Value.ParentGanttItem != clickedElement.ParentGanttItem) { return(null); } // Else - need to select range between first selected item and clicked item. // If just clicked element has the same tag as current GanttItem - // elemet is already in selection (was added earlier by custom logic in _SelectItem() method). And we should do nothing. if (_selectedElements.First().Key.ParentGanttItem.Tag == clickedElement.Tag) { return(null); } // Check that clicked item is the same type as items in collection. Type selectedItemsType = _selectedElements.First().Value.Tag.GetType(); // If new element Tag type is nos same as Tag type of already selected elements - do nothing. if (clickedElement.Tag.GetType() != selectedItemsType) { return(null); } // Rename vars to make code more clear. IGanttItemElement firstSelectedElement = _selectedElements.First().Key; IGanttItemElement lastSelectedElement = clickedElement; IGanttItem parentItem = lastSelectedElement.ParentGanttItem; // Defines whether selection bounds are in revert order. bool doSelectionBoundsHaveInvalidOrder = (parentItem.GanttItemElements.IndexOf(lastSelectedElement) < parentItem.GanttItemElements.IndexOf(firstSelectedElement)); // If index of last selected item parent is smaller than first selected item parent - interchange items. if (doSelectionBoundsHaveInvalidOrder) { IGanttItemElement buffer = firstSelectedElement; firstSelectedElement = lastSelectedElement; lastSelectedElement = buffer; } // Collection of all element which should be selected now. ICollection <IGanttItemElement> newSelectedElements = new Collection <IGanttItemElement>(); // Select elements from selection range. newSelectedElements = _GetSelectedElementsByGanttItem(selectedItemsType, parentItem, firstSelectedElement, lastSelectedElement); return(newSelectedElements); }
/// <summary> /// Selection logic if "Ctrl" button was pressed in selection. /// </summary> /// <param name="clickedElement">Last clicked element.</param> /// <returns>Collection of new selected elements. Null if selection shouldn't be changed.</returns> private ICollection <IGanttItemElement> _SelectItemsByCtrl(IGanttItemElement clickedElement) { Debug.Assert(_selectedElements.Count > 0); // Collection should contain at least one element. Otherwise we use _SelectItem method. Collection <IGanttItemElement> oldSelectedElements = new Collection <IGanttItemElement>(_selectedElements.Values.ToList <IGanttItemElement>()); // Check that clicked item is the same type as items in collection. Type selectedItemsType = _selectedElements.First().Key.Tag.GetType(); // If new element Tag type is nos same as Tag type of already selected elements - do nothing. if (clickedElement.Tag.GetType() != selectedItemsType) { return(null); } Collection <IGanttItemElement> selectedElements = new Collection <IGanttItemElement>(); // Add clicked element to collection. selectedElements.Add(clickedElement); // If clicked element has same Tag as parent Gantt Item - select all elements with this tag. if (clickedElement.Tag == clickedElement.ParentGanttItem.Tag) { selectedElements = _GetSelectedElementsWithGanttItemTag(clickedElement.ParentGanttItem); } // If clicked element is not contains in selected collection - add it (select). if (!oldSelectedElements.Contains(clickedElement)) { foreach (IGanttItemElement element in selectedElements) { oldSelectedElements.Add(element); } } // Otherwise - remove elements (deselect). else { foreach (IGanttItemElement element in selectedElements) { if (oldSelectedElements.Contains(element)) { oldSelectedElements.Remove(element); } } } return(oldSelectedElements); }
/// <summary> /// Redraws element when it necessary. /// </summary> /// <param name="sender">Element to redraw.</param> /// <param name="e">Event args.</param> private void _ElementRedrawRequired(object sender, EventArgs e) { IGanttItemElement element = sender as IGanttItemElement; Debug.Assert(element != null); GanttItemElementDrawingVisual visual = null; if (_mapElementToVisual.TryGetValue(element, out visual)) { visual.RedrawRequired = true; } InvalidateVisual(); }
/// <summary> /// Finds first element in collection by tag. /// </summary> /// <param name="tag">Necessary tag.</param> /// <returns>Result element.</returns> public IGanttItemElement FindFirstElementByTag(object tag) { IGanttItemElement foundElement = null; // Add all elements with necessary tag into result collection. foreach (IGanttItemElement element in _ganttItemElements) { if (element.Tag.Equals(tag)) { foundElement = element; break; } } return(foundElement); }
/// <summary> /// Handler updates selection if necessary. /// </summary> /// <param name="sender">Container.</param> /// <param name="e">Mouse event args.</param> private void _PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (_needToReleaseSelection) { // Get clicked element. IGanttItemElement ganttItemElement = this.HitTest(Mouse.GetPosition(this)) as IGanttItemElement; if (ganttItemElement == null) { return; } _Select(ganttItemElement); } _needToReleaseSelection = false; _mustStartDraggingOnMouseMove = false; }
/// <summary> /// Calculates drawing area for necessary visual children. /// </summary> /// <param name="element">Element for which bounds should be calculated.</param> /// <returns>New drawing area in relative coordinates.</returns> private Rect _GetChildDrawingArea(IGanttItemElement element, GanttItemElementDrawingContext context) { Debug.Assert(element != null); Debug.Assert(element.ParentGanttItem != null); // Define Y position of element. double yPos = _ganttItems.IndexOf(element.ParentGanttItem) * _rowHeight; // Copy start and end time from element to context. context.StartTime = element.StartTime; context.EndTime = element.EndTime; // If elemnts start time or end time is out of if (element.StartTime < _startTime) { context.StartTime = _startTime; } if (element.EndTime > _endTime) { context.EndTime = _endTime; } // Define element duration in time units. TimeSpan elementDuration = context.EndTime - context.StartTime; // Define element shift from left container border. We are always make a gap with width = 1 for correctly show elements styles. double xPos = Math.Max(1, (context.StartTime - _startTime).Ticks * _pixelsPerTick); // Define element duration in pixels. double elementWidth = Math.Max(0, Math.Abs(elementDuration.Ticks) * _pixelsPerTick); if (elementWidth == 0) { elementWidth = DEFAULT_ELEMENT_WIDTH; } // Define element height - it's the same for all elements and equals row height. double elementHeight = _rowHeight; return(new Rect(xPos, yPos, elementWidth, elementHeight)); }
/// <summary> /// Selects gantt elements depending on keyboard state. /// </summary> /// <param name="ganttItemElement">Element to select.</param> private void _Select(IGanttItemElement ganttItemElement) { Debug.Assert(ganttItemElement != null); ICollection <IGanttItemElement> newSelection = null; // If no modifier keys was pressed on keyboard or selection is empty - use single selection logic. if (_selectedElements.Count == 0 || Keyboard.Modifiers == ModifierKeys.None) { newSelection = _SelectItem(ganttItemElement); } else if (Keyboard.Modifiers == ModifierKeys.Shift) // If "Shift" key was pressed. { newSelection = _SelectItemsByShift(ganttItemElement); } else if (Keyboard.Modifiers == ModifierKeys.Control) // if "Ctrl" key was pressed. { newSelection = _SelectItemsByCtrl(ganttItemElement); } // If new selected collection is null - selection should not be changed. if (newSelection == null) { return; } // Set "RedrawRequired" status to true in necessary elements. _UpdateRedrawRequiredStatusWhenSelectionChanged(newSelection); // Update collection of selected items _selectedElements.Clear(); foreach (IGanttItemElement element in newSelection) { _selectedElements.Add(element, element); } InvalidateVisual(); _OnSelectionChanged(); }
/// <summary> /// Handler changes selection by mouse click. /// </summary> /// <param name="sender">Container.</param> /// <param name="e">Mouse event args.</param> private void _MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Debug.Assert(_selectedElements != null); // Get clicked element. IGanttItemElement ganttItemElement = this.HitTest(Mouse.GetPosition(this)) as IGanttItemElement; if (ganttItemElement == null) { return; } _mustStartDraggingOnMouseMove = true; if (_selectedElements.ContainsKey(ganttItemElement)) { _needToReleaseSelection = true; return; } _Select(ganttItemElement); }
/// <summary> /// Method removes all visuals from child collection if visual is bound with gantt item. Also removes objects from selection. /// </summary> /// <param name="ganttItem">Gantt item.</param> private void _RemoveVisualsForGanttItem(IGanttItem ganttItem) { Collection <IGanttItemElement> itemsToRemove = new Collection <IGanttItemElement>(); foreach (GanttItemElementDrawingVisual visual in _children) //(int i = 0; i < VisualChildrenCount; i++) { IGanttItemElement element = ((GanttItemElementDrawingVisual)visual).GanttItemElement; if (element.ParentGanttItem.Equals(ganttItem)) { itemsToRemove.Add(element); } } // Remove necessary elements from collection. foreach (IGanttItemElement element in itemsToRemove) { element.RedrawRequired -= _ElementRedrawRequired; _children.Remove(_mapElementToVisual[element]); _mapElementToVisual.Remove(element); _selectedElements.Remove(element); } }
/// <summary> /// Adds item into collection of selected items. /// </summary> /// <param name="pressedElement"></param> /// <returns>Collection of selected elements.</returns> private ICollection <IGanttItemElement> _SelectItem(IGanttItemElement ganttItemElement) { List <IGanttItemElement> newSelection = new List <IGanttItemElement>(); // If selected element has the same Tag as parent Gantt Item - select all elements with this tag. if (ganttItemElement.Tag == ganttItemElement.ParentGanttItem.Tag) { ICollection <IGanttItemElement> selectedElements = _GetSelectedElementsWithGanttItemTag(ganttItemElement.ParentGanttItem); if (selectedElements.Count == 0) { return(null); } newSelection.AddRange(selectedElements); } else { newSelection.Add(ganttItemElement); } return(newSelection); }
public GanttItemElementDrawingVisual(IGanttItemElement element) { GanttItemElement = element; RedrawRequired = true; }
/// <summary> /// Selection logic if "Shift" button was pressed in selection. /// </summary> /// <param name="pressedElement">Last clicked element.</param> /// <returns>New selection collection. If selection shouldn't be changed - returns null.</returns> private ICollection<IGanttItemElement> _SelectItemsByShift(IGanttItemElement clickedElement) { Debug.Assert(_selectedElements.Count > 0); // Collection should contain at least one element. Otherwise we use _SelectItem method. // If user clicked to element in other GanttItem - do nothing. if (_selectedElements.First().Value.ParentGanttItem != clickedElement.ParentGanttItem) return null; // Else - need to select range between first selected item and clicked item. // If just clicked element has the same tag as current GanttItem - // elemet is already in selection (was added earlier by custom logic in _SelectItem() method). And we should do nothing. if (_selectedElements.First().Key.ParentGanttItem.Tag == clickedElement.Tag) return null; // Check that clicked item is the same type as items in collection. Type selectedItemsType = _selectedElements.First().Value.Tag.GetType(); // If new element Tag type is nos same as Tag type of already selected elements - do nothing. if (clickedElement.Tag.GetType() != selectedItemsType) return null; // Rename vars to make code more clear. IGanttItemElement firstSelectedElement = _selectedElements.First().Key; IGanttItemElement lastSelectedElement = clickedElement; IGanttItem parentItem = lastSelectedElement.ParentGanttItem; // Defines whether selection bounds are in revert order. bool doSelectionBoundsHaveInvalidOrder = (parentItem.GanttItemElements.IndexOf(lastSelectedElement) < parentItem.GanttItemElements.IndexOf(firstSelectedElement)); // If index of last selected item parent is smaller than first selected item parent - interchange items. if (doSelectionBoundsHaveInvalidOrder) { IGanttItemElement buffer = firstSelectedElement; firstSelectedElement = lastSelectedElement; lastSelectedElement = buffer; } // Collection of all element which should be selected now. ICollection<IGanttItemElement> newSelectedElements = new Collection<IGanttItemElement>(); // Select elements from selection range. newSelectedElements = _GetSelectedElementsByGanttItem(selectedItemsType, parentItem, firstSelectedElement, lastSelectedElement); return newSelectedElements; }
/// <summary> /// Selection logic if "Ctrl" button was pressed in selection. /// </summary> /// <param name="clickedElement">Last clicked element.</param> /// <returns>Collection of new selected elements. Null if selection shouldn't be changed.</returns> private ICollection<IGanttItemElement> _SelectItemsByCtrl(IGanttItemElement clickedElement) { Debug.Assert(_selectedElements.Count > 0); // Collection should contain at least one element. Otherwise we use _SelectItem method. Collection<IGanttItemElement> oldSelectedElements = new Collection<IGanttItemElement>(_selectedElements.Values.ToList<IGanttItemElement>()); // Check that clicked item is the same type as items in collection. Type selectedItemsType = _selectedElements.First().Key.Tag.GetType(); // If new element Tag type is nos same as Tag type of already selected elements - do nothing. if (clickedElement.Tag.GetType() != selectedItemsType) return null; Collection<IGanttItemElement> selectedElements = new Collection<IGanttItemElement>(); // Add clicked element to collection. selectedElements.Add(clickedElement); // If clicked element has same Tag as parent Gantt Item - select all elements with this tag. if (clickedElement.Tag == clickedElement.ParentGanttItem.Tag) selectedElements = _GetSelectedElementsWithGanttItemTag(clickedElement.ParentGanttItem); // If clicked element is not contains in selected collection - add it (select). if (!oldSelectedElements.Contains(clickedElement)) { foreach (IGanttItemElement element in selectedElements) oldSelectedElements.Add(element); } // Otherwise - remove elements (deselect). else { foreach (IGanttItemElement element in selectedElements) if (oldSelectedElements.Contains(element)) oldSelectedElements.Remove(element); } return oldSelectedElements; }
/// <summary> /// Adds item into collection of selected items. /// </summary> /// <param name="pressedElement"></param> /// <returns>Collection of selected elements.</returns> private ICollection<IGanttItemElement> _SelectItem(IGanttItemElement ganttItemElement) { List<IGanttItemElement> newSelection = new List<IGanttItemElement>(); // If selected element has the same Tag as parent Gantt Item - select all elements with this tag. if (ganttItemElement.Tag == ganttItemElement.ParentGanttItem.Tag) { ICollection<IGanttItemElement> selectedElements = _GetSelectedElementsWithGanttItemTag(ganttItemElement.ParentGanttItem); if (selectedElements.Count == 0) return null; newSelection.AddRange(selectedElements); } else newSelection.Add(ganttItemElement); return newSelection; }
/// <summary> /// Selects gantt elements depending on keyboard state. /// </summary> /// <param name="ganttItemElement">Element to select.</param> private void _Select(IGanttItemElement ganttItemElement) { Debug.Assert(ganttItemElement != null); ICollection<IGanttItemElement> newSelection = null; // If no modifier keys was pressed on keyboard or selection is empty - use single selection logic. if (_selectedElements.Count == 0 || Keyboard.Modifiers == ModifierKeys.None) { newSelection = _SelectItem(ganttItemElement); } else if (Keyboard.Modifiers == ModifierKeys.Shift) // If "Shift" key was pressed. { newSelection = _SelectItemsByShift(ganttItemElement); } else if (Keyboard.Modifiers == ModifierKeys.Control) // if "Ctrl" key was pressed. { newSelection = _SelectItemsByCtrl(ganttItemElement); } // If new selected collection is null - selection should not be changed. if (newSelection == null) return; // Set "RedrawRequired" status to true in necessary elements. _UpdateRedrawRequiredStatusWhenSelectionChanged(newSelection); // Update collection of selected items _selectedElements.Clear(); foreach (IGanttItemElement element in newSelection) _selectedElements.Add(element, element); InvalidateVisual(); _OnSelectionChanged(); }
/// <summary> /// Gets collection of selected elements in necessary Gantt item. /// </summary> /// <param name="selectedType">TYpe of elements which can be added to selection.</param> /// <param name="ganttItem">Parent gantt item.</param> /// <param name="firstSelectedElement">First element in global selection.</param> /// <param name="lastSelectedElement">Last element in global selection.</param> /// <returns>Collection of selected elements.</returns> private ICollection<IGanttItemElement> _GetSelectedElementsByGanttItem(Type selectedType, IGanttItem ganttItem, IGanttItemElement firstSelectedElement, IGanttItemElement lastSelectedElement) { Collection<IGanttItemElement> selectedElements = new Collection<IGanttItemElement>(); int startIndex = 0; int endIndex = ganttItem.GanttItemElements.Count; if (ganttItem.GanttItemElements.Contains(firstSelectedElement)) startIndex = ganttItem.GanttItemElements.IndexOf(firstSelectedElement); if (ganttItem.GanttItemElements.Contains(lastSelectedElement)) endIndex = ganttItem.GanttItemElements.IndexOf(lastSelectedElement) + 1; for (int i = startIndex; i < endIndex; i++) { if (ganttItem.GanttItemElements[i].Tag.GetType() == selectedType) selectedElements.Add(ganttItem.GanttItemElements[i]); } return selectedElements; }
/// <summary> /// Calculates drawing area for necessary visual children. /// </summary> /// <param name="element">Element for which bounds should be calculated.</param> /// <returns>New drawing area in relative coordinates.</returns> private Rect _GetChildDrawingArea(IGanttItemElement element, GanttItemElementDrawingContext context) { Debug.Assert(element != null); Debug.Assert(element.ParentGanttItem != null); // Define Y position of element. double yPos = _ganttItems.IndexOf(element.ParentGanttItem) * _rowHeight; // Copy start and end time from element to context. context.StartTime = element.StartTime; context.EndTime = element.EndTime; // If elemnts start time or end time is out of if (element.StartTime < _startTime) context.StartTime = _startTime; if (element.EndTime > _endTime) context.EndTime = _endTime; // Define element duration in time units. TimeSpan elementDuration = context.EndTime - context.StartTime; // Define element shift from left container border. We are always make a gap with width = 1 for correctly show elements styles. double xPos = Math.Max(1, (context.StartTime - _startTime).Ticks * _pixelsPerTick); // Define element duration in pixels. double elementWidth = Math.Max(0, Math.Abs(elementDuration.Ticks) * _pixelsPerTick); if (elementWidth == 0) elementWidth = DEFAULT_ELEMENT_WIDTH; // Define element height - it's the same for all elements and equals row height. double elementHeight = _rowHeight; return new Rect(xPos, yPos, elementWidth, elementHeight); }
/// <summary> /// Retruns bounds of element. /// </summary> /// <param name="element">IGanttItemElement.</param> /// <returns>Element bounds.</returns> public Rect GetElementBounds(IGanttItemElement element) { return _GetChildDrawingArea(element, new GanttItemElementDrawingContext()); }
/// <summary> /// Retruns bounds of element. /// </summary> /// <param name="element">IGanttItemElement.</param> /// <returns>Element bounds.</returns> public Rect GetElementBounds(IGanttItemElement element) { return(_GetChildDrawingArea(element, new GanttItemElementDrawingContext())); }