// // Copyright (c) PlaceholderCompany. All rights reserved. // #nullable enable namespace SystemTrayMenu.UserInterface { using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Reflection; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; using SystemTrayMenu.DataClasses; using SystemTrayMenu.DllImports; using SystemTrayMenu.Helper; using SystemTrayMenu.Utilities; using Windows.UI.Composition; using Color = System.Drawing.Color; using Image = System.Windows.Controls.Image; using Point = System.Drawing.Point; /// /// Logic of Menu window. /// public partial class Menu : Window { #if TODO public const string RowFilterShowAll = "[SortIndex] LIKE '%0%'"; #endif private const int CornerRadius = 10; private readonly Fading fading = new(); private bool isShowing; private bool directionToRight; #if TODO private int rotationAngle; #endif private bool mouseDown; private Point lastLocation; #if TODO private bool isSetSearchText; private bool dgvHeightSet; #endif private bool isClosed = false; // TODO WPF Replace Forms wrapper private DispatcherTimer timerUpdateIcons = new DispatcherTimer(DispatcherPriority.Render, Dispatcher.CurrentDispatcher); internal Menu() { timerUpdateIcons.Tick += TimerUpdateIcons_Tick; Closed += (_, _) => { timerUpdateIcons.Stop(); isClosed = true; // TODO WPF Replace Forms wrapper }; Opacity = 0D; fading.ChangeOpacity += Fading_ChangeOpacity; void Fading_ChangeOpacity(object? sender, double newOpacity) { if (newOpacity != Opacity && !IsDisposed && !Disposing) { Opacity = newOpacity; } } fading.Show += Fading_Show; void Fading_Show() { try { isShowing = true; Visibility = Visibility.Visible; isShowing = false; timerUpdateIcons.Start(); } catch (ObjectDisposedException) { Visibility = Visibility.Hidden; isShowing = false; Log.Info($"Could not open menu, old menu was disposing," + $" IsDisposed={IsDisposed}"); } if (Visibility == Visibility.Visible) { if (Level == 0) { Activate(); Show(); } else { ShowActivated = false; Show(); } } } fading.Hide += Hide; InitializeComponent(); Assembly myassembly = Assembly.GetExecutingAssembly(); string myname = myassembly.GetName().Name ?? string.Empty; txtTitle.Text = myname; #if TODO foreach (KeyValuePair pair in new List>() { new KeyValuePair(pictureBoxSearch, myname + ".Resources.SystemTrayMenu.png"), new KeyValuePair(pictureBoxOpenFolder, myname + ".Resources.SystemTrayMenu.png"), new KeyValuePair(pictureBoxMenuAlwaysOpen, myname + ".Resources.SystemTrayMenu.png"), new KeyValuePair(pictureBoxSettings, myname + ".Resources.SystemTrayMenu.png"), new KeyValuePair(pictureBoxRestart, myname + ".Resources.SystemTrayMenu.png"), }) { Image control = pair.Key; using (Stream? imgstream = myassembly.GetManifestResourceStream(pair.Value)) { if (imgstream != null) { BitmapImage imageSource = new BitmapImage(); imageSource.BeginInit(); imageSource.StreamSource = imgstream; imageSource.EndInit(); control.Source = imageSource; } } control.Width = Scaling.Scale(control.Width); control.Height = Scaling.Scale(control.Height); } #else foreach (FrameworkElement control in new List() { buttonMenuAlwaysOpen, buttonOpenFolder, buttonSettings, buttonRestart, pictureBoxSearch, pictureBoxMenuAlwaysOpen, pictureBoxOpenFolder, pictureBoxSettings, pictureBoxRestart, }) { control.Width = Scaling.Scale(control.Width); control.Height = Scaling.Scale(control.Height); } #endif labelTitle.FontSize = Scaling.ScaleFontByPoints(8.25F); textBoxSearch.FontSize = Scaling.ScaleFontByPoints(8.25F); labelItems.FontSize = Scaling.ScaleFontByPoints(7F); dgv.FontSize = Scaling.ScaleFontByPoints(9F); #if TODO customScrollbar = new CustomScrollbar(); tableLayoutPanelDgvAndScrollbar.Controls.Add(customScrollbar, 1, 0); #endif MouseDown += Menu_MouseDown; MouseUp += Menu_MouseUp; MouseMove += Menu_MouseMove; textBoxSearch.TextChanged += TextBoxSearch_TextChanged; #if TODO labelTitle.MouseWheel += new MouseEventHandler(DgvMouseWheel); textBoxSearch.ContextMenu = new ContextMenu(); // customScrollbar customScrollbar.Location = new Point(0, 0); customScrollbar.Name = "customScrollbar"; customScrollbar.Size = new Size(Scaling.Scale(15), 40); #endif SolidColorBrush foreColor = Color.Black.ToSolidColorBrush(); SolidColorBrush backColor = AppColors.Background.ToSolidColorBrush(); SolidColorBrush backColorSearch = AppColors.SearchField.ToSolidColorBrush(); SolidColorBrush backgroundBorder = AppColors.BackgroundBorder.ToSolidColorBrush(); if (Config.IsDarkMode()) { foreColor = Color.White.ToSolidColorBrush(); backColor = AppColors.DarkModeBackground.ToSolidColorBrush(); backColorSearch = AppColors.DarkModeSearchField.ToSolidColorBrush(); backgroundBorder = AppColors.DarkModeBackgroundBorder.ToSolidColorBrush(); } labelTitle.Foreground = foreColor; textBoxSearch.Foreground = foreColor; dgv.Foreground = foreColor; labelItems.Foreground = MenuDefines.ColorIcons.ToSolidColorBrush(); windowFrame.BorderBrush = backgroundBorder; windowFrame.Background = backColor; searchPanel.Background = backColorSearch; panelLine.Background = AppColors.Icons.ToSolidColorBrush(); dgv.GotFocus += (_, _) => FocusTextBox(); #if TODO customScrollbar.GotFocus += (sender, e) => FocusTextBox(); customScrollbar.Margin = new Padding(0); customScrollbar.Scroll += CustomScrollbar_Scroll; void CustomScrollbar_Scroll(object sender, EventArgs e) { decimal firstIndex = customScrollbar.Value * dgv.Rows.Count / (decimal)customScrollbar.Maximum; int firstIndexRounded = (int)Math.Ceiling(firstIndex); if (firstIndexRounded > -1 && firstIndexRounded < dgv.RowCount) { dgv.FirstDisplayedScrollingRowIndex = firstIndexRounded; } } customScrollbar.MouseEnter += ControlsMouseEnter; dgv.MouseEnter += ControlsMouseEnter; labelTitle.MouseEnter += ControlsMouseEnter; textBoxSearch.MouseEnter += ControlsMouseEnter; pictureBoxOpenFolder.MouseEnter += ControlsMouseEnter; pictureBoxMenuAlwaysOpen.MouseEnter += ControlsMouseEnter; pictureBoxSettings.MouseEnter += ControlsMouseEnter; pictureBoxRestart.MouseEnter += ControlsMouseEnter; pictureBoxSearch.MouseEnter += ControlsMouseEnter; tableLayoutPanelMenu.MouseEnter += ControlsMouseEnter; tableLayoutPanelDgvAndScrollbar.MouseEnter += ControlsMouseEnter; tableLayoutPanelBottom.MouseEnter += ControlsMouseEnter; labelItems.MouseEnter += ControlsMouseEnter; void ControlsMouseEnter(object sender, EventArgs e) { MouseEnter?.Invoke(); } customScrollbar.MouseLeave += ControlsMouseLeave; dgv.MouseLeave += ControlsMouseLeave; labelTitle.MouseLeave += ControlsMouseLeave; textBoxSearch.MouseLeave += ControlsMouseLeave; pictureBoxMenuAlwaysOpen.MouseLeave += ControlsMouseLeave; pictureBoxOpenFolder.MouseLeave += ControlsMouseLeave; pictureBoxSettings.MouseLeave += ControlsMouseLeave; pictureBoxRestart.MouseLeave += ControlsMouseLeave; pictureBoxSearch.MouseLeave += ControlsMouseLeave; tableLayoutPanelMenu.MouseLeave += ControlsMouseLeave; tableLayoutPanelDgvAndScrollbar.MouseLeave += ControlsMouseLeave; tableLayoutPanelBottom.MouseLeave += ControlsMouseLeave; labelItems.MouseLeave += ControlsMouseLeave; void ControlsMouseLeave(object sender, EventArgs e) { MouseLeave?.Invoke(); } bool isTouchEnabled = NativeMethods.IsTouchEnabled(); if ((isTouchEnabled && Properties.Settings.Default.DragDropItemsEnabledTouch) || (!isTouchEnabled && Properties.Settings.Default.DragDropItemsEnabled)) { AllowDrop = true; DragEnter += DragDropHelper.DragEnter; DragDrop += DragDropHelper.DragDrop; } #endif Loaded += (sender, e) => { NativeMethods.HideFromAltTab(this); // TODO WPF Replace Forms wrapper IsHandleCreated = true; HandleCreated?.Invoke(sender, e); }; } #if TODO internal new event Action MouseWheel; internal new event Action MouseEnter; internal new event Action MouseLeave; #endif internal event Action? UserClickedOpenFolder; #if TODO internal event EventHandler CmdKeyProcessed; internal event EventHandler KeyPressCheck; internal event Action SearchTextChanging; internal event EventHandler SearchTextChanged; #endif internal event Action? UserDragsMenu; internal event RoutedEventHandler? HandleCreated; // TODO WPF Replace Forms wrapper internal event Action? CellMouseEnter; internal event Action? CellMouseLeave; internal event Action? CellMouseDown; internal event Action? CellMouseUp; internal event Action? CellMouseClick; internal event Action? CellMouseDoubleClick; internal enum MenuType { Main, Sub, Empty, NoAccess, MaxReached, Loading, } internal enum StartLocation { Predecessor, BottomLeft, BottomRight, TopRight, } public bool IsHandleCreated { get; internal set; } // TODO State out of window public bool IsLoadingMenu { get; internal set; } // TODO State out of window public bool IsDisposed => isClosed; // TODO WPF Replace Forms wrapper public bool Disposing => isClosed; // TODO WPF Replace Forms wrapper public System.Drawing.Point Location => new System.Drawing.Point((int)Left, (int)Top); // TODO WPF Replace Forms wrapper) internal int Level { get; set; } internal bool IsUsable => Visibility == Visibility.Visible && !fading.IsHiding && !IsDisposed && !Disposing; #if TODO internal bool ScrollbarVisible { get; private set; } #endif private ListView tableLayoutPanelDgvAndScrollbar => dgv; // TODO WPF Remove and replace with dgv internal void ResetSearchText() { #if TODO textBoxSearch.Text = string.Empty; if (dgv.Rows.Count > 0) { dgv.FirstDisplayedScrollingRowIndex = 0; } AdjustScrollbar(); #endif } internal void RefreshSearchText() { #if TODO TextBoxSearch_TextChanged(textBoxSearch, null); if (dgv.Rows.Count > 0) { dgv.FirstDisplayedScrollingRowIndex = 0; } AdjustScrollbar(); #endif } internal void FocusTextBox() { #if TODO if (isSetSearchText) { isSetSearchText = false; textBoxSearch.SelectAll(); textBoxSearch.Focus(); textBoxSearch.SelectionStart = textBoxSearch.Text.Length; textBoxSearch.SelectionLength = 0; } else { textBoxSearch.SelectAll(); textBoxSearch.Focus(); } #endif } internal void SetTypeSub() { SetType(MenuType.Sub); } internal void SetTypeEmpty() { SetType(MenuType.Empty); } internal void SetTypeNoAccess() { SetType(MenuType.NoAccess); } internal void SetTypeLoading() { SetType(MenuType.Loading); } internal void SetType(MenuType type) { if (type != MenuType.Main) { buttonSettings.Visibility = Visibility.Collapsed; buttonRestart.Visibility = Visibility.Collapsed; } switch (type) { case MenuType.Main: break; case MenuType.Sub: buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed; break; case MenuType.Empty: labelItems.Content = Translator.GetText("Directory empty"); buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed; break; case MenuType.NoAccess: labelItems.Content = Translator.GetText("Directory inaccessible"); buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed; break; case MenuType.Loading: labelItems.Content = Translator.GetText("loading"); buttonMenuAlwaysOpen.Visibility = Visibility.Visible; buttonOpenFolder.Visibility = Visibility.Collapsed; textBoxSearch.TextChanged -= TextBoxSearch_TextChanged; #if TODO pictureBoxMenuAlwaysOpen.Paint -= PictureBoxMenuAlwaysOpen_Paint; pictureBoxMenuAlwaysOpen.Paint += LoadingMenu_Paint; timerUpdateIcons.Tick -= TimerUpdateIcons_Tick; timerUpdateIcons.Tick += (sender, e) => pictureBoxMenuAlwaysOpen.Invalidate(); timerUpdateIcons.Interval = 15; #endif break; default: break; } } internal string GetSearchText() { return textBoxSearch.Text; } internal void SetSearchText(string userSearchText) { if (!string.IsNullOrEmpty(userSearchText)) { textBoxSearch.Text = userSearchText + "*"; #if TODO isSetSearchText = true; #endif } } internal bool IsMouseOn() { Point mousePos = NativeMethods.Screen.CursorPosition; bool isMouseOn = Visibility == Visibility.Visible && mousePos.X >= 0 && mousePos.X < Width && mousePos.Y >= 0 && mousePos.Y < Height; return isMouseOn; } internal ListView? GetDataGridView() // TODO WPF Replace Forms wrapper { return dgv; } internal void AdjustControls(string title, MenuDataValidity menuDataValidity) { if (!string.IsNullOrEmpty(title) && Config.ShowDirectoryTitleAtTop) { if (title.Length > MenuDefines.LengthMax) { title = $"{title[..MenuDefines.LengthMax]}..."; } txtTitle.Text = title; } else { txtTitle.Text = string.Empty; } if (!Config.ShowSearchBar) { searchPanel.Visibility = Visibility.Collapsed; panelLine.Visibility = Visibility.Collapsed; } if (!Config.ShowCountOfElementsBelow && menuDataValidity == MenuDataValidity.Valid) { labelItems.Visibility = Visibility.Collapsed; } if (!Config.ShowFunctionKeyOpenFolder) { buttonOpenFolder.Visibility = Visibility.Collapsed; } if (!Config.ShowFunctionKeyPinMenu) { buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed; } if (!Config.ShowFunctionKeySettings) { buttonSettings.Visibility = Visibility.Collapsed; } if (!Config.ShowFunctionKeyRestart) { buttonRestart.Visibility = Visibility.Collapsed; } } internal void ShowWithFadeOrTransparent(bool formActiveFormIsMenu) { if (formActiveFormIsMenu) { ShowWithFade(); } else { ShowTransparent(); } } internal void ShowWithFade() { fading.Fade(Fading.FadingState.Show); } internal void ShowTransparent() { fading.Fade(Fading.FadingState.ShowTransparent); } internal void HideWithFade() { if (!isShowing) { fading.Fade(Fading.FadingState.Hide); } } internal void TimerUpdateIconsStart() { timerUpdateIcons.Start(); } #if TODO // Hack for a pseudo Refresh private delegate void NoArgDelegate(); #endif /// /// Update the position and size of the menu. /// /// Screen coordinates where the menu is allowed to be drawn in. /// Predecessor menu (when available). /// Defines where the first menu is drawn (when no predecessor is set). /// isCustomLocationOutsideOfScreen. internal void AdjustSizeAndLocation( Rectangle bounds, Menu menuPredecessor, StartLocation startLocation, bool isCustomLocationOutsideOfScreen) { // Update the height and width AdjustDataGridViewHeight(menuPredecessor, bounds.Height); AdjustDataGridViewWidth(); #if TODO // Hack for a pseudo Refresh this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, (NoArgDelegate)delegate { }); #endif bool useCustomLocation = Properties.Settings.Default.UseCustomLocation || lastLocation.X > 0; bool changeDirectionWhenOutOfBounds = true; if (menuPredecessor != null) { // Ignore start as we use predecessor startLocation = StartLocation.Predecessor; } else if (useCustomLocation && !isCustomLocationOutsideOfScreen) { // Do not adjust location again because Cursor.Postion changed if (Tag != null) { return; } // Use this menu as predecessor and overwrite location with CustomLocation menuPredecessor = this; Tag = new RowData(); Left = Properties.Settings.Default.CustomLocationX; Top = Properties.Settings.Default.CustomLocationY; directionToRight = true; startLocation = StartLocation.Predecessor; changeDirectionWhenOutOfBounds = false; } else if (Properties.Settings.Default.AppearAtMouseLocation) { // Do not adjust location again because Cursor.Postion changed if (Tag != null) { return; } // Use this menu as predecessor and overwrite location with Cursor.Postion menuPredecessor = this; Tag = new RowData(); var position = Mouse.GetPosition(this); Left = position.X; Top = position.Y - labelTitle.Height; directionToRight = true; startLocation = StartLocation.Predecessor; changeDirectionWhenOutOfBounds = false; } Loaded += (_, _) => { // Calculate X position double x; switch (startLocation) { case StartLocation.Predecessor: double scaling = Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero); directionToRight = menuPredecessor!.directionToRight; // try keeping same direction if (directionToRight) { x = menuPredecessor.Location.X + menuPredecessor.Width - scaling; if (changeDirectionWhenOutOfBounds && bounds.X + bounds.Width <= x + Width - scaling) { x = menuPredecessor.Location.X - Width + scaling; if (x < bounds.X && menuPredecessor.Location.X + menuPredecessor.Width < bounds.X + bounds.Width && bounds.X + (bounds.Width / 2) > menuPredecessor.Location.X + (Width / 2)) { x = bounds.X + bounds.Width - Width + scaling; } else { if (x < bounds.X) { x = bounds.X; } directionToRight = !directionToRight; } } } else { x = menuPredecessor.Location.X - Width + scaling; if (changeDirectionWhenOutOfBounds && x < bounds.X) { x = menuPredecessor.Location.X + menuPredecessor.Width - scaling; if (x + Width > bounds.X + bounds.Width && menuPredecessor.Location.X > bounds.X && bounds.X + (bounds.Width / 2) < menuPredecessor.Location.X + (Width / 2)) { x = bounds.X; } else { if (x + Width > bounds.X + bounds.Width) { x = bounds.X + bounds.Width - Width + scaling; } directionToRight = !directionToRight; } } } break; case StartLocation.BottomLeft: x = bounds.X; directionToRight = true; break; case StartLocation.TopRight: case StartLocation.BottomRight: default: x = bounds.Width - Width; directionToRight = false; break; } // X position for click, remove width of this menu as it is used as predecessor if (menuPredecessor == this && directionToRight) { x -= Width; } if (Level != 0 && !Properties.Settings.Default.AppearNextToPreviousMenu && menuPredecessor != null && menuPredecessor.Width > Properties.Settings.Default.OverlappingOffsetPixels) { if (directionToRight) { x = x - menuPredecessor.Width + Properties.Settings.Default.OverlappingOffsetPixels; } else { x = x + menuPredecessor.Width - Properties.Settings.Default.OverlappingOffsetPixels; } } // Calculate Y position double y; switch (startLocation) { case StartLocation.Predecessor: RowData trigger = (RowData)Tag; ListView dgv = menuPredecessor!.GetDataGridView()!; // Set position on same height as the selected row from predecessor y = menuPredecessor.Location.Y; if (dgv.Items.Count > trigger.RowIndex) { ListViewItem? lvi = dgv.FindVisualChildOfType(trigger.RowIndex); if (lvi != null) { y += menuPredecessor.GetRelativeChildPositionTo(lvi).Y; } } // when warning is shown, the title should appear at same height as selected row if (searchPanel.Visibility != Visibility.Visible) { y += labelTitle.ActualHeight; } // Move vertically when out of bounds if (bounds.Y + bounds.Height < y + Height) { y = bounds.Y + bounds.Height - Height; } break; case StartLocation.TopRight: y = bounds.Y; break; case StartLocation.BottomLeft: case StartLocation.BottomRight: default: y = bounds.Height - Height; break; } // Update position Left = x; Top = y; if (Properties.Settings.Default.RoundCorners) { windowFrame.CornerRadius = new CornerRadius(CornerRadius); } }; } internal void AdjustScrollbar() { #if TODO if (dgv.Rows.Count > 0) { customScrollbar.Value = (int)Math.Round( dgv.FirstDisplayedScrollingRowIndex * (decimal)customScrollbar.Maximum / dgv.Rows.Count, 0, MidpointRounding.AwayFromZero); } #endif } internal void ResetHeight() { #if TODO dgvHeightSet = false; #endif } internal void SetCounts(int foldersCount, int filesCount) { int filesAndFoldersCount = foldersCount + filesCount; string elements = filesAndFoldersCount == 1 ? "element" : "elements"; labelItems.Content = $"{filesAndFoldersCount} {Translator.GetText(elements)}"; } #if TODO protected override bool ProcessCmdKey(ref Message msg, Key keys) { switch (keys) { case Key.Enter: case Key.Home: case Key.End: case Key.Up: case Key.Down: case Key.Left: case Key.Right: case Key.Escape: case Key.Alt | Key.F4: case Key.Control | Key.F: case Key.Tab: case Key.Tab | Key.Shift: case Key.Apps: CmdKeyProcessed.Invoke(this, keys); return true; default: break; } return base.ProcessCmdKey(ref msg, keys); } #endif private void AdjustDataGridViewHeight(Menu menuPredecessor, double screenHeightMax) { double factor = Properties.Settings.Default.RowHeighteInPercentage / 100f; if (NativeMethods.IsTouchEnabled()) { factor = Properties.Settings.Default.RowHeighteInPercentageTouch / 100f; } if (menuPredecessor == null) { if (dgv.Tag == null && dgv.Items.Count > 0) { // dgv.AutoResizeRows(); slightly incorrect depending on dpi // 100% = 20 instead 21 // 125% = 23 instead 27, 150% = 28 instead 32 // 175% = 33 instead 37, 200% = 35 instead 42 // #418 use 21 as default and scale it manually double rowHeightDefault = 21.24f * Scaling.FactorByDpi; Resources["RowHeight"] = (double)((rowHeightDefault * factor * Scaling.Factor) + 0.5); dgv.Tag = true; } } else { // Take over the height from predecessor menu Resources["RowHeight"] = (double)menuPredecessor.Resources["RowHeight"]; dgv.Tag = true; } #if TODO if (!dgvHeightSet && dgvHeightByItems > 0 && dgvHeightMax > 0) { #endif double heightMaxByOptions = Scaling.Factor * Scaling.FactorByDpi * 450f * (Properties.Settings.Default.HeightMaxInPercent / 100f); MaxHeight = Math.Min(screenHeightMax, heightMaxByOptions); #if TODO dgvHeightSet = true; } #endif #if TODO if (dgvHeightByItems > dgvHeightMax) { ScrollbarVisible = true; customScrollbar.PaintEnable(dgv.Height); if (customScrollbar.Maximum != dgvHeightByItems) { customScrollbar.Reset(); customScrollbar.Minimum = 0; customScrollbar.Maximum = dgvHeightByItems; customScrollbar.LargeChange = dgvHeightMax; customScrollbar.SmallChange = Resources["RowHeight"]; } } else { ScrollbarVisible = false; customScrollbar.PaintDisable(); } #endif } private void AdjustDataGridViewWidth() { if (!string.IsNullOrEmpty(textBoxSearch.Text)) { return; } double factorIconSizeInPercent = Properties.Settings.Default.IconSizeInPercent / 100f; // IcoWidth 100% = 21px, 175% is 33, +3+2 is padding from ColumnIcon double icoWidth = (16 * Scaling.FactorByDpi) + 5; Resources["ColumnIconWidth"] = (double)((icoWidth * factorIconSizeInPercent * Scaling.Factor) + 0.5); double renderedMaxWidth = 0D; foreach (ListViewItemData item in dgv.Items) { double renderedWidth = new FormattedText( item.ColumnText, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface(dgv.FontFamily, dgv.FontStyle, dgv.FontWeight, dgv.FontStretch), dgv.FontSize, dgv.Foreground, VisualTreeHelper.GetDpi(this).PixelsPerDip).Width; if (renderedWidth > renderedMaxWidth) { renderedMaxWidth = renderedWidth; } } #if TODO // Lazy value setting because of DataBinging but too late for Menues.AdjustSizeAndLocation() renderedMaxWidth = Math.Min( renderedMaxWidth, (double)(Scaling.Factor * Scaling.FactorByDpi * 400f * (Properties.Settings.Default.WidthMaxInPercent / 100f))); for (int i = 0; i < dgv.Items.Count; i++) { ListViewItem? lvi = dgv.FindVisualChildOfType(i); if (lvi != null) { Label? columnTextLabel = lvi.FindVisualChildOfType