2016-11-15 43 views
3

我在WPF MVVM中创建了一个动态UI应用程序,它将UI的区域绑定到我自定义的UIField类的集合。动态设置DataGridColumn的单元格内容

UIField包含多个BindingProperty属性,允许我指定Control将绑定到的属性。

public abstract class UIField : BaseObject 
{ 
    BindingProperty property, isReadonly = new BindingProperty(false, false); 
    object dataContext; 

    public BindingProperty Property 
    { 
     get { return property; } 
     set { SetProperty(ref property, value,() => Property); } 
    } 
    public BindingProperty IsReadonly 
    { 
     get { return isReadonly; } 
     set { SetProperty(ref isReadonly, value,() => IsReadonly); } 
    } 
    public object DataContext 
    { 
     get { return dataContext; } 
     set { SetProperty(ref dataContext, value,() => DataContext); } 
    } 
} 

ResourceDictionary我的模板UIField

<DataTemplate DataType="{x:Type fields:TextBoxField}"> 
    <TextBox metro:TextBoxHelper.Watermark="{e:IndirectBinding Watermark}" 
      metro:TextBoxHelper.UseFloatingWatermark="{e:IndirectBinding UseFloatingWatermark}" 
      IsReadOnly="{e:IndirectBinding IsReadonly}" 
      Text="{e:IndirectBinding Property}"     
       /> 
</DataTemplate> 

派生类,然后我在视图中创建模型这些领域,并将它们添加到集合。然后,UI使用ItemsControl

new TextBoxField() 
{ 
    DataContext = this, 
    Property = new BindingProperty(() => ((SalesOrder)Order).SecondSalesReference), 
    Watermark = new BindingProperty("Customer Ref. Number", false), 
    UseFloatingWatermark = new BindingProperty(true, false) 
} 

这是伟大的工作正常的字段,但我遇到一个问题,DataGrid结合到集合中。

最好,我希望能够绑定的UIField S作一直延伸到提供一个标题属性设置为DataGrid的列,然后这些模板来DataGridColumn个集合,但你不能有一个DataGridColumn一个DataTemplate

目前,我已经创建了一个带给我的头,DataGridColumn类型,应该是在每个单元的内容的接口:

public interface IDataGridField 
{ 
    string Header { get; set; } 

    Type ColumnType { get; } 

    UIField CellContents { get; } 
} 

我然后使用这些绑定到一个DataGrid小号列:

public class DataGridHelper 
{ 
    public static readonly DependencyProperty BindableColumnsProperty = DependencyProperty.RegisterAttached("BindableColumns", typeof(ThreadSafeCollection<IDataGridField>), typeof(DataGridHelper),new UIPropertyMetadata(null, BindableColumnsPropertyChanged)); 
    static void BindableColumnsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
    { 
     var dataGrid = source as DataGrid; 
     var columns = e.NewValue as ThreadSafeCollection<IDataGridField>; 
     dataGrid.Columns.Clear(); 
     if (columns == null) 
      return; 

     foreach (var column in columns) 
     { 
      var newColumn = Utility.CreateInstance(column.ColumnType) as DataGridColumn; 
      newColumn.Header = column.Header; 
      dataGrid.Columns.Add(newColumn); 
     } 
    } 
    public static void SetBindableColumns(DependencyObject element, ThreadSafeCollection<IDataGridField> value) 
    { 
     element.SetValue(BindableColumnsProperty, value); 
    } 
    public static ThreadSafeCollection<IDataGridField> GetBindableColumns(DependencyObject element) 
    { 
     return (ThreadSafeCollection<IDataGridField>)element.GetValue(BindableColumnsProperty); 
    } 
} 

这会给我列标题,但DataGridCell s没有内容。

如何设置创建的DataGridColumn中的每个单元格的内容?

EDIT 1(进度):

我意识到,产生的DataGridColumn必须是一个DataGridTemplateColumn所以这打开了几个属性。

我修改了IDataGridField,将UIField属性更改为Type

然后,生成新的DataGridColumn当我刚刚得到的DataTemplate分配给所选Type

foreach (var column in columns) 
{ 
    var newColumn = new DataGridTemplateColumn(); 
    var key = new DataTemplateKey(column.CellContentType); 
    var template = Application.Current.FindResource(key) as DataTemplate; 
    newColumn.CellTemplate = template; 
    newColumn.Header = column.Header; 
    dataGrid.Columns.Add(newColumn); 
} 

我认为唯一的问题正在申请绑定。

回答

0

看来你想重新发明轮子。 WPF DataGrid处理像string,bool,int这样的基本数据类型已经相当不错了。但你会有你的理由。

我认为如果您想要采用动态方法,您需要设置CellTemplate或/和CellEditingTemplate而不是创建“正确”列类型。这也适用于更复杂的数据类型。

这仅仅是XAML,但它应该表现出你能去的方向:

<DataGrid ItemsSource="{Binding}"> 
    <DataGrid.Columns> 
     <DataGridTemplateColumn> 
      <DataGridTemplateColumn.CellTemplate> 
       <DataTemplate> 
         <TextBox metro:TextBoxHelper.Watermark="{e:IndirectBinding Watermark}" 
      metro:TextBoxHelper.UseFloatingWatermark="{e:IndirectBinding UseFloatingWatermark}" 
      IsReadOnly="{e:IndirectBinding IsReadonly}" 
      Text="{e:IndirectBinding Property}"     
       /> 
       </DataTemplate> 
      </DataGridTemplateColumn.CellTemplate> 
     </DataGridTemplateColumn> 
    </DataGrid.Columns> 
</DataGrid> 

您也可以使用AutoGeneratingColumn事件DataGrid的覆盖列的创建过程。也许你想要派生你的CustomDataGrid?

private void DataGrid_AutoGeneratingColumn(object sender, System.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e) 
{ 
    //check for the type 
    if (e.PropertyType == typeof(TextField)) 
    { 
     DataGridTemplateColumn newDataGridTemplateColumn = new DataGridTemplateColumn(); 
     e.Column = newDataGridTemplateColumn; 

     //do some datatemplate voodoo, maybe you want to load it from resources or similar 
     StringReader stringReader = new StringReader(
@"<DataTemplate 
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""> 
    <" + typeof(ComboBox).Name + @" Text=""{Binding " + "Text" + @"}""/> 
</DataTemplate>"); 
     XmlReader xmlReader = XmlReader.Create(stringReader); 
     DataTemplate template = XamlReader.Load(xmlReader) as DataTemplate; 

     newDataGridTemplateColumn.CellTemplate = template; 
    } 
} 
+0

这样做的问题是,它会给我相同类型的DataTemplate。我需要能够指定不同的属性(IsReadonly等)。我认为我最好的选择可能是重写DataGridTemplateColumn和GenerateElement() – Blinx