[英]Two way binding in WPF trough LINQ to SQL for the property of a ListItem of a ListBox using a DataTemplate
I am quite new to C# and WPF. 我是C#和WPF的新手。 Despite the vast documentation, tutorials and previous questions that I have read, I can't seem to find my scenario covered. 尽管我阅读了大量的文档,教程和以前的问题,但我似乎无法找到我的场景。
I have a WPF Application in C# with a single Window containing a ListBox. 我在C#中有一个WPF应用程序,其中包含一个包含ListBox的Window。 The ListBox defines a DataTemplate to display its items with a TextBox for each ListItem. ListBox定义了一个DataTemplate,用于为每个ListItem显示带有TextBox的项目。
I have a Microsoft SQL Express server on the same machine, which contains a database named Test
with a view named Client
which exposes the columns id INT PRIMARY KEY IDENTITY
and name VARCHAR(50) NOT NULL
of another table, and a stored procedure named Client_update(@id, @name)
that sets the name
column of the client whose id
is @id
via a simple UPDATE statement on the same table. 我在同一台机器上有一个Microsoft SQL Express服务器,它包含一个名为Test
的数据库,其中包含一个名为Client
的视图,它公开了另一个表的列id INT PRIMARY KEY IDENTITY
和name VARCHAR(50) NOT NULL
,以及一个名为Client_update(@id, @name)
的存储过程Client_update(@id, @name)
id
,@ name
Client_update(@id, @name)
通过同一个表上的简单UPDATE语句设置id
为@id
的客户端的name
列。
What I'm trying to achieve is to have the ListBox to be populated on window load, and to have changes to the data (which is contained in text boxes) persisted to the database (trough the stored procedure) by switching focus to another component of the GUI. 我想要实现的是在窗口加载时填充ListBox,并通过将焦点切换到另一个组件来对数据(包含在文本框中)的更改持久保存到数据库(通过存储过程)的GUI。
I have added a new LINQ to SQL Classes element to my project using Visual Studio, which resulted in the creation of a DataContext class named DataClassesDataContext
. 我使用Visual Studio向项目中添加了一个新的LINQ to SQL Classes元素,从而创建了一个名为DataClassesDataContext
的DataContext类。 I have used the OR Designer in Visual Studio to map the view to the Class Client
and the stored procedure to the method Client_update(id, name)
. 我使用Visual Studio中的OR Designer将视图映射到Class Client
,将存储过程映射到Client_update(id, name)
。 Then I have set (using again, the GUI of the OR Designer) the primary key of the table Client
to be id
and its default edit method to be Client_update(id, name)
(taking care of matching stored procedure and method's parameters). 然后我设置(再次使用OR Designer的GUI)表Client
的主键为id
,其默认编辑方法为Client_update(id, name)
(负责匹配存储过程和方法的参数)。
My XAML code (file MainWindow.xaml.cs
) is: 我的XAML代码(文件MainWindow.xaml.cs
)是:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Loaded="Window_Loaded">
<ListBox x:Name="myListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=name Mode=TwoWay}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
I have set the TextBox Text property to be bound to the name
property of the source to be set on runtime in the code-behind shown later, on a TwoWay mode. 我已将TextBox Text属性设置为绑定到要在运行时在稍后显示的代码隐藏中设置的源的name
属性,在TwoWay模式下。 The default Trigger for data updates on a TextBox should be OnLostFocus, so I'm not specifying it. TextBox上的数据更新的默认触发器应该是OnLostFocus,所以我没有指定它。
My code-behind (file MainWindow.cs
) is: 我的代码隐藏(文件MainWindow.cs
)是:
namespace Test
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Initialize the data context
DataClassesDataContext dataContext = new DataClassesDataContext();
//Define the query to retrieve the list of clients from the SQL Server
IEnumerable<Client> clients = from c in dataContext.Client
select c;
/* Set the item source to be the result of the query defined earlier
* (This also gets the query executed)
*/
myListBox.ItemsSource = clients;
}
}
}
At first, the application won't run. 首先,应用程序将无法运行。 An unhandled exception of Type System.InvalidOperationException
in System.Data.Linq.dll
carrying the message "Incorrect AutoSync specification for member 'id'." System.Data.Linq.dll
中类型System.InvalidOperationException
的未处理异常,其中包含“成员'id'的错误AutoSync规范”。 is thrown. 被扔了。
Searching online I have found that, by default, the OR Designer sets the AutoSync specification to Always
on the primary key column. 在线搜索我发现,默认情况下,OR Designer会将AutoSync规范设置为主键列上的Always
。 Setting it on OnUpdate
raises the same problem, while setting it to OnInsert
or Never
, solves the issue. 在OnUpdate
上设置它会引发同样的问题,同时将其设置为OnInsert
或Never
,可以解决问题。
However, setting it on those two values lets my application function only partly, the data is displayed, but changes are not persisted onto the database. 但是,在这两个值上设置它会使我的应用程序仅部分运行,数据会显示,但更改不会持久保存到数据库中。 (I checked manually with Microsoft SQL Management Studio after editing the data on the application) (我在编辑应用程序上的数据后用Microsoft SQL Management Studio手动检查)
What is the AutoSync parameter and why is it causing an Exception to be thrown? 什么是AutoSync参数以及为什么会引发异常? Is this the correct way to define a two way binding in this scenario, or am I totally going in the wrong direction? 这是在这种情况下定义双向绑定的正确方法,还是我完全走错了方向? If so, could you give me any tip pointing me to the right strategy? 如果是这样,你能否给我任何提示,指出我正确的策略?
PS I'm sorry if the code isn't highlighted properly, I have read and tried to use the syntax to apply the Prettify thing, but for some reason there is no option for XAML, plus even using XML and C# (cs) as language tags is not working, and I have no idea why. PS我很抱歉,如果代码没有正确突出显示,我已阅读并尝试使用语法来应用Prettify,但由于某种原因,XAML没有选项,甚至使用XML和C#(cs)作为语言标签不起作用,我不明白为什么。
EDIT #1: The highlighting was working, it just wasn't shown in the preview. 编辑#1:突出显示正在工作,它只是未在预览中显示。
EDIT #2: Fixed some typos, the name of the view, stored procedure and classes are single-cased. 编辑#2:修正了一些拼写错误,视图的名称,存储过程和类是单一的。 (ie Client
not Clients
) (即Client
不是Clients
)
Try to define dataContext
as global variable. 尝试将dataContext
定义为全局变量。 Then whenever changes to objects from dataContext
need to be submitted, call dataContext.SubmitChanges();
那么只要改变从对象dataContext
需要提交,调用dataContext.SubmitChanges();
. 。 Synchronization to database should be on demand, by calling SubmitChanges()
method (too expensive to be real-time) : 应该按需要通过调用SubmitChanges()
方法同步到数据库(实时太昂贵):
DataClassesDataContext dataContext = new DataClassesDataContext();
......
private void ButtonSubmit_Click(object sender, RoutedEventArgs e)
{
dataContext.SubmitChanges();
}
UPDATE : (as respoind to comment) 更新:( 作为评论的respoind)
This is the way I know to persist changes to database using LINQ to SQL. 这是我所知道的使用LINQ to SQL持久更改数据库的方式。 DataContext
works by tracking changes to entities retrieved from db, upon SubmitChanges
invoked all changes sent back to db. DataContext
通过跟踪对从db检索的实体的更改来工作,当SubmitChanges
调用发送回db的所有更改时。
TwoWay
mode binding doesn't refer to application-to-db, and db-to-application. TwoWay
模式绑定不涉及application-to-db和db-to-application。 It is [bound UI control property]-to-[binding source] and the reverse. 它是[绑定UI控件属性] -to- [绑定源],反之亦然。 When user changes name in TextBox, name property in Client entity will reflect that change, also if name in the entity changed from code, TextBox will display updated name. 当用户在TextBox中更改名称时,Client实体中的name属性将反映该更改,如果实体中的名称从代码更改,TextBox将显示更新的名称。 That's what two-way means in this context. 在这种情况下,这就是双向的意思。 But all of those changes are in application, not submitted to db until SubmitChanges
get invoked. 但所有这些更改都在应用程序中,在调用SubmitChanges
之前不会提交给db。
I'm not fully aware of AutoSync
property, you can refer to this SO answer and see if that help you to understand it. 我不完全了解AutoSync
属性,你可以参考这个SO答案 ,看看是否有助于你理解它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.