RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1092911
Accepted
pinkertem
pinkertem
Asked:2020-03-10 18:29:18 +0000 UTC2020-03-10 18:29:18 +0000 UTC 2020-03-10 18:29:18 +0000 UTC

如何在 WPF 中为 ListView 手动创建列?

  • 772

有员工,他们有很多字段——姓氏、名字等。我想以表格的形式显示所有员工的列表。它发生在具有 MVVM 模式的 Wpf 中。所以我有一个这样的片段视图:

<ListView
    ItemsSource="{Binding Path=AllEmployees}"
    >
    <ListView.View>
        <GridView>
            <GridViewColumn
                Header="Фамилия"
                DisplayMemberBinding="{Binding Path=LastName}"
                />
            <GridViewColumn
                Header="Имя"
                DisplayMemberBinding="{Binding Path=FirstName}"
                />
        </GridView>
    </ListView.View>
</ListView>

因此,有一个 ViewModel,其中 AllEmployees 是一个包含员工对象的集合。这些对象仅具有 LastName、FirstName 等属性。

我想要的是?不要用手声明每个 GridViewColumn 也不要给它一个 Header 和绑定,而是像这样在 ViewModel 中声明一些字典(或其他东西,我只是举了一个例子)

public Dictionary<string, string> Columns = new Dictionary<string, string>()
{
    { "EmployeeId", "Табельный №" },
    { "TitleOfCourtesy", "Обращение" },
    { "LastName", "Фамилия" },
    { "FirstName", "Имя" },
    { "Title", "Должность" },
    { "HireDate", "Дата найма" },
    { "ReportsTo", "Подчиняется" }
};

并从此字典中形成 GridViewColumns。因此,通过键,可以清楚地从员工对象中获取哪个属性,并通过值 - 在表中为该属性赋予什么标题。

我无法弄清楚如何在 XAML 中执行此操作。以某种方式通过列模板,或以其他方式。

