WPF:如何使用 XAML 隐藏 GridViewColumn?

发布于 2024-07-16 20:29:31 字数 530 浏览 7 评论 0原文

我在 App.xaml 中有以下对象

<Application.Resources>
        <ResourceDictionary>
            <GridView x:Key="myGridView" x:Shared="false">
                             <GridViewColumn Header="Created" DisplayMemberBinding="{Binding Path=Created}"/>

... more code ...

,并且我在多个地方使用此网格视图。 示例:

<ListView x:Name="detailList"   View="{StaticResource myGridView}" ...>

在其中一种用法(例如上面的detailList)中,我想隐藏Created 列,可能使用XAML 吗?

有任何想法吗?

I have the following object in App.xaml

<Application.Resources>
        <ResourceDictionary>
            <GridView x:Key="myGridView" x:Shared="false">
                             <GridViewColumn Header="Created" DisplayMemberBinding="{Binding Path=Created}"/>

... more code ...

And I use this grid view in multiple places. Example:

<ListView x:Name="detailList"   View="{StaticResource myGridView}" ...>

In one of the usages (such as detailList above), I'd like to hide the Created column, possibly using XAML?

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

丑丑阿 2024-07-23 20:29:31

实际上,我发现最简单的解决方案是通过附加属性:

public class GridViewColumnVisibilityManager
{       
    static void UpdateListView(ListView lv)
    {
        GridView gridview = lv.View as GridView;
        if (gridview == null || gridview.Columns == null) return;
        List<GridViewColumn> toRemove = new List<GridViewColumn>();
        foreach (GridViewColumn gc in gridview.Columns)
        {
            if (GetIsVisible(gc) == false)
            {
                toRemove.Add(gc);
            }
        }
        foreach (GridViewColumn gc in toRemove)
        {
            gridview.Columns.Remove(gc);
        }
    }

    public static bool GetIsVisible(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsVisibleProperty);
    }

    public static void SetIsVisible(DependencyObject obj, bool value)
    {
        obj.SetValue(IsVisibleProperty, value);
    }

    public static readonly DependencyProperty IsVisibleProperty =
        DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(true));


    public static bool GetEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnabledProperty);
    }

    public static void SetEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(EnabledProperty, value);
    }

    public static readonly DependencyProperty EnabledProperty =
        DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(false,
            new PropertyChangedCallback(OnEnabledChanged)));

        private static void OnEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        ListView view = obj as ListView;
        if (view != null)
        {
            bool enabled = (bool)e.NewValue;
            if (enabled)
            {
                view.Loaded += (sender, e2) =>
                {
                    UpdateListView((ListView)sender);
                };
                view.TargetUpdated += (sender, e2) =>
                {
                    UpdateListView((ListView)sender);
                };
                view.DataContextChanged += (sender, e2) =>
                {
                    UpdateListView((ListView)sender);
                };
            }
        }
    }
}

然后,它可以这样使用:

<ListView foo:GridViewColumnVisibilityManager.Enabled="True">
...
<GridViewColumn Header="Status" foo:GridViewColumnVisibilityManager.IsVisible="{Binding ShowStatusColumn}">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate> ...

Actually, I find the easiest solution is via attached properties:

public class GridViewColumnVisibilityManager
{       
    static void UpdateListView(ListView lv)
    {
        GridView gridview = lv.View as GridView;
        if (gridview == null || gridview.Columns == null) return;
        List<GridViewColumn> toRemove = new List<GridViewColumn>();
        foreach (GridViewColumn gc in gridview.Columns)
        {
            if (GetIsVisible(gc) == false)
            {
                toRemove.Add(gc);
            }
        }
        foreach (GridViewColumn gc in toRemove)
        {
            gridview.Columns.Remove(gc);
        }
    }

    public static bool GetIsVisible(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsVisibleProperty);
    }

    public static void SetIsVisible(DependencyObject obj, bool value)
    {
        obj.SetValue(IsVisibleProperty, value);
    }

    public static readonly DependencyProperty IsVisibleProperty =
        DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(true));


    public static bool GetEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnabledProperty);
    }

    public static void SetEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(EnabledProperty, value);
    }

    public static readonly DependencyProperty EnabledProperty =
        DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(false,
            new PropertyChangedCallback(OnEnabledChanged)));

        private static void OnEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        ListView view = obj as ListView;
        if (view != null)
        {
            bool enabled = (bool)e.NewValue;
            if (enabled)
            {
                view.Loaded += (sender, e2) =>
                {
                    UpdateListView((ListView)sender);
                };
                view.TargetUpdated += (sender, e2) =>
                {
                    UpdateListView((ListView)sender);
                };
                view.DataContextChanged += (sender, e2) =>
                {
                    UpdateListView((ListView)sender);
                };
            }
        }
    }
}

