4

我的 WPF 应用程序中有一个如下所示的数据网格。

<Window x:Class="MyApp.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
    <DataGrid x:Name="dgTest"  ItemsSource="{Binding TestSource}" AutoGenerateColumns="False" >
            <DataGrid.Columns>
                <DataGridTemplateColumn Width="125" >
                       <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                                      <TextBox Text="{Binding Column1}"></TextBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Width="500" >
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding Column2}"></TextBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
         <Button Click="SaveButton_Click">Save</Button>
    </Grid>
</Window>

我使用以下代码绑定它。现在我的要求是当用户在数据网格内的这些文本框中输入一些文本并单击保存按钮时,它应该更新数据库。我怎样才能做到这一点?

namespace MyApp
{
    public partial class TestWindow: Window
    {
        private ObservableCollection<Test> _testSource
        public ObservableCollection<Test> TestSource
        {
            get
            {
                return _testSource;
            }
            set
            {
                _testSource = value;
                OnPropertyChanged("TestSource");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
            }
        }

        public TestWindow()
        {
            InitializeComponent();
            TestSource= new ObservableCollection<Test>();
             string strConnString = Application.Current.Properties["connectionStr"].ToString();
             SqlConnection con = new SqlConnection(strConnString);
            SqlCommand cmd = new SqlCommand("SELECT Column1,Column2 FROM MyTable", con);
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dtTest = new DataTable();
            da.Fill(dtTest);
            foreach (DataRow row in dtTest)
            {
                Test cd = new Test();
                cd.Column1 = row["Column1"].ToString();
                cd.Column2 = row["Column2"].ToString();
                TestSource.Add(cd);
            }
            this.DataContext = this;
        }

        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
             // here I need to get the updated ObservableCollection, but now it is showing old data
             foreach Test t in TestSource)
            {
                string a = t.Column1;
                string b = t.Column2;
            }
        }
    }

    public class Test: 
    {
        public string Column1{ get; set; }
        public string Column2{ get; set; }
    }
}

谢谢

4

2 回答 2

9

在创建自己的 UI DataGridTemplateColumn(或自定义DataGrid.RowStyle)时,DataGrid 会将UpdateSourceTrigger所有绑定上的(即何时更新基础数据)更改为Explicit您自己未指定它们的情况。

此处简要描述了该“功能”:5 Random Gotchas with the WPF DataGrid,尽管作者说无论您是否自己设置都会发生这种情况UpdateSourceTrigger,但自己设置确实有效(至少在.Net 4.0中)。

用于LostFocus模仿默认TextBox行为(PropertyChanged等等CheckBox):

...
<TextBox Text="{Binding Column1, UpdateSourceTrigger=LostFocus}"></TextBox>
...
<TextBox Text="{Binding Column2, UpdateSourceTrigger=LostFocus}"></TextBox>
...
于 2013-01-07T19:12:55.483 回答
2

我想做一些旁注。
1)您不需要在您的 TestSource 属性上有一个设置器。您设置了一次这个值,并且在设置 DataContext 之前,所以这是没有意义的。
2)您没有在测试类上实现 INotifyPropertyChanged
3)您在 UI 线程上加载数据。这可能会导致应用程序在加载数据时冻结(变得无响应)。

尝试将 C# 代码更新为以下内容:

namespace MyApp
{
    public partial class TestWindow: Window
    {
        private ObservableCollection<Test> _testSource = new ObservableCollection<Test>();


        public TestWindow()
        {
            InitializeComponent();

            //NOTE: this blocks the UI thread. Slow DB/Network will freeze the App while we wait. 
            // This should be done on a background thread.
            string strConnString = Application.Current.Properties["connectionStr"].ToString();
            SqlConnection con = new SqlConnection(strConnString);
            SqlCommand cmd = new SqlCommand("SELECT Column1,Column2 FROM MyTable", con);
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dtTest = new DataTable();
            da.Fill(dtTest);
            foreach (DataRow row in dtTest)
            {
                Test cd = new Test();
                cd.Column1 = row["Column1"].ToString();
                cd.Column2 = row["Column2"].ToString();
                TestSource.Add(cd);
            }
            this.DataContext = this;
        }

        public ObservableCollection<Test> TestSource { get { return _testSource; } }

        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            var rowIdx = 0;
            foreach(var t in TestSource)
            {
                string a = t.Column1;
                string b = t.Column2;

                Console.WriteLine("Row {0}, col1='{1}', col2='{2}'", rowIdx++, a, b);
            }
        }
    }

    public sealed class Test : INotifyPropertyChanged
    {
        private string _column1;
        private string _column2;

        public string Column1
        { 
            get{return _column1;}
            set
            {
                if(_column1!=value)
                {
                    _column1 = value;
                    OnPropertyChanged("Column1");
                }
            }           
        }
        public string Column2
        { 
            get{return _column2;}
            set
            {
                if(_column2!=value)
                {
                    _column2 = value;
                    OnPropertyChanged("Column2");
                }
            }           
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
}

您可能还想将绑定更新为双向,但我认为这是默认设置。

<TextBox Text="{Binding Column1, Mode=TwoWay}" />
于 2013-01-07T10:44:49.683 回答