我的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>
我使用以下代码绑定它。现在我的要求是当用户在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 :(得分:9)
在DataGridTemplateColumn
(或custom DataGrid.RowStyle
中创建自己的用户界面时),DataGrid会更改所有绑定上的UpdateSourceTrigger
(即应更新基础数据时)如果你自己没有指定它们,请Explicit
。
那&#34;功能&#34;这里简要描述: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>
...
答案 1 :(得分:2)
我想提出几个附注 1)您不需要在TestSource属性上设置setter。您设置此值一次,并在设置DataContext之前,这是毫无意义的 2)你没有在Test类上实现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));
}
}
}
}
您可能还想将Binding更新为twoway,但我认为这是默认设置。
<TextBox Text="{Binding Column1, Mode=TwoWay}" />