常见WPF用户控件操作(集合、动态生成、位运算、依赖属性)

一、集合

1.1.数组

cs 复制代码
//定义
string[] devices = new string[3];
//增
devices[0] = "电机A";
devices[1] = "传感器B";
//删
无法真正删除只能是跳过这个元素赋值给新数组
//改
devices[0]="电机B";

1.2.List

注意改的时候任然使用索引器,但是List虽然是动态列表但是只能使用Add函数来增加位数,不能直接devices[100]=''hello''这样会超出数组索引范围

cs 复制代码
//定义
var devices = new List<string> { "电机A", "传感器B", "PLC-C" };
//增
devices.Add("变频器D");
//改
devices[3] = "PLC-C升级版";
//按照值删除
devices.Remove("传感器B");
//按照索引删除
devices.RemoveAt(0);
//查
string s = devices[0];

1.3.observableCollection(可观察集合)

**特点:**只要修改observableCollection的元素就会通知ui变化,无需手动通知

注意:当元素内部变化,例如元素为对象,对象的属性值发生就不会通知

cs 复制代码
//定义
var devices = new ObservableCollection<string> { "电机A", "传感器B", "PLC-C" };
//增
devices.Add("变频器D");
devices.Insert(0, "编码器E");
Console.WriteLine("--增---");
//删
Console.WriteLine("--删---");
devices.Remove("传感器B");
devices.RemoveAt(2);
//改
devices[0] = "1111";
//查
string st = devices[0];
//清空
devices.Clear()(通知 UI)

二、动态生成

通过绑定集合的方式来实现动态生成ui上的控件

ItemsSource:绑定一个集合 (如 List<T>),是数据的来源

XML 复制代码
<ItemsControl ItemsSource="{Binding MyDataList}" />
XML 复制代码
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <!-- 这里写"单行"的布局 -->
        <TextBlock Text="{Binding Name}" />
        <Ellipse Fill="{Binding Color}" ... />
    </DataTemplate>
</ItemsControl.ItemTemplate>

后台:

cs 复制代码
namespace 模板try
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public ObservableCollection<string> StatusItems { get; set; }
        = new ObservableCollection<string> { "Item1", "Item2", "Item3" };
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }
    }
}

三、转换器的简单使用

目的:解决UI 需要的属性和数据源的值类型不匹配的问题

例一:根据布尔值切换红绿灯

要求:显示一个圆形"灯":true → 绿色,false → 红色。

但是WPF 的绑定系统不能自动把 bool 翻译成 Brush去将true变成灯的绿色,所以我们需要一个"翻译官"------这就是 转换器(Converter)

第一步:创建类文件继承IValueConverter,自动实现接口

cs 复制代码
namespace CPA.Converters
{
    public class BoolToBrushConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {//"#FF0000"
            if (value is bool && (bool)value == true)
                return new SolidColorBrush(Color.FromRgb(0xFF, 0x00, 0x00));
            return new SolidColorBrush(Color.FromRgb(0x71, 0xFF, 0x30));
        }

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

|--------------|---------------------------|
| value | 绑定源的值(这里是 属性的值,比如 true) |
| targetType | 使用转换的控件属性 |
| parameter | 可携带参数 |
| culture | 本地化信息(如中文/英文环境,本例忽略) |

xaml中使用:

cs 复制代码
  <Rectangle
      Width="30"
      Height="20"
      HorizontalAlignment="Left"
      VerticalAlignment="Center"
      Fill="{Binding IsOn, Converter={StaticResource BoolToBrush}}"
      Stroke="Black"
      StrokeThickness="1"/>

例二:利用TargetType和Parameter来实现一个转换器解决多个数据和ui属性不匹配

ui:

cs 复制代码
<TextBlock
    VerticalAlignment="Center"
    FontSize="12"
    Text="{Binding InputValue, Converter={StaticResource ByteTwoBitsConverter}, ConverterParameter=High}"
    TextAlignment="Center" />

转换器:根据输入参数来返回不同结果

cs 复制代码
  class ByteTwoBitsConverter : IValueConverter
  {
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {
          
          if (value is byte b&& parameter is string para)
          {            
               if (para == "Middle")
                  return ((b >> 4) & 0b11); // 提取次高两位
              else if (para == "High")
                  return ((b >> 6) & 0b11).ToString(); // 提取高两位
          }
          return "0";
      }

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

四、使用位运算符取二进制每一bit办法

**使用场景:**Byte每一位都有单独的意义,而非只是作为数据的存储单位

掩码定义: 就像用一张带孔的纸盖在数字上,只有孔对应的位置能被看到,其余部分被"遮住"了 ------ 这张"带孔的纸"就是掩码(实现只展示想要的数据的工具)

**左位移和右位移的本质:**右位移的本质是右移n位等于原值除以2的n次方(类比10进制,100右移一位为10)

4.1使用掩码&(源数据位移运算值)取目标位

只需要掩码目标位数的二进制值为1即可,下面进行位运算只是为了降低数值含义

4.1.1取固定几位

cs 复制代码
byte value = 0b11010010; // 示例:二进制 11010010

// 取高两位:右移 6 位,保留最低 2 位
int highTwoBits = (value >> 6) & 0b11; // 或 & 3
//右移6位等价于除以2的6次方
int hignTwoBits=(value&0b11000000)/64;

Console.WriteLine(highTwoBits); // 输出: 3 (因为 11b = 3)

4.1.2取每一位

value&掩码,只有当和掩码对应那一位为1时才等于掩码的值。

cs 复制代码
byte value = 0b10110000; // 或 Convert.ToByte("10110000", 2);
for (int i = 7; i >= 0; i--)
{
     //将掩码值转换为bool类型
   // isOn 就是第 i 位的状态
    bool isOn = (value & (1 << i)) != 0;
 //取出该位的值
Byte BitValue = (value & (1 << i));
}

五、依赖属性

依赖属性(Dependency Property) 是 WPF(Windows Presentation Foundation)的核心机制之一,它为数据绑定、动画、样式、模板、资源等高级功能提供了底层支持。

当前场景

在用户控件中使用依赖属性来作为用户控件的输入

怎么使用?

1.propdp+两次tab

cs 复制代码
//这是依赖属性包装器       
public int MyProperty
       {
           get { return (int)GetValue(MyPropertyProperty); }
           set { SetValue(MyPropertyProperty, value); }
       }

