2013-01-07 81 views
4

我在我的WPF應用程序中有一個如下所示的數據網格。WPF中的DataGrid和Observable Collection

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

我使用下面的代碼綁定它。現在我的要求是當用戶在datagrid裏面的這些文本框中輸入一些文本並點擊保存按鈕時,它應該更新數據庫。我怎樣才能做到這一點?

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; } 
    } 
} 

感謝

+0

試着在你的ItemsSource-綁定到'TwoWay'設置'Mode'。 –

+0

Hello Dev,您是否使用MVVM模式將DB值綁定到數據網格?回覆晚了非常抱歉。我也在處理這個問題。謝謝 – user1221765

回答

9

當創建在DataGridTemplateColumn自己的UI(或爲此事custom DataGrid.RowStyle),DataGrid的改變UpdateSourceTrigger(即當基礎數據應該更新)上的所有綁定Explicit如果沒有指定他們自己。

這個「功能」在這裏簡要描述:5 Random Gotchas with the WPF DataGrid,即使作者說這種情況發生,無論您是否自己設置UpdateSourceTrigger,自己設置它確實有效(至少在.Net 4.0中)。

使用LostFocus模仿默認TextBox行爲(和PropertyChangedCheckBox等):

... 
<TextBox Text="{Binding Column1, UpdateSourceTrigger=LostFocus}"></TextBox> 
... 
<TextBox Text="{Binding Column2, UpdateSourceTrigger=LostFocus}"></TextBox> 
... 
+0

非常感謝..它工作 – Dev

+0

巨大加上一個從我,我一直有這個確切的問題,並花了我兩天才發現這個!!!!! –

2

有一對夫婦的旁註我想作。
1)你不需要在你的TestSource屬性上有一個setter。你設置這個值一次,並且在設置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}" /> 
+0

我試着用'',並且它的工作方式。謝謝Lee – Dev

+0

太棒了,很高興提供幫助。 –