WPF动态数据网格绑定方法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF动态数据网格绑定方法相关的知识,希望对你有一定的参考价值。
我没有在c#编程和使用WPF的长期经验,如果我的“词汇”不够技术或适当,我道歉。
我需要在我的应用程序中显示一个表,其中行是类的实例,列是定义我的对象的properties/attributes
。
public class myObject
{
//constructor
public myObject() { }
//properties
public string Topic { get; set}
public string Description { get; set; }
public bool Display { get; set; }
public List<myAttribute> AttributeList { get; set; }
//method
public string GetAttributeValueByName(string sAttributeName)
{
foreach (myAttribute A in this.AttributeList)
{
if (A.Name == sAttributeName) { return A.Value.ToString(); }
}
return string.Empty;
}
}
我有一个myObjects
列表,我绑定为datagrid.ItemSource
,我已经能够正确绑定定义的属性,如主题/描述,并在列中显示它们。 myObject.Display
也是单向绑定的,让我可以在数据网格中可视化myObject
(作为一种来自其他地方的过滤器)。
现在,正如您在上面的代码中所注意到的,我有一个属性,它返回一个属性列表。这是因为myObject
具有用户可以设置的未定义数量的自由属性。我为这个属性设置了一个合适的类(只有很少的简单属性,如.Name
,.Value
,.Color
,.Rank
)。我有方法让我可以将值作为字符串检索,例如左右。
我的主要问题是我无法在数据网格中正确地显示它们,因为通常,绑定适用于属性而不适用于方法。我做了一些关于绑定方法的研究,我尝试过任何成功的结果。
简述:
- 我需要动态列(一些固定像Topic +每个属性一个)
- 所有myObjects在AttributeList中具有相同数量的元素
- 我需要在datagrid的正确单元格中绑定(至少单向)属性的值。
UI类:
namespace myApp.UserInterface
{
public partial class control : UserControl
{
control()
{
InitializeComponent();
InitializeData();
}
private InitializeData()
{
datagrid.ItemsSource = Core.myObjectPoolList;
}
}
}
Ui A ML
<UserControl x:Class="myApp.UserInterface.control"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:myApp.UserInterface;assembly="
xmlns:core="clr-namespace:myObject.Core;assembly="
xmlns:system="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ObjectDataProvider x:Key="basic_attribute_value"
ObjectType="{x:Type core:D2P_Issue}"
MethodName="GetAttributeValueByName"
IsAsynchronous="True">
<ObjectDataProvider.MethodParameters>
<system:String>status</system:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</UserControl.Resources>
<Grid>
<DataGrid Name="issuepool_datagrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Topic" Binding="{Binding Topic}" Width="150" TextBlock.TextAlignment="Center"/>
<DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="150" TextBlock.TextAlignment="Center"/>
<DataGridTextColumn x:Name="status_column" Header="status" Binding="{Binding Source={StaticResource basic_attribute_value}, Mode=OneWay}" Width="150" TextBlock.TextAlignment="Center"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
在这个例子中,我试图留下动态生成列,只需对其进行硬编码以查找“status”属性名称。
如果有什么不清楚,请随时询问。
您可以在后面的代码中动态创建列。虽然很简单。如果要在同一个项目中多次重复使用,可以将其重写为附加行为,并使用另一个附加属性将动态列集合存储在网格本身上。
由您决定何时更改属性集,并相应地更新列。我已经将动态列存储在字典中,以简化智能更新它们的业务,如果您碰巧知道只添加或删除了一个属性。
如果你是,我也会用myObject.AttributeList
取代Dictionary<String, myAttribute>
。绑定路径必须稍微改变。
这允许用户编辑属性值。如果您愿意,可以在动态列上设置IsReadOnly = true
。
public partial class control : UserControl
{
control()
{
InitializeComponent();
InitializeData();
}
private InitializeData()
{
datagrid.ItemsSource = Core.myObjectPoolList;
var firstItem = Core.myObjectPoolList.First();
if (firstItem != null) {
UpdateDataGridColumns(dataGrid, firstItem.AttributeList, _dynamicColumns);
}
}
private Dictionary<string, DataGridColumn> _dynamicColumns = new Dictionary<string, DataGridColumn>();
protected void UpdateDataGridColumns(DataGrid dg, List<myAttribute> attributesSample, Dictionary<string, DataGridColumn> existingDynamicColumns)
{
foreach (var col in existingDynamicColumns.Values)
{
dg.Columns.Remove(col);
}
existingDynamicColumns.Clear();
int idx = 0;
foreach (var attr in attributesSample)
{
var column = new DataGridTextColumn() {
Header = attr.Name,
Binding = new Binding($"AttributeList[{idx}].Value")
};
dg.Columns.Add(column);
existingDynamicColumns.Add(attr.Name, column);
++idx;
}
}
}
替代方法:将所有属性放在一列中。这不使用上面的代码。这只是这种形式的读取,但可以适应让用户编辑网格中的值。
将此属性添加到myObject
:
public IEnumerable<String> AttributeNames
=> AttributeList.Select(a => a.Name);
这对于XAML中的DataGrid.Columns
:
<DataGridTemplateColumn
Width="*"
>
<DataGridTemplateColumn.HeaderStyle>
<Style>
<Setter Property="ContentControl.HorizontalContentAlignment" Value="Stretch" />
</Style>
</DataGridTemplateColumn.HeaderStyle>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<ItemsControl
ItemsSource="{Binding DataContext.Items[0].AttributeNames, RelativeSource={RelativeSource AncestorType=DataGrid}}"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label
Content="{Binding}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl
ItemsSource="{Binding AttributeList}"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Value}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
为什么不使用DataGridComboBoxColumn?
像这样的东西:
<DataGridComboBoxColumnHeader="Attributes" Binding="{Binding AttributeList}" width="150" TextBlock.TextAlignment="Center"/>
以上是关于WPF动态数据网格绑定方法的主要内容,如果未能解决你的问题,请参考以下文章