日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

WPF --- 如何以Binding方式隐藏DataGrid列

發布時間:2023/11/23 asp.net 38 coder
生活随笔 收集整理的這篇文章主要介紹了 WPF --- 如何以Binding方式隐藏DataGrid列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引言

如題,如何以Binding的方式動態隱藏DataGrid列?

預想方案

像這樣:

先在ViewModel創建數據源 People 和控制列隱藏的 IsVisibility,這里直接以 MainWindowDataContext

 public partial class MainWindow : Window, INotifyPropertyChanged
 {
     public MainWindow()
     {
         InitializeComponent();
         Persons = new ObservableCollection<Person>() { new Person() { Age = 11, Name = "Peter" }, new Person() { Age = 19, Name = "Jack" } };
         DataContext = this;
     }

     public event PropertyChangedEventHandler? PropertyChanged;

     public void OnPropertyChanged([CallerMemberName] string propertyName = null)
     {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
     }


     private bool isVisibility;
     
     public bool IsVisibility
     {
         get => isVisibility;
         set
         {
             isVisibility = value;
             OnPropertyChanged(nameof(IsVisibility));
         }
     }

     private ObservableCollection<Person> persons;

     public ObservableCollection<Person> Persons
     {
         get { return persons; }
         set { persons = value; OnPropertyChanged(); }
     }
 }

然后創建 VisibilityConverter,將布爾值轉化為 Visibility

 public class VisibilityConverter : IValueConverter
 {
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
         if (value is bool isVisible && isVisible)
         {
             return Visibility.Visible;
         }
         return Visibility.Collapsed;
     }

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

然后再界面綁定 IsVisibility,且使用轉化器轉化為Visibility,最后增加一個 CheckBox 控制是否隱藏列。


<Grid>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <DataGrid
            x:Name="dataGrid"
            AutoGenerateColumns="False"
            CanUserAddRows="False"
            ItemsSource="{Binding Persons}"
            SelectionMode="Single">
            <DataGrid.Columns>
                <DataGridTextColumn
                    Header="年齡"                
                    Width="*"
                    Binding="{Binding Age}"
                    Visibility="{Binding DataContext.IsVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type Window}}, Converter={StaticResource VisibilityConverter}}" />
                <DataGridTextColumn Header="姓名" Width="*" Binding="{Binding Name}" />
            </DataGrid.Columns>
        </DataGrid>
        <CheckBox
            Grid.Column="1"
            Content="是否顯示年齡列"
            IsChecked="{Binding IsVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Grid>

這樣應該沒問題,Visibility 是依賴屬性,能直接通過 Binding 的方式賦值。

但實際測試時就會發現,勾選 CheckBox 能夠改變 DataContext.IsVisibility 的值,但是無法觸發轉換器 VisibilityConverter,即使不用 RelativeSource 方式,更改為指定 ElementName獲取元素的方式,也一樣不生效。

這是為什么呢?

我疑惑了很久,直到看到了Visual Studio中的實時可視化樹:

從圖中可以看出,雖然我在 Xaml 中聲明了兩列 DataGridTextColumn,但他根本不在可視化樹中。

獲取 RelativeSource 和指定 ElementName 的方式,本質上還是在可視化樹中尋找元素,所以上述方案無法生效。

那為什么 DataGridTextColumn 不在可視化樹中呢?

可視化樹(Visula Tree)

在上面那個問題之前,先看看什么是可視化樹?

我們先從微軟文檔來看一下WPF中其他控件的繼承樹。

比如 Button

比如 DataGrid

又比如 ListBox

大家可以去看看其他的控件,幾乎 WPF 中所有的控件都繼承自 Visual(例如,PanelWindowButton 等都是由 Visual 對象構建而成)。

Visual 是 WPF 中可視化對象模型的基礎,而 Visual 對象通過形成可視化樹(Visual Tree)來組織所有可視化模型。所以Visual Tree 是一個層次結構,包含了所有界面元素的視覺表示。所有繼承自 VisualUIElement(UI 元素的更高級別抽象)的對象都存在于可視化樹中。