Then, it can be used as so:

<ListView foo:GridViewColumnVisibilityManager.Enabled="True">
...
<GridViewColumn Header="Status" foo:GridViewColumnVisibilityManager.IsVisible="{Binding ShowStatusColumn}">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate> ...
盛夏已如深秋| 2024-07-23 20:29:31

基于 Ben McMillan 的答案,但支持动态更改可见属性。
我通过删除 IsEnabled 属性进一步简化了他的解决方案。

public class GridViewColumnVisibilityManager
{
    static Dictionary<GridViewColumn, double> originalColumnWidths = new Dictionary<GridViewColumn, double>();

    public static bool GetIsVisible(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsVisibleProperty);
    }

    public static void SetIsVisible(DependencyObject obj, bool value)
    {
        obj.SetValue(IsVisibleProperty, value);
    }

    public static readonly DependencyProperty IsVisibleProperty =
        DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(true, OnIsVisibleChanged));

    private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        GridViewColumn gc = d as GridViewColumn;
        if (gc == null)
            return;

        if (GetIsVisible(gc) == false)
        {
            originalColumnWidths[gc] = gc.Width;
            gc.Width = 0;
        }
        else
        {
            if (gc.Width == 0)
                gc.Width = originalColumnWidths[gc];
        }
    }
}

Based on Ben McMillan's answer, but supports dynamic changing of visible property.
I've simplified his solution further by removing the IsEnabled property.

public class GridViewColumnVisibilityManager
{
    static Dictionary<GridViewColumn, double> originalColumnWidths = new Dictionary<GridViewColumn, double>();

    public static bool GetIsVisible(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsVisibleProperty);
    }

    public static void SetIsVisible(DependencyObject obj, bool value)
    {
        obj.SetValue(IsVisibleProperty, value);
    }

    public static readonly DependencyProperty IsVisibleProperty =
        DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(true, OnIsVisibleChanged));

    private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        GridViewColumn gc = d as GridViewColumn;
        if (gc == null)
            return;

        if (GetIsVisible(gc) == false)
        {
            originalColumnWidths[gc] = gc.Width;
            gc.Width = 0;
        }
        else
        {
            if (gc.Width == 0)
                gc.Width = originalColumnWidths[gc];
        }
    }
}
一直在等你来 2024-07-23 20:29:31

您最好的选择可能是通过继承 GridView 类、添加所需的列并公开有意义的属性来显示/隐藏特定列来创建自定义控件。 您的自定义 GridView 类可能如下所示:

using System;
using System.Windows.Controls;

namespace MyProject.CustomControls
{
    public class CustomGridView : GridView
    {
        private GridViewColumn _fixedColumn;
        private GridViewColumn _optionalColumn;

        public CustomGridView()
        {
            this._fixedColumn = new GridViewColumn() { Header = "Fixed Column" };
            this._optionalColumn = new GridViewColumn() { Header = "Optional Column" };

            this.Columns.Add(_fixedColumn);
            this.Columns.Add(_optionalColumn);
        }

        public bool ShowOptionalColumn
        {
            get { return _optionalColumn.Width > 0; }
            set
            {
                // When 'False' hides the entire column
                // otherwise its width will be set to 'Auto'
                _optionalColumn.Width = (!value) ? 0 : Double.NaN;
            }
        }

    }
}

然后您可以简单地从 XAML 设置该属性,如下例所示:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cc="clr-namespace:MyProject.CustomControls"
        Title="Window1"
        Height="300"
        Width="300">
    <StackPanel>
        <ListView>
            <ListView.View>
                <cc:CustomGridView ShowOptionalColumn="False" />
            </ListView.View>
        </ListView>

        <ListView>
            <ListView.View>
                <cc:CustomGridView ShowOptionalColumn="True" />
            </ListView.View>
        </ListView>
    </StackPanel>
</Window>

或者,您可以将“CustomGridView.ShowOptionalColumn”设置为 DependencyProperty能够将其用作绑定目标。

