通过LINQ to SQL在WPF中实现ListItem的属性与ListBox的双向绑定,使用DataTemplate。

3

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

我的情况

我有一个使用C#编写的WPF应用程序,其中包含一个ListBox的单个窗口。 ListBox定义了一个DataTemplate来显示其项目,每个ListItem都有一个TextBox。

我在同一台机器上安装了Microsoft SQL Express服务器,其中包含一个名为Test的数据库,其中包含一个名为Client的视图,该视图公开另一个表的id INT PRIMARY KEY IDENTITYname VARCHAR(50) NOT NULL列,并且有一个名为Client_update(@id, @name)的存储过程,通过对相同表执行简单的UPDATE语句设置其id@id的客户端的name列。

我的目标

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

我做了什么

我向项目添加了一个新的LINQ to SQL Classes元素,使用Visual Studio创建了一个名为DataClassesDataContext的DataContext类。 我在Visual Studio中使用O-R Designer将视图映射到Class Client和存储过程映射到方法Client_update(id, name)。然后,我使用O-R Designer的GUI将表Client的主键设置为id,并将其默认编辑方法设置为Client_update(id, name)(注意匹配存储过程和方法的参数)。

我的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>

我已将TextBox的Text属性绑定到代码后端在运行时设置的源的name属性上,且为双向绑定模式。 对于TextBox的数据更新,默认的触发器应该是OnLostFocus,所以我没有指定它。
我的代码后端(文件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;
        }
    }
}

我得到了什么

一开始,这个应用程序无法运行。在System.Data.Linq.dll中抛出一个未处理的异常类型System.InvalidOperationException,并携带着消息“成员'id'的AutoSync规范不正确。”。

通过在线搜索,我发现默认情况下 O-R Designer 在主键列上设置 Always 的 AutoSync 规范。将其设置为 OnUpdate 会引发相同的问题,而将其设置为 OnInsertNever 则可以解决该问题。

然而,将其设置为这两个值只能使我的应用程序部分地工作,数据被显示,但更改不会保存到数据库中。(编辑应用程序数据后,我手动使用 Microsoft SQL Management Studio 进行了检查)

我的问题是什么

AutoSync 参数是什么,为什么会导致异常抛出?在此情况下,这是否是定义双向绑定的正确方式,还是我完全走错了方向?如果是后者,你可以给我任何指向正确策略的提示吗?

P.S. 如果代码没有正确高亮显示,我很抱歉。我已经阅读并尝试使用语法来应用Prettify,但由于某种原因没有XAML选项,即使使用XML和C#(cs)作为语言标记也无效,我不知道为什么。

EDIT #1: 高亮显示正常工作,只是预览中没有显示。

EDIT #2: 修正了一些拼写错误,视图、存储过程和类的名称是单数形式的。(即Client而不是Clients


@Blam 你是说我不应该使用DataClassesDataContext类吗?数据上下文类不是LINQ to SQL交互的主要组件吗? 另外,你所说的“您可以尝试使用类和属性,在set中更新db”,能否更具体些? - user3313590
我不确定您是否可以使用DataContext来完成它?如果您创建一个带有属性的自定义类,那么您可以在set中执行更新。尝试绑定到该类。 - paparazzo
1个回答

0
尝试将dataContext定义为全局变量。然后,每当需要提交来自dataContext的对象更改时,请调用dataContext.SubmitChanges();。通过调用SubmitChanges()方法进行数据库同步应该是按需的(实时太昂贵)。
DataClassesDataContext dataContext = new DataClassesDataContext();
......
private void ButtonSubmit_Click(object sender, RoutedEventArgs e)
{
    dataContext.SubmitChanges();
}

更新:(回应评论)

这是我知道的使用 LINQ to SQL 持久化更改到数据库的方法。 DataContext 通过跟踪从数据库检索的实体的更改来工作,在调用 SubmitChanges 时,所有更改都会发送回数据库。

TwoWay 模式绑定不是指应用程序到数据库和数据库到应用程序。它是 [绑定的 UI 控件属性]-to-[绑定源] 和反向的关系。当用户在 TextBox 中更改名称时,Client 实体中的名称属性将反映该更改,如果实体中的名称从代码中更改,则 TextBox 将显示更新后的名称。这就是此上下文中双向的含义。但是,所有这些更改都在应用程序中,直到调用 SubmitChanges 才会提交到数据库。

我不完全了解 AutoSync 属性,您可以参考 this SO answer 并查看是否有帮助您理解它的内容。


谢谢你的回答,har07。你的解决方案似乎有效。 虽然在我看来,这似乎是某种粗略的解决方法,因为它试图更新整个数据上下文(可能包括比 ListBox 的唯一来源更多的信息集),但这是正确的做法吗? 然而,我可能错了:你会推荐它/在你的应用程序中使用它吗? 我将尝试检查其优缺点。 - user3313590
看起来这是这类事情的标准流程,如MSDN页面“实现保存功能”部分所述:http://msdn.microsoft.com/en-us/library/bb629289.aspx 我以为只要将绑定声明为TwoWay,更改就会自动持久化,但显然并非如此。 所以,再次感谢您! 不过,我仍然对AutoSync一事感到困惑。 - user3313590
我不认为这是一种变通方法,这是我目前使用的方式。 - har07
好的,既然看起来这个方法是正确的,我就把它作为答案。谢谢!我还不知道AutoSync属性,但我会自己弄清楚的。 - user3313590

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接