private void Rectangle_MouseDown(object sender, MouseButtonEventArgs e) { if (sender is Rectangle rectangle) { var stackPanel = VisualTreeTraverseHelper.FindParent <StackPanel>(rectangle); if (stackPanel != null) { // we've got this! } var grid = VisualTreeTraverseHelper.FindParent <Grid>(rectangle); if (grid != null) { // we've got this! } var lazyStackPanel = VisualTreeTraverseHelper.FindVisualParentByName(rectangle, "LazyStackPanel") as StackPanel; if (lazyStackPanel != null) { // cool } } }
// Control authors who want to customize the arrange pass of layout processing should // override this method. The implementation pattern should call Arrange(Rect) on each visible child element, // and pass the final desired size for each child element as the finalRect parameter. Parent elements should // call Arrange(Rect) on each child, otherwise the child elements will not be rendered. protected override Size ArrangeOverride(Size finalSize) { this._numberOfChildren = 0; var listOfWidths = new List <double>(); var location = new Point(); var listView = VisualTreeTraverseHelper.FindParent <ListView>(this.TemplatedParent); if (listView != null) { // get all of the desired widths in order // to pick up the greatest width of all children for (int i = 0; i < listView.Items.Count; i++) { var listViewItem = (ListViewItem)listView.ItemContainerGenerator.ContainerFromIndex(i); if (listViewItem != null) { var rootStackPanel = VisualTreeTraverseHelper.FindDescendant <StackPanel>(listViewItem); if (rootStackPanel != null) { foreach (var child in rootStackPanel.Children) { var frameworkElement = child as FrameworkElement; if (frameworkElement != null) { listOfWidths.Add(frameworkElement.DesiredSize.Width); } } } } } // first pass won't have any desired sizes // second pass should have. if (listOfWidths.Count > 0) { double maxValue = listOfWidths.Max <double>(); // iterate through children again, but this time // let's set our desired width to each of them for (int i = 0; i < listView.Items.Count; i++) { var listViewItem = (ListViewItem)listView.ItemContainerGenerator.ContainerFromIndex(i); if (listViewItem != null) { var rootStackPanel = VisualTreeTraverseHelper.FindDescendant <StackPanel>(listViewItem); if (rootStackPanel != null) { foreach (var child in rootStackPanel.Children) { var frameworkElement = child as FrameworkElement; if (frameworkElement != null) { frameworkElement.Width = maxValue; _numberOfChildren++; } } } } } // calculates width of whole item _totalChildWidth = Math.Round(((maxValue * _numberOfChildren) + ADDITIONAL_SPACE), DECIMAL_PLACES); // this must be called in order to re-calculate // each child size that it's needed to display foreach (UIElement child in InternalChildren) { child.Measure(new Size(_totalChildWidth, child.DesiredSize.Height)); } } } // final screen positioning foreach (UIElement child in InternalChildren) { // set child position on the screen // since location.Y has been incremented // each child will stack vertically child.Arrange(new Rect(location, child.DesiredSize)); location.Y += child.DesiredSize.Height; } return(finalSize); }
// Control authors who want to customize the arrange pass of layout processing should // override this method. The implementation pattern should call Arrange(Rect) on each visible child element, // and pass the final desired size for each child element as the finalRect parameter. Parent elements should // call Arrange(Rect) on each child, otherwise the child elements will not be rendered. protected override Size ArrangeOverride(Size finalSize) { var location = new Point(); var listOfNotStretchedItemsWidth = new List <double>(); var numberOfHorizontalStretched = 0; var lengthOfItemsControlItems = 0; var totalParentWidth = 0.0; var widthOfStretchedItem = 0.0; // iterate through itemscontrol children in order // to check how many of these children have horizontalaligmnent // set to stretched. These calculations are needed to split available // width into equal parts among stretched children var listView = VisualTreeTraverseHelper.FindParent <ListView>(this.TemplatedParent); if (listView != null && listView.Items != null) { for (int i = 0; i < listView.Items.Count; i++) { // generate container from particular index // to check if it's stretched or not var childContainer = listView.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement; if (childContainer != null) { // change thickness depending on thickness // that was given by us through dependency // property called 'Spacing' if (this.Orientation != Orientation.Vertical) { if ((Spacing.Right > 0 || Spacing.Left > 0) && i < listView.Items.Count) { childContainer.Margin = new Thickness(Spacing.Left, 0, Spacing.Right, 0); } } else { if ((Spacing.Top > 0 || Spacing.Bottom > 0) && i < listView.Items.Count - 1) { childContainer.Margin = new Thickness(0, Spacing.Top, 0, Spacing.Bottom); } } // if container has stretched alignment then // increment given value for further calculations if (childContainer.HorizontalAlignment == HorizontalAlignment.Stretch) { numberOfHorizontalStretched++; } else { // store width of non-stretched items // to calculate a proper logic for // the stretched once. listOfNotStretchedItemsWidth.Add(childContainer.DesiredSize.Width); } } } // get number of stretched children lengthOfItemsControlItems = numberOfHorizontalStretched; } // setting up HorizontalAlighment on the control itself to stretch // will make sure that the finalSize.Width is equal to the maximum // available size. It will fit it's parent. totalParentWidth = finalSize.Width; // if there's children with different state // of horizontalalignment then remove previously // stored widths from the totalParentWidths // in order to split stretched children into equal parts. if (listOfNotStretchedItemsWidth.Count > 0) { foreach (var element in listOfNotStretchedItemsWidth) { totalParentWidth -= element; } } // divide width for stretched child into // equal parts among each stretched item. widthOfStretchedItem = totalParentWidth / lengthOfItemsControlItems; // iterate through internal children to // set desired size and to call Arrange() method. foreach (UIElement child in InternalChildren) { // change the location (placement) of an item // depending of the orientation dependency property if (Orientation != Orientation.Vertical) { // set the rectangle that will be a direct container // for our child and add same width to the location child.Arrange(new Rect(location, new Size(widthOfStretchedItem, child.DesiredSize.Height))); if (Spacing.Right > 0 || Spacing.Left > 0) { location.X += widthOfStretchedItem + Math.Max(Spacing.Right, Spacing.Left); } else { location.X += widthOfStretchedItem; } } else { child.Arrange(new Rect(location, child.DesiredSize)); if (Spacing.Top > 0 || Spacing.Bottom > 0) { location.X += widthOfStretchedItem + Math.Max(Spacing.Top, Spacing.Bottom); } else { location.Y += child.DesiredSize.Height; } } } return(finalSize); }