0

I've managed to stump myself with LINQ. I am trying to create an editable datagrid in a WPF app using a subset gathered from a LINQ query:

var LookUpEvents = from d in ThisData.Events.Local
                   where d.StartDate.Value.Date <= DateTime.Now.Date &&
                   (d.EndDate.HasValue == false || d.EndDate.Value.Date >= DateTime.Now.Date)
                   select d;
RangeEventGrid.ItemsSource = LookUpEvents;
RangeEventGrid.Items.Refresh();

This query works, and the datagrid is populated however I am unable to edit the datagrid, when trying to this exception is thrown:

"'EditItem' is not allowed for this view."
   at System.Windows.Controls.ItemCollection.System.ComponentModel.IEditableCollectionView.EditItem(Object item)
   at System.Windows.Controls.DataGrid.EditRowItem(Object rowItem)

When loading the full dataset using:

ThisData.Events.Load();
FullEventGrid.ItemsSource = ThisData.Events.Local;

Everything works fine and the data is editable. The XAML used is identical (I have also tried swapping the bound datagrids and the full result remains editable and the query throws the exception still) and the only difference between these is the query. When I try to change the query I end up with a new exception:

The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

The query used for that:

var LookUpEvents = from d in ThisData.Events
                   where d.StartDate.Value.Date <= DateTime.Now.Date &&
                   (d.EndDate.HasValue == false || d.EndDate.Value.Date >= DateTime.Now.Date)
                   select d;
LookUpEvents.Load(); //Exception thrown here.
RangeEventGrid.ItemsSource = LookUpEvents;
RangeEventGrid.Items.Refresh();

The really weird thing about that exception (weird to me at least) is that I use DateTime comparison in other queries that do not throw any exceptions, for example this query in another place works fine:

var LookUpSessions = from d in ThisData.Sessions
                     where d.EndTime.Hour >= (DateTime.Now.Hour - 1) && d.StartTime.Hour <= (DateTime.Now.Hour + 2)
                     && d.Event.IsActive == true
                     orderby d.StartTime.Hour, d.StartTime.Minute
                     select d;

Is it not possible to bind a LINQ query result to a DataGrid to be editable? That seems like it'd be a huge oversight if that's the case. I feel like it's much more likely I'm just missing something basic since LINQ, WPF and EF are all brand new to me.

Thanks in advance.

4

2 回答 2

4

要使在 GridView 中编辑数据成为可能,您不能使用IEnumerable<T>IQueryable<T>作为项目源。IList您需要一个实现或IEnumerable<T>不实现的集合类型IQueryable<T>

一个可能的解决方案是您从 LINQ 查询创建一个ObservableCollection<T>(确实实现):IList

RangeEventGrid.ItemsSource = new ObservableCollection<Event>(LookUpEvents);

这也是为什么

FullEventGrid.ItemsSource = ThisData.Events.Local;

确实有效,因为Local已经是 type ObservableCollection<Event>

您的第一个查询不会引发异常(尽管您正在使用DateTime.Date),因为它不是 LINQ-to-Entities/database 查询。它是在Local集合的内存中运行的 LINQ-to-Objects 查询。不涉及数据库查询。

如果删除Local,则运行 LINQ-to-Entities 和 LINQ-to-Entities 不支持 LINQ-to-Objects 支持的所有方法和属性,尤其是它不支持DateTime.Date(但显然确实支持DateTime.Hour)。

要在 LINQ-to-Entities 查询中执行比较,Date您可以使用EntityFunctions

var today = DateTime.Now.Date;
var LookUpEvents = from d in ThisData.Events
                   where EntityFunction.TruncateTime(d.StartDate) <= today &&
                         (!d.EndDate.HasValue ||
                          EntityFunction.TruncateTime(d.EndDate) >= today)
                   select d;

或者,该EntityFunction.DiffDays功能也是一种选择。

于 2012-11-08T22:06:10.170 回答
1

并且问题解决了!

添加.ToList()到绑定中并且可以正常工作!

完整的工作 LINQ 查询:

var LookUpEvents = from d in ThisData.Events.Local
                   where d.StartDate.Value.Date <= DateTime.Now.Date &&
                   (d.EndDate.HasValue == false || d.EndDate.Value.Date >= DateTime.Now.Date)
                   select d;

// Old binding: RangeEventGrid.ItemsSource = LookUpEvents;
// New binding:
RangeEventGrid.ItemsSource = LookUpEvents.ToList(); // .ToList() Fixes it!
RangeEventGrid.Items.Refresh();

自我回答以纪念http://xkcd.com/979/

于 2012-11-08T22:03:18.330 回答