You best bet is probably to create a custom control by inheriting from the GridView class, adding the required columns, and exposing a meaningful property to show/hide a particular column. Your custom GridView class could look like this:

using System;
using System.Windows.Controls;

namespace MyProject.CustomControls
{
    public class CustomGridView : GridView
    {
        private GridViewColumn _fixedColumn;
        private GridViewColumn _optionalColumn;

        public CustomGridView()
        {
            this._fixedColumn = new GridViewColumn() { Header = "Fixed Column" };
            this._optionalColumn = new GridViewColumn() { Header = "Optional Column" };

            this.Columns.Add(_fixedColumn);
            this.Columns.Add(_optionalColumn);
        }

        public bool ShowOptionalColumn
        {
            get { return _optionalColumn.Width > 0; }
            set
            {
                // When 'False' hides the entire column
                // otherwise its width will be set to 'Auto'
                _optionalColumn.Width = (!value) ? 0 : Double.NaN;
            }
        }

    }
}

Then you can simply set that property from XAML like in this example:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cc="clr-namespace:MyProject.CustomControls"
        Title="Window1"
        Height="300"
        Width="300">
    <StackPanel>
        <ListView>
            <ListView.View>
                <cc:CustomGridView ShowOptionalColumn="False" />
            </ListView.View>
        </ListView>

        <ListView>
            <ListView.View>
                <cc:CustomGridView ShowOptionalColumn="True" />
            </ListView.View>
        </ListView>
    </StackPanel>
</Window>

Optionally, you could make the 'CustomGridView.ShowOptionalColumn' a DependencyProperty to be able to use it as a binding target.

南城追梦 2024-07-23 20:29:31

摘自此处

<ListView Grid.Column="1" Grid.Row="1"  Name="FicheList" >
            <ListView.Resources>
                <ResourceDictionary>
                    <Style x:Key="hiddenStyle" TargetType="GridViewColumnHeader">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </Style>
                </ResourceDictionary>
            </ListView.Resources>
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding Code}" Header="Code" Width="0" HeaderContainerStyle="{StaticResource hiddenStyle}" />
                    <GridViewColumn DisplayMemberBinding="{Binding FicheTitle}" Header="Title" Width="100" />
                    <GridViewColumn DisplayMemberBinding="{Binding CategoryName}" Header="Category" Width="100" />
                    <GridViewColumn DisplayMemberBinding="{Binding UpdateDate}" Header="Update Date" Width="100" />

                </GridView>
            </ListView.View>
        </ListView>

Taken from here

<ListView Grid.Column="1" Grid.Row="1"  Name="FicheList" >
            <ListView.Resources>
                <ResourceDictionary>
                    <Style x:Key="hiddenStyle" TargetType="GridViewColumnHeader">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </Style>
                </ResourceDictionary>
            </ListView.Resources>
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding Code}" Header="Code" Width="0" HeaderContainerStyle="{StaticResource hiddenStyle}" />
                    <GridViewColumn DisplayMemberBinding="{Binding FicheTitle}" Header="Title" Width="100" />
                    <GridViewColumn DisplayMemberBinding="{Binding CategoryName}" Header="Category" Width="100" />
                    <GridViewColumn DisplayMemberBinding="{Binding UpdateDate}" Header="Update Date" Width="100" />

                </GridView>
            </ListView.View>
        </ListView>
回眸一遍 2024-07-23 20:29:31

我有一个比使用附加行为更简单的解决方案。

您所要做的就是将 GridViewColumn 的 Width 属性绑定到 ViewModel 上的布尔值。 然后创建一个简单的转换器,例如 BooleanToWidthConverter,它接受一个布尔值并返回一个双精度值,如果为假则返回零,如果为真则返回 x 宽度。

我希望这对您有所帮助并使您的生活更轻松。

XAML:

<GridViewColumn x:Name="MyHiddenGridViewColumn"
                Width={Binding Path=IsColumnVisibleProperty, Converter={StaticResource BooleanToWidthConverter}}">
   <!-- GridViewColumn.HeaderTemplate etc. goes here. -->
</GridViewColumn>

转换器:

public class BooleanToWidthConverter : IValueConverter
    {
        private const double Column_Width = 40.0;

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value != null && value != DependencyProperty.UnsetValue)
            {
                bool isVisible = (bool) value;

                return isVisible ? Column_Width : 0;
            }
            return Column_Width;
        }

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

