none
Привязывание данных из базы данных к DataGrid с помощью LINQ запроса с помощью механизма Databinding RRS feed

  • Вопрос

  • Добрый день.

    У меня есть WPF-приложение, работающее с базой данных SQL Server. Мне необходимо вывести данные из таблицы базы данных в окно приложения (в DataGrid), для этого я написал простой LINQ-запрос:

    from d in App.glidusContext.tbl_users
     select new { d.userID, d.userName, d.userPassword }
    

    Теперь мне осталось каким-то образом привязать результаты этого запроса к DataGrid, причем сделать это надо так, чтобы данные в DataGrid можно было бы изменять, удалять, добавлять и чтобы все эти изменения сохранялись бы по запросу пользователя (нажатию на «Сохранить») и в базе данных.

    Мой DataGrid:
    <DataGrid x:Name="ContentDataGrid">
     <DataGrid.Columns>
     <DataGridTextColumn Header="User ID"
     Binding="{Binding userID}" />
     <DataGridTextColumn Header="User name"
     Binding="{Binding userName}" />
     <DataGridTextColumn Header="Password"
     Binding="{Binding userPassword}" />
     </DataGrid.Columns>
    </DataGrid>
    

    Из многочисленных примеров в интернете следует, что необходимо указать ItemSource и DataContext, а также определить Mode=TwoWay.

    Чтобы реализовать задуманное я поместил результаты LINQ-запроса в IBindingList users, а дальше связал эти данные с DataGrid, в результате получилось:
    <DataGrid x:Name="ContentDataGrid"
     Style="{StaticResource ContentDataGrid}"
     ItemsSource="{Binding}">
     <DataGrid.Columns>
     <DataGridTextColumn Header="User ID"
     Width="100"
     Binding="{Binding userID}" />
     <DataGridTextColumn Header="User name"
     Width="100"
     Binding="{Binding userName}" />
     <DataGridTextColumn Header="Password"
     Width="*"
     Binding="{Binding userPassword}" />
     </DataGrid.Columns>
    </DataGrid>
    

    После компиляции и запуска программы в ее окне отобразилась таблица с результатами запроса к базе данных, НО при этом изменить данные или удалить их не удается, программа «падает» с исключением: «InvalidOperationException» и сообщением об ошибке: «A TwoWay or OneWayToSource binding cannot work on the read-only property 'userPassword' of type '<>f__AnonymousType0`3[System.Int32,System.String,System.String]'».

    В параметрах привязки данных я пробовал прописывать вручную Mode=TwoWay, но Visual Studio 2010 выдает ошибку, что IBindingList только для чтения и OneWayToSource/TwoWay не может быть активирован для этой привязки.

    Народ, подскажите, пожалуйста, как реализовать возможность отображения, изменения и удаления данных из БД с помощью DataGrid и через Databinding.

    Спасибо!

     

    9 октября 2010 г. 23:48

Ответы

  • 2. Сортировка по умолчанию в датагриде включена. Попробуй убрать из стиля или посмотри, не переопределено ли это свойство на уровне DataColumn?

    Разобрался с сортировкой, этот код решает мою проблему и позволяет сортировать столбцы в DataGrid:

    IList users = (from d in App.glidusContext.tbl_users select d).ToList();
    ContentDataGrid.DataContext = users;
    

    Весь прикол в том, что отдавать данные в DataContext надо в виде листа, применяя метод ToList(), по всей видимости, при попытке сортировки DataGrid просто вызывает метод Sort() и если таковой имеется у данных, привязанных к гриду, то все сортируется, в противном случае сортировки не происходит.

     

    • Предложено в качестве ответа ulcerModerator 12 октября 2010 г. 4:09
    • Помечено в качестве ответа Toucki 12 октября 2010 г. 10:58
    11 октября 2010 г. 23:38