       //下面是依赖属性
       public static readonly DependencyProperty MyPropertyProperty =
           DependencyProperty.Register(
"MyProperty",//属性名称要和包装器相同
 typeof(int),//属性类型
 typeof(BitStatusDisplay),//属性所属类
 new PropertyMetadata(0));//初始值,这个非必须,不填默认为类型的默认值

2.PropertyMetadata有重载方法,使用ctrl+左键点开PropertyMetadata

增加回调函数的依赖属性

cs 复制代码
     public int MyProperty
     {
         get { return (int)GetValue(MyPropertyProperty); }
         set { SetValue(MyPropertyProperty, value); }
     }

     public static readonly DependencyProperty MyPropertyProperty =
         DependencyProperty.Register("MyProperty", typeof(int), typeof(BitStatusDisplay), new PropertyMetadata(0, OnMyPropertyChanged));

     private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
     {
         throw new NotImplementedException();
     }

回调函数怎么生成?

直接写函数名,然后使用提示创建函数

注意:回调函数是静态方法无法直接调用非静态方法,只能通过实例来调用

回调函数的调用时机

当值改变的时候自动调用

注意: 无论哪种方式(xaml,绑定,动画)修改依赖属性,WPF 都会触发回调和绑定更新;但只有 C# 赋值会调用 属性中的set,C# 赋值会走完整链路:setSetValue → 回调 → 绑定更新,原因是Setvalue方法

c#赋值例如:

cs 复制代码
bitStatusDisplay.MyProperty = 42;
cs 复制代码
     public int MyProperty
     {
         get { return (int)GetValue(MyPropertyProperty); }
         set { SetValue(MyPropertyProperty, value); }
     }

     public static readonly DependencyProperty MyPropertyProperty =
         DependencyProperty.Register("MyProperty", typeof(int), typeof(BitStatusDisplay), new PropertyMetadata(0, OnMyPropertyChanged));

     private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
     {
         throw new NotImplementedException();
     }

核心语句

这里很有意思,当前的场景是在用户控件中使用依赖属性来作为用户控件的输入,那么传入的d就是用户控件本身,根据形式参数的字段=实际参数的地址,那么其实是多态的写法,但是现在不是要多态,而是要调用子类自定义的类型和方法,必须要转换为子类类型

通常is关键字表示是,写法如下,返回值为bool类型

cs 复制代码
bool aa=human is animal

下面是高级特性,可以实现转换,将d重命名为BitStatusDisplay类型的control

cs 复制代码
if (d is BitStatusDisplay control)
{}

参数内容

DependencyPropertyChangedEventArgs e函数参数:

  • e.OldValue → 变化前的值(object 类型)
  • e.NewValue → 变化后的值(object 类型)
相关推荐
Lupino11 小时前
实战记录:使用 Haskell.nix 交叉编译 Haskell 项目至 Windows
windows·haskell
zzcufo13 小时前
使用multimonitortool工具实现多屏显示器的映射
windows·计算机外设
一条咸鱼¥¥¥14 小时前
【运维经验】服务器磁盘做镜像的方法
运维·服务器·windows·经验分享
cpp_learners14 小时前
Qt Windows版本的《智能鼠标点击器》
windows·qt·鼠标点击器
love530love14 小时前
Windows 11 下 Z-Image-Turbo 完整部署与 Flash Attention 2.8.3 本地编译复盘
人工智能·windows·python·aigc·flash-attn·z-image·cuda加速
Halo_tjn18 小时前
Java IO流实现文件操作知识点
java·开发语言·windows·算法
love530love18 小时前
Windows 下 Z-Image-Turbo 专业版 Gradio 生成器实战:功能增强全记录
人工智能·windows·python·大模型·gradio·博客之星·z-image
離離原上譜21 小时前
Windows 环境下 Node.js + Claude Code 安装与配置教程
windows·node.js
小鸡脚来咯21 小时前
怎么配置主机名映射?
linux·windows·macos