但是,DataGridColumn 是一個特例,它不繼承 Visual,它直接繼承 DependencyObject,如下:

所以,DataGridColumn的繼承樹就解答了他為什么不在可視化樹中。

解決方案

所以,通過直接找 DataContext 的方式,是不可行的,那就曲線救國。

既然無法找到承載 DataContext.IsVisibility 的對象,那就創建一個能夠承載的對象。首先該對象必須是 DependencyObject 類型或其子類,這樣才能使用依賴屬性在 Xaml 進行綁定,其次必須有屬性變化通知功能,這樣才能觸發 VisibilityConverter,實現預期功能。

這時候就需要借助一個抽象類 System.Windows.Freezable。摘取部分官方解釋如下:


從文檔中可以看出 Freezable 非常符合我們想要的,第一它本身繼承 DependencyObject 且 它在子屬性值更改時能夠提供變化通知。

所以我們可以創建一個自定義 Freezable 類,實現我們的功能,如下:

public class CustomFreezable : Freezable
{
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(CustomFreezable));

    public object Value
    {
        get => (object)GetValue(ValueProperty);
        set => SetValue(ValueProperty, value);
    }

    protected override void OnChanged()
    {
        base.OnChanged();
    }
    
    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);
    }

    protected override Freezable CreateInstanceCore()
    {
        return new CustomFreezable();
    }
}

然后在 Xaml 添加 customFreezable 資源,給 DataGridTextColumnVisibility 綁定資源

<Window.Resources>
    <local:VisibilityConverter x:Key="VisibilityConverter" />
    <local:CustomFreezable x:Key="customFreezable" Value="{Binding IsVisibility, Converter={StaticResource VisibilityConverter}}" />
</Window.Resources>
<Grid>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <DataGrid
            x:Name="dataGrid"
            AutoGenerateColumns="False"
            CanUserAddRows="False"
            ItemsSource="{Binding Persons}"
            SelectionMode="Single">
            <DataGrid.Columns>
                <DataGridTextColumn
                    x:Name="personName"
                    Width="*"
                    Binding="{Binding Age}"
                    Header="年齡"
                    Visibility="{Binding Value, Source={StaticResource customFreezable}}" />
                <DataGridTextColumn
                    Width="*"
                    Binding="{Binding Name}"
                    Header="姓名" />
            </DataGrid.Columns>
        </DataGrid>
        <CheckBox
            Grid.Column="1"
            Content="是否顯示年齡列"
            IsChecked="{Binding IsVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Grid>

測試:

勾選后,顯示年齡列:

取消勾選后,隱藏年齡列

小結

本篇文章中,首先探索了 DataGridTextColumn 為什么不在可視化樹結構內,是因為所有繼承自 VisualUIElement(UI 元素的更高級別抽象)的對象才存在于可視化樹中。DataGridTextColumn是直接繼承DependencyObject ,所以才不在可視化樹結構內。

其次探索如何通過曲線救國,實現以 Binding 的方式實現隱藏DataGridTextColumn,我們借助了一個核心抽象類 System.Windows.Freezable。該抽象類是 DependencyObject 的子類,能使用依賴屬性在 Xaml 進行綁定,且有屬性變化通知功能,觸發 VisibilityConverter轉換器,實現了預期功能。

如果大家有更優雅的方案,歡迎留言討論。

參考

* - how to hide wpf datagrid columns depending on a propert?: https://*.com/questions/6857780/how-to-hide-wpf-datagrid-columns-depending-on-a-property

Freezable Objects Overview: https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/freezable-objects-overview?view=netframeworkdesktop-4.8&wt.mc_id=MVP

總結

以上是生活随笔為你收集整理的WPF --- 如何以Binding方式隐藏DataGrid列的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。