侧边栏壁纸
博主头像
陌上花 博主等级

回首万事皆休

  • 累计撰写 73 篇文章
  • 累计创建 11 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录
WPF

WPF坑之DataType

种向日葵的人
2025-07-19 / 0 评论 / 0 点赞 / 2 阅读 / 0 字

Why

  • 最近闲着无聊打算写一个小工具,其中用到了TreeView,发现了一个在某些时候一个很坑的东西–DataType

How

  • 新建一个Prism项目。
  • 以下是使用的主要树的绑定数据类
public partial class UserInfo : ObservableObject
{
    [ObservableProperty]
    private int _id;
    [ObservableProperty]
    private string? _userName;
    [ObservableProperty]
    private string? _password;
    [ObservableProperty]
    private string? _email;
    [ObservableProperty]
    private string? _phone;
    [ObservableProperty]
    private string? _address;
    [ObservableProperty]
    private string? _city;
    [ObservableProperty]
    private ObservableCollection<ClassBase> _classInfos = [];
}
public partial class ClassBase : ObservableObject
{
    [ObservableProperty]
    private string? _className;
    [ObservableProperty]
    private string? _classTeacher;
}
public partial class ClassOne : ClassBase
{
    [ObservableProperty]
    private string? _classOneTeacher;
}
public partial class ClassTwo : ClassBase
{
    [ObservableProperty]
    private string? _classTwoTeacher;
}
  • 以下是对应的MainViewModel,使用模拟数据,最简单的100行数据。
public partial class MainViewModel : ObservableObject
{
    private readonly IRegionManager iRegionManager;
    private readonly IEventAggregator iEventAggregator;
    public MainViewModel()
    {
        LoadUsers();
    }

    public MainViewModel(IRegionManager iRegionManager, IEventAggregator iEventAggregator) : this()
    {
        this.iRegionManager = iRegionManager;
        this.iEventAggregator = iEventAggregator;
    }
    [ObservableProperty]
    private ObservableCollection<UserInfo> _userInfos = [];

    private void LoadUsers()
    {
        for (int i = 0; i < 100; i++)
        {
            UserInfo userInfo = new()
            {
                Id = i,
                UserName = "User" + i,
                Address = "Address" + i,
            };

            if (i % 2 == 0)
            {
                userInfo.ClassInfos.Add(new ClassOne()
                {
                    ClassOneTeacher = "Teacher1"
                });
            }
            else
            {
                userInfo.ClassInfos.Add(new ClassTwo()
                {
                    ClassTwoTeacher = "Teacher2"
                });
            }
            this.UserInfos.Add(userInfo);
        }

    }

}
  • 以下是正确的绑定方式:
<TreeView
    Height="300"
    ItemsSource="{Binding UserInfos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
    ScrollViewer.VerticalScrollBarVisibility="Visible">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="True" />
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type common:UserInfo}" ItemsSource="{Binding ClassInfos}">
            <TextBlock Text="{Binding UserName}" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type common:ClassOne}">
            <TextBlock Text="{Binding ClassOneTeacher}" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type common:ClassTwo}">
            <TextBlock Text="{Binding ClassTwoTeacher}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>
  • 以下是不正确的绑定方式:
 <TreeView
     Height="300"
     ItemsSource="{Binding UserInfos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
     ScrollViewer.VerticalScrollBarVisibility="Visible">
     <TreeView.ItemContainerStyle>
         <Style TargetType="{x:Type TreeViewItem}">
             <Setter Property="IsExpanded" Value="True" />
         </Style>
     </TreeView.ItemContainerStyle>
     <TreeView.Resources>
         <HierarchicalDataTemplate DataType="common:UserInfo" ItemsSource="{Binding ClassInfos}">
             <TextBlock Text="{Binding UserName}" />
         </HierarchicalDataTemplate>
         <HierarchicalDataTemplate DataType="common:ClassOne">
             <TextBlock Text="{Binding ClassOneTeacher}" />
         </HierarchicalDataTemplate>
         <HierarchicalDataTemplate DataType="common:ClassTwo">
             <TextBlock Text="{Binding ClassTwoTeacher}" />
         </HierarchicalDataTemplate>
     </TreeView.Resources>
 </TreeView>
  • 以上你可以发现,最主要的差别其实就是DataType的内容,一个是使用x:Type,一个是使用直接使用字符串,你可以发现哪怕是第二种方法,智能提示也是没问题的,写的很丝滑,在设计时显示的也没啥差别,,一模一样的:
    datatype_design.png
  • 当你信心满满的运行的时候,你就会发现不是那么个事儿了:
    datatype_run.png
  • 你看,这写的是不是让人很生气,明明提示也有,设计时显示也是完美的,一运行就G了,这多让人挫败。其实这就涉及到强制指定DataType当前是一个类型而不是一个字符串,这样WPF才能反射获取类型,如果只是字符串,会找不到然后直接调用ToString方法。

Tips

  • 上述情况其实也可能会出现在TargetType,所以在需要指定类型的时候最好是就直接指定类型,哪怕智能提示显示没问题,设计时显示也没问题,但是很可能运行时显示就不是那么回事了。
0
博主关闭了所有页面的评论