这个问题是今天的工作中遇到的,不过却不是我解决,记录在这里,一是给自己备个份,二是可以和大家交流一下,也许还有更好的方法。
首先,建立一个WPF应用程序,FrameWork要4.0的,然后在Window里面添加一个DataGrid控件,Xaml如下:
<Window x:Class="BindingWithPeriod.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">
<Grid>
<DataGrid x:Name="dgDisplay" CanUserAddRows="False">
</DataGrid>
</Grid>
</Window>
接着,再新建一个ViewModel类,里面只有一个DataTable的属性,这个DataTable里面有列名包含点,比如"Number.A",具体代码如下:
using System;
using System.Data;
namespace BindingWithPeriod
{
public class TestViewModel
{
public TestViewModel()
{
CurrentDataTable = new DataTable();
CurrentDataTable.Columns.Add(new DataColumn("ID", typeof(string)));
CurrentDataTable.Columns.Add(new DataColumn("Number.A", typeof(int)));
Random random = new Random();
for (int i = 1; i <= 100; i++)
{
DataRow row = CurrentDataTable.NewRow();
row[0] = i.ToString();
row[1] = random.Next(-10000, 10000);
CurrentDataTable.Rows.Add(row);
}
}
public DataTable CurrentDataTable { get; set; }
}
}
最后就Binding吧,然后F5,程序就报错了,异常信息如下(通过Snoop得到的):
System.Windows.Data Error: 40 : BindingExpression path error: 'Number' property not found
on 'object' ''DataRowView' (HashCode=60213203)'. BindingExpression:Path=Number.A;
DataItem='DataRowView' (HashCode=60213203);
target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
这里,重点就来了,相信大家看到这个异常也知道原因了,Path的内容是Number.A,意思指向就是Number的A属性,但实际上Number.A是一个列名,并不存在Number属性和A属性。
后来在强大的leader的帮助下,找到了解决方案,首先,给DataGrid加AutoGeneratingColumn事件,事件里面添加如下代码:
//if the column contains period, give it a new binding.
if (e.PropertyName.Contains("."))
{
string path=string.Format("[{0}]", e.PropertyName);
((DataGridBoundColumn)e.Column).Binding = new Binding(path);
}
这样,程序就可以跑起来了,不过当你点击列Number.A,它并不会自动排序了,所以我们还需要添加一个Sorting事件来处理Number.A的排序,代码如下:
string columnName = e.Column.Header.ToString();
//if the column contains period, remove '[' and ']' and let DataView sort
automatically.
if (columnName.Contains("."))
{
e.Column.SortMemberPath = columnName.Trim(new char[] { '[', ']' });
}