Двусторонняя привязка к сетке данных в WPF

#c# #wpf #xaml #wpfdatagrid

#c# #wpf #xaml #wpfdatagrid

Вопрос:

У меня есть сетка данных WPF, которую я заполняю с помощью

 var allLines = from Lines in ctx.InvoiceLines join PerPs in ctx.ProductsViews on Lines.ProductCode equals PerPs.ProductCode 
               where (Lines.BranchNo == BrNo) amp;amp; (Lines.Docket == Docket)
               select new { Lines.ProductCode, Lines.Description, Lines.Inv_Quantity, Lines.Grn_Quantity,
                Lines.Inv_Price,Lines.Grn_Price,Lines.Inv_Total, Lines.Grn_Total, Lines.AnalCode,
                Lines.Vat_Rate, Lines.GrnNo,Lines.Comment , PerPs.OuterUnits};

dgGrid.ItemsSource = allLines;
  

Я хочу использовать двустороннюю привязку для обновления базы данных при изменении любого из значений или при добавлении новой строки. Возможно ли это?

Мой код xaml

 <DataGrid Grid.Row="3" x:Name="dgGrid" DataContext="{Binding}" FontSize="16" HorizontalScrollBarVisibility="Visible" 
              VerticalScrollBarVisibility="Visible" SelectionUnit="FullRow" SelectionMode="Extended" AutoGenerateColumns="False"
              SelectionChanged="dgGrid_SelectionChanged" >
        <DataGrid.Columns>
            <DataGridTextColumn Width="Auto" Header="ProductCode"  Binding="{Binding ProductCode, Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="250" Header="Description"  Binding="{Binding Description,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" FontSize="14"/>
            <DataGridTextColumn Width="61" Header="Inv_Quantity" Binding="{Binding Inv_Quantity,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="63" Header="Grn_Quantity" Binding="{Binding Grn_Quantity,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="59" Header="Inv_Price" Binding="{Binding Inv_Price,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="61" Header="Ord_Price" Binding="{Binding Grn_Price,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="72" Header="Inv_Total" Binding="{Binding Inv_Total, Converter={StaticResource Currency},  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="74" Header="Grn_Total" Binding="{Binding Grn_Total, Converter={StaticResource Currency},  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="58" Header="AnalCode" Binding="{Binding AnalCode,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="40" Header="Vat_Rate" Binding="{Binding Vat_Rate,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="Auto" Header="GrnNo"  Binding="{Binding GrnNo,  Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="Auto" Header="Comment" Binding="{Binding Comment, Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
            <DataGridTextColumn Width="Auto" Header="PerP" Binding="{Binding OuterUnits}" IsReadOnly="True"/>
        </DataGrid.Columns>
        <DataGrid.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightSteelBlue"/>
        </DataGrid.Resources>
    </DataGrid>
  

Когда я запускаю этот код, все столбцы, кроме PerP, пусты.

Я совершенно не понимаю, как сделать это наилучшим образом, поэтому любая помощь будет очень признательна.

Ответ №1:

Все Bindings для вашего DataGridTextColumn столбца, кроме столбца «PerP», указывают путь дважды. Например:

 <DataGridTextColumn Width="Auto" Header="ProductCode"  Binding="{Binding ProductCode, Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
  

Здесь вы Binding сначала указываете путь, который должен быть «ProductCode», а затем также указываете его как «IsSelected». Поскольку для объектов в коллекции, которые вы привязываете к сетке, нет свойства «IsSelected», если вы запустите это в отладчике, вы должны увидеть ошибки привязки в окне вывода. Если вы удалите Path=IsSelected для этих привязок, значения столбцов должны быть привязаны правильно.

Ваш источник данных представляет собой коллекцию анонимного типа, поэтому var это необходимо, но, как говорили другие, двусторонняя привязка к этой коллекции не будет работать для обновлений обратно к источнику.

Комментарии:

1. Есть ли другой способ сделать это, который будет поддерживать двустороннюю привязку для обновлений?

2. Да, путем привязки к экземплярам фактического объекта, который вы хотите обновить, который в вашем случае будет объектами, отслеживаемыми Entity Framework. Я предполагаю, что в конечном итоге вы хотите, чтобы изменения сохранялись обратно в базу данных, поэтому имеет смысл, чтобы обновления влияли на объекты EF, которые выполняют отслеживание изменений, чтобы позже все изменения можно было сбросить в базу данных.

3. Есть ли у вас ссылка на какие-либо сайты, которые показали бы, как это можно сделать?

4. Спасибо, Стив, это действительно хорошее видео, я думаю, это именно то, что мне было нужно. 🙂

5. @Steve Rowbotham, у меня странное чувство от этого видео, как будто я в параллельной вселенной. Я никогда не получаю источник данных при создании модели EF. Я думал, что источники данных предназначены только для старомодных табличных адаптеров.

Ответ №2:

Ваша allLines переменная является перечислимой анонимного типа. В C # анонимные типы доступны только для чтения — свойства нельзя редактировать, а изменения нельзя сохранить.

Попробуйте выполнить свой запрос:

 var allLines = 
    from Lines in ctx.InvoiceLines 
    join PerPs in ctx.ProductsViews on Lines.ProductCode equals PerPs.ProductCode 
    where (Lines.BranchNo == BrNo) amp;amp; (Lines.Docket == Docket)
    select Lines;

dgGrid.ItemsSource = allLines.ToList();
  

Комментарии:

1. Вместо того, чтобы проецировать результаты вашего запроса в коллекцию анонимного типа (т. Е. С использованием new {...} ), Выберите фактические строки, как показал Пол выше, поскольку они должны отслеживать внесенные в них изменения.

Ответ №3:

Если переменной «allLines» является a DataTable , вы можете просто установить для вашей сетки AutoGenerateColumns данных значение true .
Вам также не нужно использовать свойство «DataContext», а вместо него «ItemsSource».
Что-то вроде этого:

 <DataGrid ItemsSource="{Binding Path=allLines.DefaultView}" ... />
  

Чтобы обновить базу данных при изменениях, вызовите Update() метод вашей таблицы данных, например, нажав кнопку «Сохранить».

Если «allLines» не является объектом данных, то удалите это адское ключевое слово «var» и сообщите нам истинную природу переменной =)

Комментарии:

1. Когда я использую ItemsSource, DG пуст. Я не знаю, какой тип данных allLines на самом деле

2. Из кода довольно ясно, что переменная в левой части присваивания не является объектом данных, так что это не имеет значения. Очевидно, что это коллекция анонимного типа, поэтому необходим var.