32

我在 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?

有任何想法吗?

4

11 回答 11

21

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

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> ...
于 2010-06-21T20:45:15.623 回答
13

基于 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];
        }
    }
}
于 2012-03-09T13:24:53.090 回答
6

您最好的选择可能是通过从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,以便能够将其用作绑定目标。

于 2009-04-08T22:23:42.473 回答
4

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>
于 2009-09-20T13:57:47.960 回答
2

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

您所要做的就是将 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();
        }
    }
于 2015-10-23T05:53:41.143 回答
1

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

    /// <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;
                        }
                    }
                }

            }

        }
    }
于 2010-07-22T13:23:27.150 回答
0

这对我
有用 需要在标题和内容上绑定可见性
在这种情况下它在最后所以我不担心宽度
但是用户没有获得 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>
于 2014-04-30T21:41:55.993 回答
0

我建议在父级上使用自定义属性(或劫持现有属性),然后在 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>
于 2009-04-08T17:21:10.453 回答
0

在我编写的一个小实用程序中,我有一个列表视图,用户可以在其中隐藏/显示一些列。列上没有 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 };
}
于 2012-10-15T09:42:44.047 回答
0
<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。很多Dev 只是在这一步停止,因为它似乎被隐藏了但没有。我们仍然使其可扩展,因此通过调整列大小将其重新显示在 UI 上,因此我们需要执行更多步骤 2。
  2. 通过设置 GridViewColumnHeader IsEnabled = false 禁用调整 GridViewColumn 的大小。

上面的代码示例:

于 2019-03-25T10:07:06.707 回答
0

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

根据 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;

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

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

于 2021-03-22T12:42:09.987 回答