I have a much simpler solution than using an Attached Behavior.

All you have to do is bind the Width Property of the GridViewColumn to a boolean on your ViewModel. Then create a simple Converter like BooleanToWidthConverter that takes a boolean and returns a double, zero if its false, x width if its true.

I hope this helps and makes your life easier.

XAML:

<GridViewColumn x:Name="MyHiddenGridViewColumn"
                Width={Binding Path=IsColumnVisibleProperty, Converter={StaticResource BooleanToWidthConverter}}">
   <!-- GridViewColumn.HeaderTemplate etc. goes here. -->
</GridViewColumn>

Converter:

public class BooleanToWidthConverter : IValueConverter
    {
        private const double Column_Width = 40.0;

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value != null && value != DependencyProperty.UnsetValue)
            {
                bool isVisible = (bool) value;

                return isVisible ? Column_Width : 0;
            }
            return Column_Width;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
囚我心虐我身 2024-07-23 20:29:31

这是我的代码,它在我的项目中运行得很好。 如果您不想添加一些外部代码。

    /// <summary>
    /// show/hide datagrid column
    /// </summary>
    /// <param name="datagrid"></param>
    /// <param name="header"></param>
    private void ToggleDataGridColumnsVisible()
    {
        if (IsNeedToShowHideColumn())
        {
            foreach (GridViewColumn column in ((GridView)(this.ListView1.View)).Columns)
            {
                GridViewColumnHeader header = column.Header as GridViewColumnHeader;
                if (header != null)
                {
                    string headerstring = header.Tag.ToString();

                    if (!IsAllWaysShowingHeader(headerstring ) )
                    {
                        if (IsShowingHeader())
                        {

                        }
                        else
                        {
                            //hide it
                            header.Template = null;
                            column.CellTemplate = null;
                            column.Width = 0;
                        }
                    }
                }

            }

        }
    }

This is my code , it works very well in my project. if you don't like to add some external code.

    /// <summary>
    /// show/hide datagrid column
    /// </summary>
    /// <param name="datagrid"></param>
    /// <param name="header"></param>
    private void ToggleDataGridColumnsVisible()
    {
        if (IsNeedToShowHideColumn())
        {
            foreach (GridViewColumn column in ((GridView)(this.ListView1.View)).Columns)
            {
                GridViewColumnHeader header = column.Header as GridViewColumnHeader;
                if (header != null)
                {
                    string headerstring = header.Tag.ToString();

                    if (!IsAllWaysShowingHeader(headerstring ) )
                    {
                        if (IsShowingHeader())
                        {

                        }
                        else
                        {
                            //hide it
                            header.Template = null;
                            column.CellTemplate = null;
                            column.Width = 0;
                        }
                    }
                }

            }

        }
    }
愁杀 2024-07-23 20:29:31

我建议在父级上使用自定义属性(或劫持现有属性),然后在 gridviewcolumnheader 上使用自定义样式来引用该祖先属性。 像这样:

<Window.Resources>
    <Style TargetType="{x:Type GridViewColumnHeader}">
        <Setter Property="Visibility" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=Tag}"/>
    </Style>
    <GridView x:Key="myGridView" x:Shared="false">                             
        <GridViewColumn Header="Created" DisplayMemberBinding="{Binding Path=Created}"/>    
    </GridView>
</Window.Resources>
<Grid x:Name="LayoutRoot">
    <StackPanel>
        <ListView x:Name="detailList"   View="{StaticResource myGridView}"/>
        <ListView x:Name="detailListHide" Tag="{x:Static Member=Visibility.Hidden}" View="{StaticResource myGridView}"/>
    </StackPanel>
</Grid>

I'd suggest using a custom property (or hijacking an existing one) on the parent and then using a custom style on the gridviewcolumnheader to reference that ancestor property. Like this:

<Window.Resources>
    <Style TargetType="{x:Type GridViewColumnHeader}">
        <Setter Property="Visibility" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=Tag}"/>
    </Style>
    <GridView x:Key="myGridView" x:Shared="false">                             
        <GridViewColumn Header="Created" DisplayMemberBinding="{Binding Path=Created}"/>    
    </GridView>
