WPF 可见性折叠保留空间

Posted

技术标签:

【中文标题】WPF 可见性折叠保留空间【英文标题】:WPF visibility collapse keep space 【发布时间】:2020-12-10 21:12:53 【问题描述】:

我有 3 列,在使用特定转换器时,我成功地将中间列和右列的可见性更改为可见性折叠或可见。

我的问题是,当这些列应该可见时,我希望它们具有星号宽度,而折叠宽度必须为自动。

然后,如果它们的可见性可见,我的所有列都共享相同的空间,否则她将占据所有空间并且可以居中到父级。

我设置了我的可见性转换器

internal class TradeUnitLevelToVisibilityConverter : BaseConverter, IValueConverter

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        return value != null && (TradeUnit)value == TradeUnit.Unit
            ? Visibility.Collapsed
            : Visibility.Visible;
    

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        return null;
    

我的宽度转换器

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        return value != null && (TradeUnit)value == TradeUnit.Unit
            ? new GridLength(0, GridUnitType.Auto)
            : new GridLength(5, GridUnitType.Star);
    

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        return null;
    

我的 xaml :

       <Grid Grid.Column="1" Background="StaticResource Black3C3D41Brush">
            <Grid Grid.Column="1" HorizontalAlignment="Stretch">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.5*"/>
                    <ColumnDefinition Width="2.5*"/>
                    <ColumnDefinition >
                        <!--<ColumnDefinition.Style>
                            <Style TargetType="ColumnDefinition">
                                <Setter Property="Width" Value="*"/>
                                <Style.Triggers>
                                    <DataTrigger Binding="Binding , Converter=eshopeur:TradeUnitLevelToVisibilityConverter" Value="Unit">
                                        <Setter Property="Width" Value="auto"/>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </ColumnDefinition.Style>-->
                    </ColumnDefinition>
                    <ColumnDefinition >
                        <!--<ColumnDefinition.Style>
                            <Style TargetType="ColumnDefinition">
                                <Setter Property="Width" Value="2.5*"/>
                                <Style.Triggers>
                                    <DataTrigger Binding="Binding , Converter=eshopeur:TradeUnitLevelToVisibilityConverter" Value="Collapsed">
                                        <Setter Property="Width" Value="auto"/>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </ColumnDefinition.Style>-->
                    </ColumnDefinition>
                    <ColumnDefinition Width="0.5*"/>
                </Grid.ColumnDefinitions>

                <Grid Grid.Column="1" HorizontalAlignment="Center">
                    
                    ...
                    
                </Grid>
                <Grid Grid.Column="2"  Visibility="Binding UnitTradeUnitlevel, 
                        Converter=eshopeur:TradeUnitLevelToVisibilityConverter"  
                      HorizontalAlignment="Stretch"
                      Width="Binding UnitTradeUnitlevel, Converter=auxilaryscreen:UnitTradeUnitToVisibilityConverter" >

                    <Grid>
                        ...
                </Grid>
                <Grid Grid.Column="3"  HorizontalAlignment="Stretch" 
                      Width="Binding UnitTradeUnitlevel, Converter=auxilaryscreen:UnitTradeUnitToVisibilityConverter" 
                      Visibility="Binding UnitTradeUnitlevel, Converter=eshopeur:TradeUnitLevelToVisibilityConverter">
                    
                     ...
                   
                </Grid>
            </Grid>
        </Grid>

我尝试使用触发器,但我不知道如何正确设置它们,因为他们正在检查可见性转换器以适应宽度。

这是我所期望的 虽然都可见

all visible

折叠时

collapse

我的实际结果是崩溃:

today collapse result

你有什么办法可以同时改变列的可见性和宽度吗?

【问题讨论】:

Visibility.Hidden代替Visibility.Collapsed怎么样? .Hidden 也会保留列空间。如果我成功将列的宽度设置为 auto 而不是 * 当可见性折叠时,visibility.Collapse 将正确忽略空格。 您可以尝试使用 jagged arrays 布局:代替带有行和列的类似表格的顶部容器定义一个或多个列表,其中每一行是单元格的另一个容器。这将为您提供更大的灵活性(例如,您将能够通过折叠单元格来占据所有可用宽度),但现在您将遇到另一个问题:如何在行之间同步单元格宽度。 【参考方案1】:

最后我更改了我的 xaml 树和一个转换器:当一列可见时,另一列不可见,全部设置为 width = auto。

它似乎可以完成这项工作,如果我能找到更清洁的解决方案,那就太好了。如果有人已经用我感兴趣的触发器做到了。

【讨论】:

【参考方案2】:

实现结果的一种方法是为列定义创建附加行为。

附加的行为是一个带有 3 个附加属性的静态类。您可以更改名称以使其真正有意义。

DefaultWidth - 列定义的默认宽度 UnitWidth - 当TradeUnitUnit 时列定义的宽度 TradeUnit - 贸易单位

TradeUnit 更改时,行为会将列定义的Width 设置为正确的值DefaultWidthUnitWidth

