首页 > 其他分享 >WPF DataGridTextColumn下的Visibility绑定

WPF DataGridTextColumn下的Visibility绑定

时间:2024-05-11 23:44:23浏览次数:18  
标签:绑定 Freezable object Visibility public using WPF DataGridTextColumn

WPF中的DataContext属性非常方便,但在某些情况下,DataContext是不可访问的,比如,当你想绑定的元素不属于其逻辑树或可视树时,想正常使用绑定就可能非常困难……

让我们给一个简单的例子予以说明:我们要在DataGrid中显示产品列表。 在其中,我们希望能够基于ViewModel中公开的ShowPrice属性的值来显示或隐藏Price列。 按照我们正常的做法的话是将列的Visibility绑定到IsHide属性上,有需要的话再通过转化器来将值转换成Visibility枚举:

前台XAML代码如下

<Window
    x:Class="WPFTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WPFTest"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>
        <local:VisibilityConverter x:Key="visibilityConverter" />
    </Window.Resources>
    <Grid>
        <DataGrid
            x:Name="DataGrid"
            AutoGenerateColumns="False"
            CanUserAddRows="False"
            ItemsSource="{Binding DataList}">
            <DataGrid.Resources>
                <local:BindingProxy x:Key="proxy" Data="{Binding IsHide}" />
            </DataGrid.Resources>
            <DataGrid.Columns>
                <DataGridTextColumn
                    Binding="{Binding Name}"
                    Header="名称"
                    IsReadOnly="True" />
                <DataGridTextColumn
                    Binding="{Binding Content}"
                    Header="备注"
                    IsReadOnly="True" />
                <DataGridTextColumn
                    Binding="{Binding Value}"
                    Header="值"
                    IsReadOnly="False"
                    Visibility="{Binding IsHide, Converter={StaticResource visibilityConverter}}" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

后台ViewModel代码如下

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.ObjectModel;

namespace WPFTest
{
    public class MainViewModel : ObservableRecipient
    {
        private bool isHide = true;

        public bool IsHide
        {
            get => isHide;
            set => SetProperty(ref isHide, value);
        }

        private ObservableCollection<ItemModel> dataList = new ObservableCollection<ItemModel>();

        public ObservableCollection<ItemModel> DataList
        {
            get => dataList;
            set => SetProperty(ref dataList, value);
        }

        public MainViewModel()
        {
            InitData();
        }

        private void InitData()
        {
            for (int i = 0; i < 5; i++)
            {
                ItemModel model = new ItemModel();
                model.Name = $"名称{i + 1}";
                model.Content = $"备注{i + 1}";
                Random random = new Random();
                model.Value = random.Next(0, 100).ToString();
                DataList.Add(model);
            }
        }
    }
}

对应的Model代码如下

namespace WPFTest
{
    public class ItemModel
    {
        public string Name { get; set; } = string.Empty;

        public string Content { get; set; } = string.Empty;

        public string Value { get; set; } = string.Empty;

        public bool IsHide { get; set; } = false;
    }
}

转换器代码如下

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace WPFTest
{
    public class VisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Visibility.Collapsed : Visibility.Visible;
        }

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

以上代码的运行效果如下

但是,我们很快就会发现这样并不起作用,"值"列会一直可见。同时我们可以看到Visual Studio下的XAML绑定失败中可以看到提示

IsHide DataGridTextColumn.Visibility Visibility 找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement

哪怕我们更改绑定成其他的绑定方式

                <DataGridTextColumn
                    Binding="{Binding Value}"
                    Header="值"
                    IsReadOnly="False"
                    Visibility="{Binding IsHide, Converter={StaticResource visibilityConverter},RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" />

也是一样不生效的

此处可以采用Freezable类来处理这个问题,首先创建一个BindingProxy类的继承了Freezable的类,以及定义了一个名为Data的依赖项属性:

Freezable 提供 Changed 事件来通知观察者对象发生的任何修改。 冻结的 Freezable 还可以跨线程共享,解冻的 Freezable 则不能。

using System.Windows;

namespace WPFTest
{
    public class BindingProxy : Freezable
    {
        #region Overrides of Freezable

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

        #endregion Overrides of Freezable

        public object Data
        {
            get
            {
                return (object)GetValue(DataProperty);
            }
            set
            {
                SetValue(DataProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy));
    }
}

然后,我们可以在DataGrid的资源中声明此类的实例,并将Data属性绑定到当前的DataContext:

<DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding IsHide}" />
</DataGrid.Resources>

最后一步是指定此BindingProxy对象作为绑定的源:

<DataGridTextColumn
                    Binding="{Binding Value}"
                    Header="值"
                    IsReadOnly="False"
                    Visibility="{Binding Data, Converter={StaticResource visibilityConverter}, Source={StaticResource proxy}}" />

此处Data即是上面绑定的IsHide属性值(如果绑定的是诸如Class的话则对应的属性)

完整的XAML代码如下