</Window.Resources>
<Grid x:Name="LayoutRoot">
    <StackPanel>
        <ListView x:Name="detailList"   View="{StaticResource myGridView}"/>
        <ListView x:Name="detailListHide" Tag="{x:Static Member=Visibility.Hidden}" View="{StaticResource myGridView}"/>
    </StackPanel>
</Grid>
情感失落者 2024-07-23 20:29:31

在我编写的一个小实用程序中,我有一个列表视图,用户可以在其中隐藏/显示一些列。 列上没有 Visibility 属性,因此我决定将隐藏列宽度设置为零。 并不理想,因为用户仍然可以调整它们的大小并使它们再次可见。

无论如何,为了做到这一点,我使用了:

<GridViewColumn.Width>
    <MultiBinding Converter="{StaticResource WidthConverter}" Mode="TwoWay">
        <Binding Path="ThreadIdColumnWidth" Mode="TwoWay" />
        <Binding Path="IsThreadIdShown" />
    </MultiBinding>
</GridViewColumn.Width>

IsThreadIdShown 绑定到工具栏上的复选框。
多值转换器为:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
    if (values.Length != 2) {
        return null;
    }

    object o0 = values[0];
    object o1 = values[1];

    if (! (o1 is bool)) {
        return o0;
    }
    bool toBeDisplayed = (bool) o1;
    if (! toBeDisplayed) {
        return 0.0;
    }

    if (! (o0 is double)) {
        return 0;
    }

    return (double) o0;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {

    return new object[] { (double)value, Binding.DoNothing };
}

In a small utility I wrote, I have a list view where the user can hide/show some columns. There is no Visibility property on the columns, so I decided to set the hidden columns width to zero. Not ideal, as the user can still resize them and make them visible again.

Anyway, to do this, I used:

<GridViewColumn.Width>
    <MultiBinding Converter="{StaticResource WidthConverter}" Mode="TwoWay">
        <Binding Path="ThreadIdColumnWidth" Mode="TwoWay" />
        <Binding Path="IsThreadIdShown" />
    </MultiBinding>
</GridViewColumn.Width>

IsThreadIdShown is bound to a check box on the toolbar.
And the multi-value converter is:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
    if (values.Length != 2) {
        return null;
    }

    object o0 = values[0];
    object o1 = values[1];

    if (! (o1 is bool)) {
        return o0;
    }
    bool toBeDisplayed = (bool) o1;
    if (! toBeDisplayed) {
        return 0.0;
    }

    if (! (o0 is double)) {
        return 0;
    }

    return (double) o0;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {

    return new object[] { (double)value, Binding.DoNothing };
}
顾挽 2024-07-23 20:29:31

这对我有用
需要在标题和内容上绑定 Visibility
在本例中,它位于末尾,因此我不必担心宽度
但用户没有获得 UI 挂钩来重置宽度,因此如果将宽度设置为零,它就会消失

<GridViewColumn Width="60">
    <GridViewColumnHeader HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch"
                            Visibility="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.CurUser.IsInRoleSysAdmin, Converter={StaticResource bvc}}">
        <TextBlock>WS<LineBreak/>Count</TextBlock>
    </GridViewColumnHeader>
    <GridViewColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=WordScoreCount, StringFormat={}{0:N0}}" HorizontalAlignment="Right"
                        Visibility="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.CurUser.IsInRoleSysAdmin, Converter={StaticResource bvc}}"/>
        </DataTemplate>
    </GridViewColumn.CellTemplate>
</GridViewColumn>

This works for me
Need to bind the Visibility on both the header and the content
In this case it is at the end so I don't worry about the Width
BUT the user does not get a UI hook to reset the width so if you set the width to zero it is gone

<GridViewColumn Width="60">
    <GridViewColumnHeader HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch"
                            Visibility="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.CurUser.IsInRoleSysAdmin, Converter={StaticResource bvc}}">
        <TextBlock>WS<LineBreak/>Count</TextBlock>
    </GridViewColumnHeader>
    <GridViewColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=WordScoreCount, StringFormat={}{0:N0}}" HorizontalAlignment="Right"
                        Visibility="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.CurUser.IsInRoleSysAdmin, Converter={StaticResource bvc}}"/>
        </DataTemplate>
    </GridViewColumn.CellTemplate>