using System.Windows;
using System.Windows.Controls;

namespace SO

    public static class TradeUnitColumnWidthBehavior
    
        #region DefaultWidth (Attached Property)
        public static readonly DependencyProperty DefaultWidthProperty =
            DependencyProperty.RegisterAttached(
                "DefaultWidth",
                typeof(GridLength),
                typeof(TradeUnitColumnWidthBehavior),
                new PropertyMetadata(null));

        public static GridLength GetDefaultWidth(DependencyObject obj)
        
            return (GridLength)obj.GetValue(DefaultWidthProperty);
        

        public static void SetDefaultWidth(DependencyObject obj, GridLength value)
        
            obj.SetValue(DefaultWidthProperty, value);
        
        #endregion

        #region UnitWidth (Attached Property)
        public static readonly DependencyProperty UnitWidthProperty =
            DependencyProperty.RegisterAttached(
                "UnitWidth",
                typeof(GridLength),
                typeof(TradeUnitColumnWidthBehavior),
                new PropertyMetadata(null));

        public static GridLength GetUnitWidth(DependencyObject obj)
        
            return (GridLength)obj.GetValue(UnitWidthProperty);
        

        public static void SetUnitWidth(DependencyObject obj, GridLength value)
        
            obj.SetValue(UnitWidthProperty, value);
        
        #endregion

        #region TradeUnit (Attached Property)
        public static readonly DependencyProperty TradeUnitProperty =
            DependencyProperty.RegisterAttached(
                "TradeUnit",
                typeof(MainWindowViewModel.TradeUnit),
                typeof(TradeUnitColumnWidthBehavior),
                new PropertyMetadata(MainWindowViewModel.TradeUnit.None, OnTradeUnitChanged));

        public static MainWindowViewModel.TradeUnit GetTradeUnit(DependencyObject obj)
        
            return (MainWindowViewModel.TradeUnit)obj.GetValue(TradeUnitProperty);
        

        public static void SetTradeUnit(DependencyObject obj, MainWindowViewModel.TradeUnit value)
        
            obj.SetValue(TradeUnitProperty, value);
        

        private static void OnTradeUnitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var columnDefinition = (ColumnDefinition)d;
            if (columnDefinition == null) return;

            if ((MainWindowViewModel.TradeUnit) e.NewValue == MainWindowViewModel.TradeUnit.Unit)
            
                columnDefinition.Width = GetUnitWidth(d);
            
            else
            
                columnDefinition.Width = GetDefaultWidth(d);
            
        
        #endregion
    


这是 XAML 的一个示例:

<Grid ShowGridLines="True">
    <!--    -->
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="0.5*" />
        <ColumnDefinition Width="2.5*" 
            local:TradeUnitColumnWidthBehavior.DefaultWidth="2.5*" 
            local:TradeUnitColumnWidthBehavior.TradeUnit="Binding RelativeSource=RelativeSource AncestorType=x:Type Grid, Path=DataContext.UnitTradeUnitLevel" 
            local:TradeUnitColumnWidthBehavior.UnitWidth="*" />
        <ColumnDefinition Width="1.5*" 
            local:TradeUnitColumnWidthBehavior.DefaultWidth="1.5*" 
            local:TradeUnitColumnWidthBehavior.TradeUnit="Binding RelativeSource=RelativeSource AncestorType=x:Type Grid, Path=DataContext.UnitTradeUnitLevel" 
            local:TradeUnitColumnWidthBehavior.UnitWidth="Auto" />
        <ColumnDefinition Width="2.5*" 
            local:TradeUnitColumnWidthBehavior.DefaultWidth="2.5*" 
            local:TradeUnitColumnWidthBehavior.TradeUnit="Binding RelativeSource=RelativeSource AncestorType=x:Type Grid, Path=DataContext.UnitTradeUnitLevel" 
            local:TradeUnitColumnWidthBehavior.UnitWidth="Auto" />
        <ColumnDefinition Width="0.5*" />
    </Grid.ColumnDefinitions>
    <Border x:Name="Border1"
        Grid.Column="1"
        Background="Red">
        <Button
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Command="Binding TradeUnitCommand"
            Content="Change Unit" />
    </Border>
    <Border
        Grid.Column="2"
        Background="Green"
        Visibility="Binding UnitTradeUnitLevel, Converter=StaticResource TradeUnitLevelToVisibilityConverter" />
    <Border
        Grid.Column="3"
        Background="Blue"
        Visibility="Binding UnitTradeUnitLevel, Converter=StaticResource TradeUnitLevelToVisibilityConverter" />
</Grid>

【讨论】:

以上是关于WPF 可见性折叠保留空间的主要内容,如果未能解决你的问题,请参考以下文章

WPF ComboBoxItem 内的折叠可见性

WPF XAML 网格可见性触发器

WPF:尝试根据组合框中的选择更改可见性

WPF绑定到Listview的Itemtemplate的可见性不起作用[重复]

flexbox 中的可见性:隐藏和可见性:折叠有啥区别?

如何设置绑定到文本框的标签的可见性?