Wpf 应用程序中的注释和 UI 控件

Annotation and UI control within Wpf application

我有这个视图模型class

 public  class SchoolViewModel : INotifyPropertyChanged
    {

      private  ObservableCollection<Student> _Eleves=  new ObservableCollection<Student>();

      public  ObservableCollection<Student> Eleves 
      {
          get {
              return _Eleves;
              }

          set {
              _Eleves = value;
              PropertyChanged(this, new PropertyChangedEventArgs("Eleves"));

          }
      }
      public SchoolViewModel( )
      {
      }


      public event PropertyChangedEventHandler PropertyChanged;
    }

我添加了这个简单的页面:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:SchoolViewModel x:Key="Locator" />
    </Window.Resources>
        <Grid  >
        <DataGrid  AutoGenerateColumns="True" ItemsSource="{Binding Eleves, Source={StaticResource Locator}}" ></DataGrid>
    </Grid>
</Window>

我需要扩展数据网格的行为以使其更聪明我的意思是,我有这个模型class:

 public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string FirstName { get; set; }
        public DateTime DateNaissance { get; set; }
    }

我需要向 class 属性添加一些属性,并使数据网格将其转换为 UI 控件:

例如:

[DatePicker]
 public DateTime DateNaissance { get; set; }

会在绑定到DateNaissance的datagrid中生成一列Datepicker。

我该怎么做?最好和更简单的方法是什么?

谢谢

您可以通过处理 DataGrid.AutoGeneratingColumn.

来完成

XAML:

<DataGrid x:Name="myDataGrid"
          AutoGenerateColumns="True"
          AutoGeneratingColumn="OnDataGridAutoGeneratingColumn"
          ItemsSource="{Binding Eleves, Source={StaticResource Locator}}" />

事件处理程序:

private void OnDataGridAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    PropertyInfo propertyInfo;
    PropertyDescriptor propertyDescriptor;
    IEnumerable attributes;

    if ((propertyInfo = e.PropertyDescriptor as PropertyInfo) != null)
    { attributes = propertyInfo.GetCustomAttributes(); }
    else if ((propertyDescriptor = e.PropertyDescriptor as PropertyDescriptor) != null)
    { attributes = propertyDescriptor.Attributes; }
    else
    { return; }

    ColumnAttribute attribute = attributes
        .OfType<ColumnAttribute>()
        .FirstOrDefault();

    if (attribute != null)
    { e.Column = attribute.CreateColumn(myDataGrid, e.PropertyDescriptor); }
}

用于注释属性和创建 DataGridColumns 的属性:

public abstract class ColumnAttribute : Attribute
{
    protected internal abstract DataGridColumn CreateColumn(DataGrid dataGrid, object property);
}

public class DatePickerAttribute : ColumnAttribute
{
    protected internal override DataGridColumn CreateColumn(DataGrid dataGrid, object property)
    {
        Binding binding = new Binding();
        DataGridDateColumn column = new DataGridDateColumn();

        column.Binding = binding;

        PropertyInfo propertyInfo;
        PropertyDescriptor propertyDescriptor;

        if ((propertyDescriptor = property as PropertyDescriptor) != null)
        {
            binding.Path = new PropertyPath(propertyDescriptor.Name, null);

            if (propertyDescriptor.IsReadOnly)
            {
                binding.Mode = BindingMode.OneWay;
                column.IsReadOnly = true;
            }
        }
        else if ((propertyInfo = property as PropertyInfo) != null)
        {
            binding.Path = new PropertyPath(propertyInfo.Name, null);

            if (!propertyInfo.CanWrite)
            {
                binding.Mode = BindingMode.OneWay;
                column.IsReadOnly = true;
            }
        }

        return column;
    }
}

最后是我们的专栏,里面有一个 DatePicker:

public class DataGridDateColumn : DataGridBoundColumn
{
    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        TextBlock textBlock = new TextBlock();
        BindingBase binding = Binding;

        if (binding != null)
        { BindingOperations.SetBinding(textBlock, TextBlock.TextProperty, Binding); }

        return textBlock;
    }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        DatePicker datePicker = new DatePicker();
        BindingBase binding = Binding;

        if (binding != null)
        { BindingOperations.SetBinding(datePicker, DatePicker.SelectedDateProperty, Binding); }

        return datePicker;
    }
}

注意: 这不是 MVVM 解决方案,因为您注释了模型的属性(视图在模型中指定)。如果您想要 MVVM 解决方案,则不要使用属性并根据 属性 类型选择 DataGridColumn。

你的Studentclass显然是模特。根据 MVVM,你不应该在你的 model 中定义它的 view 应该是什么样子(例如使用一些属性,比如 [DatePicker]你的例子)。

您应该在 view 中定义它,而不是这个 - 在这种情况下就是 XAML 标记。为您的数据项创建一个 DataTemplate 并描述您想要拥有的所有 聪明 事物。

请看this article。有一个很好的例子,如何为自动生成的列灵活定义 DataTemplates。

你也可以考虑this Microsoft article

此外,我建议您仔细阅读有关 MVVM 范式的内容。