• c# 学习笔记 PropertyChangedEventHandler、 =>、DependencyObject、DataContext


    在C#中,PropertyChangedEventHandlerPropertyChanged 常常与 INotifyPropertyChanged 接口一起使用,这是实现数据绑定和通知机制的关键部分,尤其在WPF (Windows Presentation Foundation) 或其他支持数据绑定的UI框架中。

    PropertyChangedEventHandler

    PropertyChangedEventHandler 是一个委托,它定义了当属性发生变化时应该调用的方法的签名。这个委托接受两个参数:发送更改通知的对象(通常是实现 INotifyPropertyChanged 接口的对象)和一个 PropertyChangedEventArgs 对象,后者包含关于更改的具体信息(即哪个属性发生了变化)。

    PropertyChanged 事件

    PropertyChanged 是一个事件,通常在一个实现了 INotifyPropertyChanged 接口的类中声明。当类的某个属性值发生变化时,类的实现者会触发这个事件,以通知任何订阅了这个事件的监听器。

    示例

    下面是一个简单的例子,展示了如何在C#中实现 INotifyPropertyChanged 接口,并使用 PropertyChangedEventHandlerPropertyChanged 事件:

    using System;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    
    public class Person : INotifyPropertyChanged
    {
        private string _name;
        private int _age;
    
        public string Name
        {
            get { return _name; }
            set
            {
                if (_name == value) return;
                _name = value;
                OnPropertyChanged();
            }
        }
    
        public int Age
        {
            get { return _age; }
            set
            {
                if (_age == value) return;
                _age = value;
                OnPropertyChanged();
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        // 这个方法用于触发 PropertyChanged 事件
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    在这个例子中,Person 类实现了 INotifyPropertyChanged 接口,并声明了 PropertyChanged 事件。NameAge 属性在它们的setter中包含了调用 OnPropertyChanged 方法的逻辑。当这些属性的值发生变化时,OnPropertyChanged 方法会被调用,并触发 PropertyChanged 事件。

    [CallerMemberName] 是一个特性,它允许你在没有显式传递属性名的情况下获取当前成员的名称。这使得代码更简洁,减少了错误的可能性。

    任何订阅了 Person 对象的 PropertyChanged 事件的监听器现在都会收到通知,包括哪个属性发生了变化。这通常用于UI更新,或者任何需要响应数据变化的其他逻辑。

    =>

    在C#中,=> 是一个特殊的符号,它主要在两种上下文中有特殊的意义:

    Lambda 表达式:
    Lambda 表达式是一种简洁的编写匿名函数的方法。=> 符号用于分隔输入参数和表达式体。以下是一个Lambda表达式的例子:

    csharp
    Func add = (x, y) => x + y;
    在这个例子中,(x, y) 是输入参数,而 x + y 是表达式体。

    如果Lambda表达式只有一个参数,你可以省略括号:

    csharp
    Func isPositive = x => x > 0;
    表达式体成员(Expression-bodied members):
    从C# 6.0开始,你可以使用 => 来定义一个只有表达式体的成员(如方法、属性、索引器、构造函数和析构函数)。这可以使得代码更加简洁。

    例如,一个只有表达式体的方法:

    csharp
    public int Square(int x) => x * x;
    一个只有表达式体的只读属性:

    csharp
    public int Length => someList.Count;
    一个只有表达式体的索引器:

    csharp
    public int this[int index] => data[index];
    在这两种情况下,=> 都起到了分隔左侧的定义(如参数列表、属性名或索引器签名)和右侧的表达式体的作用。

    WPF DependencyObject

    在WPF(Windows Presentation Foundation)中,DependencyObject 是一个基础类,用于实现依赖属性(Dependency Properties)系统。依赖属性是WPF中用于数据绑定、样式、动画和默认值的强大系统。

    DependencyObject 类提供了存储和检索依赖属性值的机制。与传统的.NET属性不同,依赖属性可以参与WPF的属性系统,该系统提供了许多高级功能,如数据绑定、样式、动画、值继承、默认值等。

    以下是关于 DependencyObject 的一些关键点:

    基础类:所有具有依赖属性的WPF类(如 Control、FrameworkElement、Shape 等)都继承自 DependencyObject。
    依赖属性存储:依赖属性的值不直接存储在类的字段中,而是存储在 DependencyObject 的内部字典中。这使得WPF能够在运行时高效地查询和修改这些值。
    元数据:每个依赖属性都与一个 PropertyMetadata 对象相关联,该对象包含有关该属性的元数据,如默认值、属性更改回调等。
    属性更改通知:当依赖属性的值更改时,WPF可以触发各种事件和回调,如 PropertyChangedCallback。
    数据绑定:依赖属性是WPF数据绑定系统的核心。通过依赖属性,你可以将UI元素与数据源进行双向绑定。
    动画和渐变:WPF的动画系统使用依赖属性来驱动动画和渐变效果。
    样式和模板:依赖属性允许WPF样式和模板系统通过统一的方式修改多个UI元素的外观和行为。
    要使用依赖属性,你需要定义一个 DependencyProperty 静态字段,并使用 DependencyProperty.Register 方法或 DependencyProperty.RegisterAttached 方法(对于附加属性)进行注册。然后,你可以使用 GetValue 和 SetValue 方法来读取和设置依赖属性的值。

    下面是一个简单的示例,展示了如何定义一个依赖属性:

    csharp
    public class MyControl : Control
    {
    // 依赖属性注册
    public static readonly DependencyProperty MyPropertyProperty =
    DependencyProperty.Register(“MyProperty”, typeof(string), typeof(MyControl), new PropertyMetadata(string.Empty));

    // .NET包装属性  
    public string MyProperty  
    {  
        get { return (string)GetValue(MyPropertyProperty); }  
        set { SetValue(MyPropertyProperty, value); }  
    }  
    

    }
    在这个示例中,MyControl 类定义了一个名为 MyProperty 的依赖属性,并提供了一个相应的.NET包装属性以便于访问。

    WPF DataContext

    在C#的WPF(Windows Presentation Foundation)框架中,DataContext 是一个非常重要的概念,特别是在数据绑定(Data Binding)方面。DataContext 是一个对象,它包含了要绑定到UI元素(如TextBlock、ListBox、ComboBox等)的数据。这些数据可以是简单的数据类型(如string、int等),也可以是复杂的对象或集合。

    DataContext 可以被设置为任何类型的对象,并且通常通过以下几种方式之一与UI元素相关联:

    直接设置:你可以直接为某个UI元素(如UserControl、Window、Grid等)设置DataContext属性。这样,该元素及其所有子元素都可以访问这个DataContext中的数据。
    csharp
    myControl.DataContext = new MyViewModel();
    继承:如果一个UI元素没有显式设置DataContext,它将从其父元素继承DataContext。这允许你在根元素(如Window或UserControl)上设置DataContext,并使其自动应用于所有子元素。
    数据模板:在数据控件(如ListView、DataGrid等)中,你可以使用数据模板(Data Templates)来定义如何显示数据项。在这些模板中,你可以使用数据绑定表达式(如{Binding PropertyName})来引用当前数据项(即当前项的DataContext)的属性。
    在MVVM(Model-View-ViewModel)架构中,DataContext 通常是一个ViewModel对象。ViewModel是一个充当数据中介的类,它将Model中的数据转换为适合在View中显示的形式,并处理来自View的用户输入。通过将数据绑定到ViewModel的属性,你可以轻松地将UI与数据隔离开来,从而实现更清晰的代码结构和更好的可维护性。

    以下是一个简单的示例,展示了如何在WPF中设置和使用DataContext:

    xml






    csharp
    // C# 代码
    public class MyViewModel
    {
    public string MyProperty { get; set; } = “Hello, WPF!”;
    }

    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    this.DataContext = new MyViewModel();
    }
    }
    在这个示例中,我们创建了一个名为MyViewModel的类,它有一个名为MyProperty的属性。然后,在MainWindow的构造函数中,我们将MyViewModel对象设置为窗口的DataContext。最后,在XAML文件中,我们使用数据绑定表达式{Binding MyProperty}将TextBlock的Text属性绑定到MyProperty属性上。当MyProperty属性的值改变时,TextBlock的文本将自动更新以反映新的值。

    c# 给出4个C1ComboBox 其中其他值也跟着变化

    在C#中,如果四个C1ComboBox(第三方库如C1 Studio for .NET中的控件)中的值能够相互关联,即改变一个C1ComboBox的值会导致其他C1ComboBox的值也相应地改变,你需要实现一种事件监听机制。

    以下是一个基本的步骤说明和示例代码,展示如何实现这种功能:

    定义事件处理函数:为每个C1ComboBox的SelectedIndexChanged或ValueChanged事件定义一个处理函数。
    更新其他控件:在事件处理函数中,根据当前C1ComboBox的选中值来更新其他C1ComboBox的值或可选项。
    避免无限循环:确保在更新其他C1ComboBox时不会触发它们自己的事件,从而导致无限循环。你可以通过设置某个标志或使用BeginInvoke来在UI线程上异步更新控件来避免这个问题。
    下面是一个简化的示例代码:

    csharp

    public partial class MyForm : Form  
    {  
        private bool isUpdating = false; // 用于防止无限循环的标志  
      
        public MyForm()  
        {  
            InitializeComponent();  
      
            // 假设你已经有四个C1ComboBox:comboBox1, comboBox2, comboBox3, comboBox4  
            comboBox1.SelectedIndexChanged += ComboBox1_SelectedIndexChanged;  
            // 为其他三个也添加类似的事件监听  
        }  
      
        private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)  
        {  
            if (isUpdating) return; // 如果正在更新,则直接返回  
      
            isUpdating = true; // 设置标志,表示开始更新  
      
            try  
            {  
                // 根据comboBox1的选中值来更新其他三个ComboBox  
                // 例如,如果comboBox1选中了某个值,你可能想要从某个数据源中获取与该值相关的其他选项  
                // 并设置到comboBox2, comboBox3, comboBox4中  
      
                // 伪代码示例:  
                // List relatedOptions = GetDataRelatedTo(comboBox1.SelectedItem);  
                // comboBox2.DataSource = relatedOptions;  
                // comboBox3.DataSource = relatedOptions; // 根据实际情况可能需要不同的数据源  
                // comboBox4.DataSource = relatedOptions;  
      
                // ... 实际设置代码 ...  
            }  
            finally  
            {  
                isUpdating = false; // 更新完成,重置标志  
            }  
        }  
      
        // ... 为其他三个ComboBox也添加类似的事件处理函数 ...  
    }
    
  • 相关阅读:
    Pytorch 机器学习专业基础知识+神经网络搭建相关知识
    27.基于ADS的不等分威尔金森功分器设计
    UFS Power Management 介绍
    【图像融合】基于DSIFT多聚焦图像融合附matlab代码
    Powershell 一键安装 virtio_qemu_agent
    ATT&CK红队评估实战靶场二
    Win11如何增强麦克风?Win11增强麦克风的设置
    你给我解释解释,什么TMD叫TMD attention(持续更新ing...)
    STM32物联网项目-高级定时器功能介绍
    Pandas详细总结
  • 原文地址:https://blog.csdn.net/weixin_45751713/article/details/139790277