</GridViewColumn>
岁月静好 2024-07-23 20:29:31
<GridViewColumn Width="{Binding Tag, RelativeSource={RelativeSource AncestorType=ListView}, Converter={converters:BooleanToWidthConverter}, ConverterParameter=100}">
                            <GridViewColumn.HeaderContainerStyle>
                                <Style TargetType="{x:Type GridViewColumnHeader}" BasedOn="{StaticResource ColumnHeaderStyle}">
                                    <Setter Property="IsEnabled" Value="False"/>
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource AncestorType=ListView}}" Value="true">
                                            <Setter Property="IsEnabled" Value="True"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </GridViewColumn.HeaderContainerStyle>
                            <GridViewColumn.Header>
                                <StackPanel Tag="columnHeader" Orientation="Horizontal">
                                </StackPanel>
                            </GridViewColumn.Header>
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <ContentControl>
                                        <TextBlock Text="test" />
                                    </ContentControl>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>

类 BooleanToWidthConverter :IValueConverter
{

    public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool b)
        {
            return b ? parameter : 0;
        }
        return 0;
    }

    public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

不幸的是,GridViewColumn 中没有“IsVisible”属性
但是,我有一个解决方案可以通过简单而完整的方式解决这个问题:

  1. 将宽度设置为0。许多开发人员就停在这一步,因为它似乎已经被隐藏了,但实际上并没有。 我们仍然使其可扩展,因此通过调整列大小将其带回 UI,因此我们需要执行更多步骤 2。
  2. 通过设置 GridViewColumnHeader IsEnabled = false 禁用调整 GridViewColumn 大小。

上面的代码示例:

<GridViewColumn Width="{Binding Tag, RelativeSource={RelativeSource AncestorType=ListView}, Converter={converters:BooleanToWidthConverter}, ConverterParameter=100}">
                            <GridViewColumn.HeaderContainerStyle>
                                <Style TargetType="{x:Type GridViewColumnHeader}" BasedOn="{StaticResource ColumnHeaderStyle}">
                                    <Setter Property="IsEnabled" Value="False"/>
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource AncestorType=ListView}}" Value="true">
                                            <Setter Property="IsEnabled" Value="True"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </GridViewColumn.HeaderContainerStyle>
                            <GridViewColumn.Header>
                                <StackPanel Tag="columnHeader" Orientation="Horizontal">
                                </StackPanel>
                            </GridViewColumn.Header>
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <ContentControl>
                                        <TextBlock Text="test" />
                                    </ContentControl>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>

class BooleanToWidthConverter :IValueConverter
{

    public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool b)
        {
            return b ? parameter : 0;
        }
        return 0;
    }

    public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

Unfortunately, there is no "IsVisible" Property in GridViewColumn
But, I have a solution can solve this problem by simple and complete way:

  1. Setting width to 0. Many Dev just stop at this step, because it seems to have been hidden but not. We still make it extendible hence bringing it back on the UI by resize column, so we need to do more step 2.
  2. Disable resize GridViewColumn by set GridViewColumnHeader IsEnabled = false.

Code sample above:

祁梦 2024-07-23 20:29:31

有点晚了,但我认为这可能仍然有用:

根据 A.Pissicat、Surfen 和 Ben McMillan 的代码(和注释),我更新了 GridViewColumnVisibilityManager 如下:

    /// <summary>
    /// Used to hide the attached <see cref="GridViewColumn"/> and prevent the user
    /// from being able to access the column's resize "gripper" by
    /// temporarily setting both the column's width and style to
    /// a value of 0 and null (respectively) when IsVisible
    /// is set to false. The prior values will be restored
    /// once IsVisible is set to true.
    /// </summary>
    public static class GridViewColumnVisibilityManager
    {
        public static readonly DependencyProperty IsVisibleProperty =
            DependencyProperty.RegisterAttached(
                "IsVisible",
                typeof(bool),
                typeof(GridViewColumnVisibilityManager),
                new UIPropertyMetadata(true, OnIsVisibleChanged));

        private static readonly ConditionalWeakTable<GridViewColumn, ColumnValues> OriginalColumnValues = new ConditionalWeakTable<GridViewColumn, ColumnValues>();

        public static bool GetIsVisible(DependencyObject obj) => (bool)obj.GetValue(IsVisibleProperty);

        public static void SetIsVisible(DependencyObject obj, bool value) => obj.SetValue(IsVisibleProperty, value);

        private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is GridViewColumn gridViewColumn))
            {
                return;
            }

            if (!GetIsVisible(gridViewColumn))
            {
                // Use GetOrCreateValue to ensure
                // we have a place to cache our values.
                // Any previous values will be overwritten.
                var columnValues = OriginalColumnValues.GetOrCreateValue(gridViewColumn);
                columnValues.Width = gridViewColumn.Width;
                columnValues.Style = gridViewColumn.HeaderContainerStyle;

                // Hide the column by
                // setting the Width to 0.
                gridViewColumn.Width = 0;

                // By setting HeaderContainerStyle to null,
                // this should remove the resize "gripper" so
                // the user won't be able to resize the column
                // and make it visible again.
                gridViewColumn.HeaderContainerStyle = null;
            }
            else if (gridViewColumn.Width == 0
                     && OriginalColumnValues.TryGetValue(gridViewColumn, out var columnValues))
            {
                // Revert back to the previously cached values.
                gridViewColumn.HeaderContainerStyle = columnValues.Style;
                gridViewColumn.Width = columnValues.Width;
            }
        }

        private class ColumnValues
        {
            public Style Style { get; set; }

            public double Width { get; set; }
        }
    }

