C# WPF中使用DataTemplate通过LINQ到SQL对ListBox的ListItem属性进行双向绑定

C# WPF中使用DataTemplate通过LINQ到SQL对ListBox的ListItem属性进行双向绑定,c#,wpf,linq,binding,listbox,C#,Wpf,Linq,Binding,Listbox,我对C#和WPF还很陌生。尽管我已经阅读了大量的文档、教程和以前的问题,但我似乎找不到我的场景 我所拥有的 我有一个C#格式的WPF应用程序,其中一个窗口包含一个列表框。 ListBox定义一个DataTemplate来显示其项,每个ListItem都有一个文本框 我在同一台计算机上有一个Microsoft SQL Express server,其中包含一个名为Test的数据库,该数据库的视图名为Client,该视图公开另一个表的id INT主键标识列和name VARCHAR(50)NOT N

我对C#和WPF还很陌生。尽管我已经阅读了大量的文档、教程和以前的问题,但我似乎找不到我的场景

我所拥有的 我有一个C#格式的WPF应用程序,其中一个窗口包含一个列表框。 ListBox定义一个DataTemplate来显示其项,每个ListItem都有一个文本框

我在同一台计算机上有一个Microsoft SQL Express server,其中包含一个名为
Test
的数据库,该数据库的视图名为
Client
,该视图公开另一个表的
id INT主键标识
列和
name VARCHAR(50)NOT NULL
,以及一个名为
Client\u update(@id,@name)的存储过程
通过同一表上的简单UPDATE语句设置其
id
@id
的客户机的
名称

我正在努力实现的目标 我试图实现的是在窗口加载时填充ListBox,并通过将焦点切换到GUI的另一个组件,将对数据(包含在文本框中)的更改持久化到数据库(通过存储过程)

我所做的 我使用Visual Studio在我的项目中添加了一个新的LINQ to SQL Classes元素,从而创建了一个名为
DataClassesDataContext
的DataContext类。 我使用了Visual Studio中的O-R设计器将视图映射到类
客户机
,并将存储过程映射到方法
客户机更新(id,name)
。然后我(再次使用O-R设计器的GUI)将表
Client
的主键设置为
id
,其默认编辑方法设置为
Client\u update(id,name)
(注意匹配存储过程和方法参数)

我的XAML代码(文件
MainWindow.XAML.cs
)是:

我所得到的 首先,应用程序不会运行。 抛出
System.Data.Linq.dll
中类型为
System.InvalidOperationException
的未处理异常,其中包含消息“成员'id'的自动同步规范不正确”

在线搜索我发现,默认情况下,O-R设计器会在主键列上将自动同步规范设置为
始终
。将其设置为
OnUpdate
会引发相同的问题,而将其设置为
OnInsert
Never
则会解决此问题

但是,将其设置为这两个值只允许我的应用程序部分运行,数据将显示,但更改不会持久化到数据库中。(在编辑应用程序上的数据后,我与Microsoft SQL Management Studio进行了手动检查)

我的问题是什么 AutoSync参数是什么?为什么它会引发异常? 在这种情况下,这是定义双向绑定的正确方法,还是我完全走错了方向?如果是这样的话,你能给我一些提示,告诉我正确的策略吗

p.S.如果代码没有正确突出显示,我很抱歉,我已经阅读并尝试使用语法来应用美观的东西,但是出于某种原因,XAML没有选项,而且甚至使用XML和C#(cs)作为语言标记也不起作用,我不知道为什么

编辑#1:高亮显示正在工作,只是没有显示在预览中


EDIT#2:修复了一些打字错误,视图名称、存储过程和类都是单壳的。(即
Client
而不是
Clients

尝试将
dataContext
定义为全局变量。然后,每当需要提交来自
dataContext
的对象更改时,调用
dataContext.SubmitChanges()。通过调用
SubmitChanges()
方法(成本太高,无法实时),应按需同步到数据库:

更新:(回复评论)

这就是我所知道的使用LINQtoSQL将更改持久化到数据库的方法
DataContext
SubmitChanges
调用发送回db的所有更改时,通过跟踪从db检索到的实体的更改来工作

TwoWay
模式绑定不指应用程序到数据库,也不指数据库到应用程序。它是[binding UI control property]-[binding source],反之亦然。当用户更改TextBox中的名称时,客户端实体中的name属性将反映该更改,并且如果实体中的名称从代码更改,TextBox将显示更新的名称。这就是双向在这种情况下的含义。但所有这些更改都在应用程序中,在调用
SubmitChanges
get之前不会提交给db


我不完全了解
AutoSync
属性,您可以参考,看看这是否有助于您理解它。

@Blam您是说我不应该使用DataClassesDataContext类吗?数据上下文类不是LINQ到SQL交互的主要组件吗?另外,你说“你可以尝试一个类和一个属性并在集合中的db中更新”是什么意思?你能说得更具体一点吗?我不确定你是否能用DataContext做到这一点?如果使用属性创建自定义类,则可以在集合中执行更新。关于绑定到类的外观。谢谢您的回答,har07。你的解决方案似乎奏效了。虽然在我看来,这是一种粗略的解决方法,因为它试图更新整个数据上下文(可能包括一组比列表框的唯一来源大得多的信息),但这是正确的方法吗?然而,我可能弄错了:你会推荐它吗/你会在你的应用程序中使用它吗?我将尝试分析利弊。这似乎是这类事情的标准过程,如MSDN页面的“实现保存功能”部分所述:我认为只要将绑定声明为双向绑定,更改就会自动持久化,但显然这样做了
<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>
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;
        }
    }
}
DataClassesDataContext dataContext = new DataClassesDataContext();
......
private void ButtonSubmit_Click(object sender, RoutedEventArgs e)
{
    dataContext.SubmitChanges();
}