【问题标题】:Prevent ComboBox to expand acording to selected item防止 ComboBox 根据所选项目展开
【发布时间】:2017-10-09 03:37:30
【问题描述】:

我想防止 ComboBox 根据所选项目的大小调整大小。考虑这个简化的例子:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="150" Width="300">
    <GroupBox Header="Group Header" Margin="5">
        <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <ComboBox MinWidth="100" Grid.Column="0" Margin="5" MaxWidth="150"/>
                <ComboBox Grid.Column="1" Margin="5" MinWidth="110">
                    <ComboBoxItem Content="Very loooooooooooooooooooooooooooooooooooooooong text"/>
                    <ComboBoxItem Content="Normal text"/>
                </ComboBox>
            </Grid>
        </ScrollViewer>
    </GroupBox>
</Window>

当您选择第二个 ComboBox 中的第一个项目时,该 ComboBox 会展开,以便所选项目的全部内容适合,从左侧隐藏 ComboBox

我想实现三件事:

  • 拥有滚动查看器,使控件适合其最小尺寸
  • 如果 Window 很大,我希望第二个 ComboBox 适合剩余的大小
  • 如果我在第二个 ComboBox 中选择了一个很长的项目,我希望它保持原来的大小并且调整为所选项目的内容

有可能吗?

【问题讨论】:

  • 删除scrollViewer 即可满足您的所有需求。
  • @RohitVats 我无法删除 ScrollViewer,因为它是 Window 的一小部分,可能没有足够的空间容纳所有控件

标签: c# wpf layout


【解决方案1】:

编辑:

我再次查看了这个问题,发现比之前提出的解决方案要简单得多。这个想法是重写 ComboBox 类的 MeasureOverride 函数并提供有限的可用空间,其中宽度等于 ComboBox 的 MinWidth 属性。为此,我们创建了 ComboBox 派生类:

public class MyComboBox
        : ComboBox
{
    protected override Size MeasureOverride(Size constraint)
    {
        return base.MeasureOverride(new Size(MinWidth, constraint.Height));
    }
}

然后我们在控件中使用它来代替将 Horizo​​ntalContentAlignment 设置为 Stretch 的 ComboBox:

<local:MyComboBox Grid.Column="1" Margin="5" MinWidth="110"
                                  HorizontalContentAlignment="Stretch">
    <ComboBoxItem Content="Very loooooooooooooooooooooooooooooooooooooooong text"/>
    <ComboBoxItem Content="Normal text"/>
</local:MyComboBox>


之前提出的,太复杂的解决方案:

您可以将第二个ComboBox的MaxWidth属性绑定到剩余的空间(可以计算):

<Window x:Class="Example.MainWindow"
        xmlns:local="clr-namespace:Example"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="150" Width="300">

    <Window.Resources>
        <local:SubstractConverter x:Key="SubstractConverter"/>
    </Window.Resources>

    <GroupBox Header="Group Header" Margin="5">
        <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
                      x:Name="ScrollViewer1">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <ComboBox MinWidth="100" Grid.Column="0" Margin="5" MaxWidth="150"
                              x:Name="ComboBox1"/>

                <ComboBox Grid.Column="1" Margin="5" MinWidth="110">
                    <ComboBox.MaxWidth>
                        <MultiBinding Converter="{StaticResource SubstractConverter}">
                            <Binding ElementName="ScrollViewer1" Path="ActualWidth"/>
                            <Binding ElementName="ComboBox1" Path="ActualWidth"/>
                            <Binding ElementName="ComboBox1" Path="Margin.Left"/>
                            <Binding ElementName="ComboBox1" Path="Margin.Right"/>
                            <Binding Path="Margin.Left" RelativeSource="{RelativeSource Self}"/>
                            <Binding Path="Margin.Right" RelativeSource="{RelativeSource Self}"/>
                        </MultiBinding>
                    </ComboBox.MaxWidth>

                    <ComboBoxItem Content="Very loooooooooooooooooooooooooooooooooooooooong text"/>
                    <ComboBoxItem Content="Normal text"/>
                </ComboBox>
            </Grid>
        </ScrollViewer>
    </GroupBox>
</Window>

我从滚动查看器的 ActualWidth 中减去第一个组合框的 ActualWidth、它的边距和第二个组合框的边距。为了减少要减去的元素,您可以在 ComboBox1 周围放置一个边框。然后,您将减去边框的 ActualWidth 而不是 ComboBox1 属性。

这里使用的转换器:

public class SubstractConverter
        : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values != null && values.Any())
        {
            var result = System.Convert.ToDouble(values.First());
            var toSubstract = values.Skip(1);

            foreach (var number in toSubstract)
            {
                result -= System.Convert.ToDouble(number);
            }
            return result;
        }
        return 0d;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

【讨论】:

  • 感谢您的回答。我期待一些更简单的东西,但看起来这将是处理它的方法。我会稍等一下,看看是否有人提供了更好的解决方案,但如果没有,我会很乐意接受你的回答: )
  • 我已经更新了我的解决方案。如果您仍然感兴趣,现在应该会简单得多。
  • 谢谢。一个小问题:我必须设置 MinWidth 属性,对吧?
  • 您不必这样做。 MinWidth 属性仅说明允许减少多少组合框宽度。如果不设置,在将窗口缩小后,组合框会变得很窄,看不到任何文字。
  • 哦,我以为我必须设置一些值 MinWidth 因为您的代码使用该属性。我不确定 MinWidth 是否默认为某个非零值。
【解决方案2】:

我在 ScrollViewer 中的 ComboBox 也遇到了同样的问题。我不想要水平滚动,只想要垂直滚动。但是 ComboBox 不断调整自身的大小以适应所选项目。我使用了 aligators 的答案,但将 MinWidth 替换为 ActualWidth 以防止 CombobBox 自行调整大小,但所选项目将始终使用可用空间。

public class FixedWidthComboBox : ComboBox
{
    protected override Size MeasureOverride(Size constraint)
    {
        return base.MeasureOverride(new Size(ActualWidth, constraint.Height));
    }
}

【讨论】:

    猜你喜欢
    • 2015-02-18
    • 2017-06-01
    • 1970-01-01
    • 2011-04-19
    • 2023-03-10
    • 2016-10-02
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    相关资源
    最近更新 更多