如果您愿意隐藏列时使用特定的 HeaderContainerStyle Style 而不是 null,然后替换:

gridViewColumn.HeaderContainerStyle = columnValues.Style; code>

with

gridViewColumn.HeaderContainerStyle = Application.Current.TryFindResource(@"disabledColumn") as Style;

并将 @"disabledColumn" 更改为您想要使用的任何名称。

A bit late, but I thought this might still be useful:

Based on the code (and comments) of A.Pissicat, Surfen and Ben McMillan, I've updated GridViewColumnVisibilityManager as follows:

    /// <summary>
    /// Used to hide the attached <see cref="GridViewColumn"/> and prevent the user
    /// from being able to access the column's resize "gripper" by
    /// temporarily setting both the column's width and style to
    /// a value of 0 and null (respectively) when IsVisible
    /// is set to false. The prior values will be restored
    /// once IsVisible is set to true.
    /// </summary>
    public static class GridViewColumnVisibilityManager
    {
        public static readonly DependencyProperty IsVisibleProperty =
            DependencyProperty.RegisterAttached(
                "IsVisible",
                typeof(bool),
                typeof(GridViewColumnVisibilityManager),
                new UIPropertyMetadata(true, OnIsVisibleChanged));

        private static readonly ConditionalWeakTable<GridViewColumn, ColumnValues> OriginalColumnValues = new ConditionalWeakTable<GridViewColumn, ColumnValues>();

        public static bool GetIsVisible(DependencyObject obj) => (bool)obj.GetValue(IsVisibleProperty);

        public static void SetIsVisible(DependencyObject obj, bool value) => obj.SetValue(IsVisibleProperty, value);

        private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is GridViewColumn gridViewColumn))
            {
                return;
            }

            if (!GetIsVisible(gridViewColumn))
            {
                // Use GetOrCreateValue to ensure
                // we have a place to cache our values.
                // Any previous values will be overwritten.
                var columnValues = OriginalColumnValues.GetOrCreateValue(gridViewColumn);
                columnValues.Width = gridViewColumn.Width;
                columnValues.Style = gridViewColumn.HeaderContainerStyle;

                // Hide the column by
                // setting the Width to 0.
                gridViewColumn.Width = 0;

                // By setting HeaderContainerStyle to null,
                // this should remove the resize "gripper" so
                // the user won't be able to resize the column
                // and make it visible again.
                gridViewColumn.HeaderContainerStyle = null;
            }
            else if (gridViewColumn.Width == 0
                     && OriginalColumnValues.TryGetValue(gridViewColumn, out var columnValues))
            {
                // Revert back to the previously cached values.
                gridViewColumn.HeaderContainerStyle = columnValues.Style;
                gridViewColumn.Width = columnValues.Width;
            }
        }

        private class ColumnValues
        {
            public Style Style { get; set; }

            public double Width { get; set; }
        }
    }

If you wish to use a particular HeaderContainerStyle Style instead of null when hiding the column, then replace:

gridViewColumn.HeaderContainerStyle = columnValues.Style;

with

gridViewColumn.HeaderContainerStyle = Application.Current.TryFindResource(@"disabledColumn") as Style;

and change @"disabledColumn" to whatever name you want to use.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文