Все ответы

  • 1. Чтобы работал TwoWay нужно избавиться от вывода анонимного типа в запросе (достаточно убрать new ).

    from d in App.glidusContext.tbl_users select d;
    

    2. Чтобы сохранить изменения нужно использовать функцию SubmitChanges на датаконтексте.

     

    App.glidusContext.SubmitChanges();
    

     

    10 октября 2010 г. 8:44
    Модератор
  • 1. Чтобы работал TwoWay нужно избавиться от вывода анонимного типа в запросе (достаточно убрать new ).

    from d in App.glidusContext.tbl_users select d;
    

    2. Чтобы сохранить изменения нужно использовать функцию SubmitChanges на датаконтексте.

    App.glidusContext.SubmitChanges();

    Изменил запрос в соответствии с вашей рекомендацией, потом решил проверить что реально возвращает этот запрос с помощью следующего кода:

    IBindingList users = ((from d in App.glidusContext.tbl_users select d) as IListSource).GetList() as IBindingList;
    
    foreach (var a in users)
    {
    	MessageBox.Show(a.ToString());
    }
    
    

    Оказалось, что MessageBox выводить название таблицы: «Glidus.tbl_users», а как именно мне добраться до столбцов таблицы — userName, userID, password при этом чтобы соблюдались бы все требования и условия, указанные в первом посте — работал бы Mode=TwoWay, изменение и удаление данных из DataGrid и из самой базы данных.

    Спасибо.

    10 октября 2010 г. 11:49
  • Не совсем ясен сакральный смысл преобразования в IListSource и IBindingSource, но наверно стоит попробовать a["userName"]  и тд...
    10 октября 2010 г. 18:40
    Модератор
  • Не совсем ясен сакральный смысл преобразования в IListSource и IBindingSource, но наверно стоит попробовать a["userName"]  и тд...

    Никакого сакрального смысла нет, просто такой пример приводился в одном из скрикастов по работе с DataBinding на Techdays.ru.

    Немного модифицировав код запроса у меня вышло:

    IQueryable users = from d in App.glidusContext.tbl_users select d;
    DataContext = users;
    

    в XAML-файле же я написал:

    <DataGrid x:Name="ContentDataGrid"
    		ItemsSource="{Binding}">
    	<DataGrid.Columns>
    		<DataGridTextColumn Header="UserID"
    			Binding="{Binding userID}" />
    		<DataGridTextColumn Header="UserName"
    			Binding="{Binding userName}" />
    		<DataGridTextColumn Header="Password"
    			Binding="{Binding password}" />
    	</DataGrid.Columns>
    </DataGrid>
    

    В результате компиляции я получил DataGrid со всеми данными из таблицы, внутри этой DataGrid данные можно изменять и удалять, НО, к сожалению, все эти изменения не сохраняются в самой базе данных и пропадают после закрытия программы. Насколько я понимаю, для устранения этого бага необходимо прописать Mode=TwoWay, который, в свою очередь, требует прописать Path, а вот он-то как раз-то и не определен для моего случая, по крайней мере в конструктуре биндинга в VS2010 в разделе Path нет возможности выбрать какой-либо параметр, есть только метка «None».

    Подскажите, пожалуйста, что нужно исправить, чтобы все изменения, внесенные и отображенные в DataGrid также вносились бы и в базу данных.

    И ещё одно, у меня не работает сортировка данных по столбцам, несмотря на то, что в настройках XAML-стиля (в коде выша эта опция опущена для уменьшения объёма фрагмента) для DataGrid явно прописано:

    <Setter Property="CanUserSortColumns"
    		Value="True" />
    

    Как включить сортировку данных в DataGrid?

    Зараннее спасибо!

    10 октября 2010 г. 22:45
  • 1. SubmitChages пробовал перед закрытием формы делать?

    2. Сортировка по умолчанию в датагриде включена. Попробуй убрать из стиля или посмотри, не переопределено ли это свойство на уровне DataColumn?

    11 октября 2010 г. 4:24
    Модератор
  • 2. Сортировка по умолчанию в датагриде включена. Попробуй убрать из стиля или посмотри, не переопределено ли это свойство на уровне DataColumn?

    Удалил из стиля XAML «CanUserSortColumns», перекомпилировал теперь вообще пропал какой-либо намек на сортировку столбцов, если раньше при нажатии на заголовок там появлялись стрелочки вниз/вверх, но самой сортировки не происходило, то теперь при нажатии на заголовок столбца вообще никакой реакции не возникает — данные не сортируются, стрелочки не появляются.
    11 октября 2010 г. 13:18
  • 2. Сортировка по умолчанию в датагриде включена. Попробуй убрать из стиля или посмотри, не переопределено ли это свойство на уровне DataColumn?

    Разобрался с сортировкой, этот код решает мою проблему и позволяет сортировать столбцы в DataGrid:

    IList users = (from d in App.glidusContext.tbl_users select d).ToList();
    ContentDataGrid.DataContext = users;
    

    Весь прикол в том, что отдавать данные в DataContext надо в виде листа, применяя метод ToList(), по всей видимости, при попытке сортировки DataGrid просто вызывает метод Sort() и если таковой имеется у данных, привязанных к гриду, то все сортируется, в противном случае сортировки не происходит.

     

    • Предложено в качестве ответа ulcerModerator 12 октября 2010 г. 4:09
    • Помечено в качестве ответа Toucki 12 октября 2010 г. 10:58
    11 октября 2010 г. 23:38
  • Только не SubmitChanges(), а 
    glidusContext.SaveChanges();
    
    Именно этот метод позволяет сохранить внесенные изменения в базу данных.
    14 октября 2010 г. 23:25
  • Так Linq или EF?
    15 октября 2010 г. 5:51
    Модератор
  • EF - это тоже LINQ :)
    15 октября 2010 г. 12:21