我正在 WPF MVVM 中创建动态 UI 应用程序,它将 UI 区域绑定(bind)到我的自定义 UIField
类的集合。
UIField
包含许多 BindingProperty
属性,允许我指定 Control
将绑定(bind)到的属性。
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>
然后我在 View 模型中创建这些字段并将它们添加到集合中。然后,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
的问题。
最好,我希望能够绑定(bind)已扩展的 UIField
集合,为 DataGrid
的列提供 Header 属性,然后绑定(bind)模板这些到 DataGridColumn
,但您不能在 DataTemplate
中有 DataGridColumn
。
目前,我已经创建了一个界面,为我提供标题、DataGridColumn
类型和每个单元格中应包含的内容:
public interface IDataGridField
{
string Header { get; set; }
Type ColumnType { get; }
UIField CellContents { get; }
}
然后我使用以下方法将它们绑定(bind)到 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
中没有内容的列。
如何设置创建的 DataGridColumn
中每个单元格的内容?
编辑 1(进度?):
我意识到生成的 DataGridColumn
必须是 DataGridTemplateColumn
,因此这会打开更多属性。
我修改了 IDataGridField
,将 UIField
属性更改为 Type
。
然后,在生成新的 DataGridColumn
时,我只获取分配给所选 Type
的 DataTemplate
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);
}
我认为现在唯一的问题是应用绑定(bind)。
最佳答案
看来你想重新发明轮子。 WPF DataGrid 已经很好地处理基本的数据类型,如字符串、 bool 、整数。但是您会有自己的理由。
我认为如果您想采用动态方法,您需要设置 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
事件来覆盖列的创建。也许您想派生您的 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;
}
}
关于c# - 动态设置 DataGridColumn 的单元格内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40608915/