Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Settings] Fix flyout position when ComboBox is aligned to the right #31

Merged
merged 7 commits into from
Feb 19, 2023
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Automation.Provider;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.Xaml.Interactivity;
using Windows.Foundation.Collections;

namespace Natsurainko.FluentLauncher.Behaviors
{
class SetComboBoxWidthFromItemsBehavior : Behavior<ComboBox>
{
public static readonly DependencyProperty SetComboBoxWidthFromItemsProperty =
DependencyProperty.RegisterAttached
(
"SetComboBoxWidthFromItems",
typeof(bool),
typeof(SetComboBoxWidthFromItemsBehavior),
new PropertyMetadata(false, OnSetComboBoxWidthFromItemsPropertyChanged)
);

public bool SetComboBoxWidthFromItems
{
get => (bool)GetValue(SetComboBoxWidthFromItemsProperty);
set => SetValue(SetComboBoxWidthFromItemsProperty, value);
}

protected override void OnAttached()
{
AssociatedObject.Loaded += OnComboBoxLoaded;
AssociatedObject.Items.VectorChanged += Items_VectorChanged;
}

public void Items_VectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs e)
{
SetComboBoxWidth(AssociatedObject);
}

private static void OnComboBoxLoaded(object sender, RoutedEventArgs e)
{
SetComboBoxWidth((ComboBox)sender);
}

private static void OnSetComboBoxWidthFromItemsPropertyChanged(
DependencyObject dpo,
DependencyPropertyChangedEventArgs e)
{
SetComboBoxWidthFromItemsBehavior behavior = (SetComboBoxWidthFromItemsBehavior)dpo;
ComboBox comboBox = behavior.AssociatedObject;

bool newValue = (bool)e.NewValue;
bool oldValue = (bool)e.OldValue;

if (comboBox != null && newValue != oldValue)
{
if (newValue == true)
{
comboBox.Loaded += OnComboBoxLoaded;
comboBox.Items.VectorChanged += behavior.Items_VectorChanged;

}
else
{
comboBox.Loaded -= OnComboBoxLoaded;
comboBox.Items.VectorChanged -= behavior.Items_VectorChanged;
}
}
}

/// <summary>
/// Set the width of a ComboBox to the longest item in its drop down menu
/// </summary>
/// <param name="comboBox">Target</param>
private static void SetComboBoxWidth(ComboBox comboBox)
{
// Open ComboBox drop down and prepare ItemContainerGenerator
comboBox.IsDropDownOpen = true;
comboBox.ItemContainerGenerator.StartAt(new GeneratorPosition(0, 0), GeneratorDirection.Forward, true);

double maxWidth = 0;
ComboBoxItem? item;
while ((item = comboBox.ItemContainerGenerator.GenerateNext(out _) as ComboBoxItem) != null)
{
item.Measure(new Windows.Foundation.Size(double.PositiveInfinity, double.PositiveInfinity));
var size = item.DesiredSize;
if (size.Width > maxWidth)
{
maxWidth = size.Width;
}
}

maxWidth += 20; // This constant adds more space to include the drop down button and paddings
comboBox.Width = maxWidth > 70 ? maxWidth : 70; // Ensures a MinWidth of 70 when there is no content; Less width will result in issues with appearance
comboBox.ItemContainerGenerator.Stop();
comboBox.IsDropDownOpen = false;
}
}
}
11 changes: 8 additions & 3 deletions Natsurainko.FluentLauncher/Views/Pages/Settings/Launch.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
xmlns:local="using:Natsurainko.FluentLauncher.Views.Pages.Settings"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:Natsurainko.FluentLauncher.ViewModels.Pages.Settings"
xmlns:behaviors ="using:Natsurainko.FluentLauncher.Behaviors"
Background="Transparent"
xmlns:i="using:Microsoft.Xaml.Interactivity"
mc:Ignorable="d">
<Page.DataContext>
<vm:Launch />
Expand Down Expand Up @@ -41,19 +43,23 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="15" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" x:Name="container1"/>
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="Settings_Launch_Item_1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="Current .minecraft folder:" />
<ComboBox
Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FlowDirection="RightToLeft"
ItemsSource="{Binding GameFolders}"
MaxWidth="{Binding ElementName=container1, Path=ActualWidth, Mode=OneTime}"
SelectedItem="{Binding CurrentGameFolder, Mode=TwoWay}">
<i:Interaction.Behaviors>
<behaviors:SetComboBoxWidthFromItemsBehavior SetComboBoxWidthFromItems="True"/>
</i:Interaction.Behaviors>
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{Binding}" TextTrimming="CharacterEllipsis" />
Expand Down Expand Up @@ -151,7 +157,6 @@
Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FlowDirection="RightToLeft"
ItemsSource="{Binding JavaRuntimes}"
SelectedItem="{Binding CurrentJavaRuntime, Mode=TwoWay}">
<ComboBox.ItemTemplate>
Expand Down