<Window
    x:Class="WPFTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WPFTest"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>
        <local:VisibilityConverter x:Key="visibilityConverter" />
    </Window.Resources>
    <Grid>
        <DataGrid
            x:Name="DataGrid"
            AutoGenerateColumns="False"
            CanUserAddRows="False"
            ItemsSource="{Binding DataList}">
            <DataGrid.Resources>
                <local:BindingProxy x:Key="proxy" Data="{Binding IsHide}" />
            </DataGrid.Resources>
            <DataGrid.Columns>
                <DataGridTextColumn
                    Binding="{Binding Name}"
                    Header="名称"
                    IsReadOnly="True" />
                <DataGridTextColumn
                    Binding="{Binding Content}"
                    Header="备注"
                    IsReadOnly="True" />
                <DataGridTextColumn
                    Binding="{Binding Value}"
                    Header="值"
                    IsReadOnly="False"
                    Visibility="{Binding Data, Converter={StaticResource visibilityConverter}, Source={StaticResource proxy}}" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

运行结果如下:

https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/freezable-objects-overview?view=netframeworkdesktop-4.8

标签:绑定,Freezable,object,Visibility,public,using,WPF,DataGridTextColumn
From: https://www.cnblogs.com/SmallCarp/p/18187362

相关文章

  • WPF 基础、WPF 相关知识、学习、参考项目
     前言:  最初参加工作时,做过WPF项目,后面几年后者虽然有写WPF项目,但多数都是边边角角,写一点满足工作需要。  现在写下WPF,主要就是玩一玩,尝试下不同的东西。  这是我的代码仓库:地址(如果对您有帮助,给颗小星星奖励下吧),在WPF/Lesson10Practice/Practice/下面。基本涵盖WPF......
  • 在 WPF 中集成 ASP.NET Core 和 WebView2 用于集成 SPA 应用
    背景我们有些工具在Web版中已经有了很好的实践,而在WPF中重新开发也是一种费时费力的操作,那么直接集成则是最省事省力的方法了。修改项目文件我们首先修改项目文件,让WPF项目可以包含ASP.NETCore的库,以及引用WebView2控件。<ProjectSdk="Microsoft.NET.Sdk"><Pr......
  • 【坑】严重性 代码 说明 项目 文件 行 禁止显示状态 错误 NETSDK1141 无法解析位于 E:
    错误严重性代码说明项目文件行禁止显示状态错误NETSDK1141无法解析位于E:\firefox\WPF-Samples-main\WPF-Samples-main\global.json的global.json中指定的.NETSDK版本。DragDropObjectsC:\ProgramFiles\dotnet\sdk\8.0.202\Sdks\Microsoft.NET.Sdk\targets\M......
  • WPF Canvas在Image 图像上绘图,自适应缩放.
    效果如图  实现了绘图,自适应缩放核心代码如下<Window.InputBindings><KeyBindingKey="Z"Modifiers="Ctrl"Command="{BindingUndoCommand}"/></Window.InputBindings><i:Interaction.Triggers>......
  • WPF 稳定的全屏化窗口方法
    本文来告诉大家在WPF中,设置窗口全屏化的一个稳定的设置方法。在设置窗口全屏的时候,经常遇到的问题就是应用程序虽然设置最大化加无边框,但是此方式经常会有任务栏冒出来,或者说窗口没有贴屏幕的边。本文的方法是基于Win32的,由lsj提供的方法,当前已在1000多万台设备上稳定运行......
  • WPF dynamic resources drawbacks
     Dynamic resource, on the other hand, will create a temporary expression during the initial compilation and thus defer lookup for resources until the requested resource value is actually required in order to construct an obj......
  • WPF 引用类库中的图片在设计器的时候显示,运行起来不显示
    我这边是建立了一个类库,然后把所有静态资源放在该类库中,然后主项目添加该项目引用,然后图片死活不显示  1.图片属性设置为资源2.主项目添加该项目引用操作都试过了,就是死活不显示,然后问了别人,让我删除类库重新建一个试试,然后试了下,诶,好像确实可以了,突然想起一个小细节,我......
  • 【WPF】静态属性资源绑定动态更新
    1、Xaml资源文件<Application.Resources><ResourceDictionary><local:BindTestx:Key="bindtest"></local:BindTest><SolidColorBrushx:Key="brush"Color="Blue"/>......
  • dotnet 9 WPF 支持 Style 的 Setter 填充内容时可忽略 Value 标签
    本文记录WPF在dotnet9的一项XAML编写语法改进点,此改进点用于解决编写Style的Setter进行给Value赋值时,不能将Value当成默认内容,需要多写Value标签的问题。通过此改进点可减少两行XAML代码在原先的WPF版本里面,对Style的Setter填充复杂的对象内容时,大概的......
  • WPF/C#:ProgressBar的基本使用
    前言在日常开发过程中,如果遇到需要一段时间才能完成的任务,通常需要给用户一个进度条提示。今天给大家介绍的是WPF/C#中ProgressBar的基本使用。ProgressBar的介绍在WPF(WindowsPresentationFoundation)中,ProgressBar是一个用户界面元素,用于显示一个操作的进度。ProgressBar有......