c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    EvgeniyZ
    2020-03-12T09:51:08Z2020-03-12T09:51:08Z

    此行为可以使用AttachedProperty.

    • 让我们创建一个静态类,我们称它为 valid GridViewColumns。
    • 在这个类中,我们创建了三个AttachedProperty(在工作室中有一个片段 - propa):

      • 第一个将被称为Source( object) - 它将用于指定带有列的集合。
      • 第二个将是Header( string) - 将负责标题。
      • 好吧,最后一个DisplayMember( string) - 负责该列应显示的属性的名称。

      我们最终会得到这样的结果:

      public static object GetSource(DependencyObject obj) => obj.GetValue(SourceProperty);
      public static void SetSource(DependencyObject obj, object value) => obj.SetValue(SourceProperty, value);
      public static readonly DependencyProperty SourceProperty =
          DependencyProperty.RegisterAttached("Source", typeof(object), typeof(GridViewColumns), new UIPropertyMetadata(default));
      
      public static string GetHeader(DependencyObject obj) => (string)obj.GetValue(HeaderProperty);
      public static void SetHeader(DependencyObject obj, string value) => obj.SetValue(HeaderProperty, value);
      public static readonly DependencyProperty HeaderProperty =
          DependencyProperty.RegisterAttached("Header", typeof(string), typeof(GridViewColumns), new UIPropertyMetadata(default));
      
      public static string GetDisplayMember(DependencyObject obj) => (string)obj.GetValue(DisplayMemberProperty);
      public static void SetDisplayMember(DependencyObject obj, string value) => obj.SetValue(DisplayMemberProperty, value);
      public static readonly DependencyProperty DisplayMemberProperty =
          DependencyProperty.RegisterAttached("DisplayMember", typeof(string), typeof(GridViewColumns), new UIPropertyMetadata(default));
      
    • 现在让我们订阅更新Source并在处理程序中为此事件创建测试列:

      • 我们在注册中添加我们需要的Sourcehandler

        new UIPropertyMetadata(default, SourceChanged)
        
      • 我们创建处理程序本身,在其中检查对象的类型,如果有新对象,则创建列:

        private static void SourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj is GridView gridView)
            {
                if (e.NewValue != null)
                {
                    ICollectionView view = CollectionViewSource.GetDefaultView(e.NewValue);
                    if (view != null)
                    {
                        CreateColumns(gridView, view);
                    }
                }
            }
        }
        
      • 好吧,一个简单的生成列的方法:

        private static void CreateColumns(GridView gridView, ICollectionView view)
        {
            foreach (var item in view)
            {
                GridViewColumn column = new GridViewColumn
                {
                    Header = "Привет мир!"
                };
                gridView.Columns.Add(column);
            }
        }
        

      我们绑定所有东西,运行它,看到我们已经成功创建了一个测试列(我在测试集合中有1个对象)

      结果 1

    太好了,已经完成了一半的工作,我们还需要处理标题和属性。

    • 让我们创建一个返回属性值的辅助方法:

      private static T GetPropertyValue<T>(object obj, string propertyName)
      {
          if (obj == null) return default;
          PropertyInfo prop = obj.GetType().GetProperty(propertyName);
          return (T)prop?.GetValue(obj, null);
      }
      
    • 此外,为方便起见,我们会将一列的生成移到单独的方法中。
      在这个方法中,我们从属性DisplayMember和Header它们的值中获取,如果它们不为空,那么我们分配它们:

      private static GridViewColumn CreateColumn(GridView gridView, object columnSource)
      {
          GridViewColumn column = new GridViewColumn();
          string header = GetHeader(gridView);
          string displayMemberMember = GetDisplayMember(gridView);
      
          if (!string.IsNullOrEmpty(header))
              column.Header = GetPropertyValue<string>(columnSource, header);
      
          if (!string.IsNullOrEmpty(displayMemberMember))
          {
              string propertyName = GetPropertyValue<string>(columnSource, displayMemberMember);
              column.DisplayMemberBinding = new Binding(propertyName);
          }
          return column;
      }
      
    • 让我们重写方法中列的创建CreateColumns:

      GridViewColumn column = CreateColumn(gridView, item);
      

    就是这样,这是一个这样的实现的基本示例,让我们测试一下:

    • 创建测试数据:

      class Person
      {
          public Person(string name, int age)
              => (Name, Age) = (name, age);
      
          public string Name { get; set; }
          public int Age { get; set; }
      }
      
      class Column
      {
          public Column(string header, string displayMember)
              => (Header, DisplayMember) = (header, displayMember);
      
          public string Header { get; }
          public string DisplayMember { get; }
      }
      
      class MainViewModel
      {
          public ObservableCollection<Column> Columns { get; } = new ObservableCollection<Column>
          {
              new Column("Имя", "Name")
          };
      
          public ObservableCollection<Person> People { get; } = new ObservableCollection<Person>
          {
              new Person("Вася", 12),
              new Person("Петя", 19)
          };
      }
      
    • 我们在 XAML 中绑定所有内容:

      <ListView ItemsSource="{Binding People}">
          <ListView.View>
              <GridView
                  local:GridViewColumns.DisplayMember="DisplayMember"
                  local:GridViewColumns.Header="Header"
                  local:GridViewColumns.Source="{Binding Columns}" />
          </ListView.View>
      </ListView>
      

      这里DisplayMember, 和Header是类中相应属性的名称Column, 和Source是列集合本身。

    结果将是包含此人姓名的一列:

    结果 2

    让我们再添加几列:

    public ObservableCollection<Column> Columns { get; } = new ObservableCollection<Column>
    {
        new Column("Имя", "Name"),
        new Column("Возраст", "Age"),
        new Column("Неизвестная 1", null),
        new Column("Неизвестная 2", null)
    };
    

    结果:

    结果 3

    如您所见,一切顺利。我以这个答案为基础,它有很多东西我没有在这里开始转移,因为我的任务是展示基本原理,我把这个的进一步发展留给你。

    • 3

相关问题

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5