118人参与 • 2025-08-14 • Windows Phone
在wpf开发中,数据新增与更新是构建高效用户界面的核心功能。无论是简单的表单操作,还是复杂的datagrid控件交互,掌握数据绑定与事件处理的技巧是提升开发效率的关键。本文将通过完整的代码示例、深度解析和实战技巧,带你全面掌握wpf中数据新增与更新的实现方法,并规避常见陷阱。
wpf的数据绑定依赖于依赖属性(dependencyproperty),它允许ui元素与数据源动态同步。绑定的关键在于datacontext的设置和binding类的使用。
public class personviewmodel : inotifypropertychanged
{
private string _name;
public string name
{
get => _name;
set
{
_name = value;
onpropertychanged(nameof(name));
}
}
public event propertychangedeventhandler propertychanged;
protected virtual void onpropertychanged(string propertyname)
{
propertychanged?.invoke(this, new propertychangedeventargs(propertyname));
}
}
// xaml绑定
<textbox text="{binding name, updatesourcetrigger=propertychanged}" />
说明:
- inotifypropertychanged接口确保属性变更时自动通知ui更新。
- updatesourcetrigger=propertychanged使文本输入时立即更新数据源,而非等待焦点丢失。
在wpf中,observablecollection<t>是动态集合的标准选择,它支持实时更新ui。
public class peopleviewmodel
{
public observablecollection<person> people { get; } = new observablecollection<person>();
public peopleviewmodel()
{
people.add(new person { name = "alice", age = 30 });
people.add(new person { name = "bob", age = 25 });
}
}
// xaml绑定
<datagrid itemssource="{binding people}" autogeneratecolumns="true" />
说明:
- observablecollection在添加/删除项时自动触发ui更新。
- autogeneratecolumns自动生成列,适用于快速原型开发。
datagrid控件支持直接新增行,通过canuseraddrows属性启用此功能。
<datagrid
itemssource="{binding people}"
canuseraddrows="true"
autogeneratecolumns="false">
<datagrid.columns>
<datagridtextcolumn header="name" binding="{binding name}" />
<datagridtextcolumn header="age" binding="{binding age}" />
</datagrid.columns>
</datagrid>
private void datagrid_roweditending(object sender, datagridroweditendingeventargs e)
{
if (e.editaction == datagrideditaction.commit && e.row.isnewitem)
{
var newperson = e.row.item as person;
if (newperson != null)
{
// 验证逻辑(可选)
if (string.isnullorempty(newperson.name))
{
messagebox.show("name is required!");
e.cancel = true;
return;
}
// 保存到数据源
((peopleviewmodel)datacontext).people.add(newperson);
}
}
}
说明:
- canuseraddrows="true"允许用户添加新行。
- roweditending事件用于验证和提交新增数据。
对于更复杂的场景(如弹窗表单),可通过按钮触发新增逻辑。
<button content="add new" command="{binding addnewcommand}" />
public class peopleviewmodel
{
public icommand addnewcommand { get; }
public peopleviewmodel()
{
addnewcommand = new relaycommand(addnewperson);
}
private void addnewperson()
{
var newperson = new person { name = "new person", age = 0 };
people.add(newperson);
}
}
datagrid支持单元格直接编辑,通过roweditending或celleditending事件处理更新逻辑。
<datagrid
itemssource="{binding people}"
autogeneratecolumns="false"
celleditending="datagrid_celleditending">
<datagrid.columns>
<datagridtextcolumn header="name" binding="{binding name}" />
<datagridtextcolumn header="age" binding="{binding age}" />
</datagrid.columns>
</datagrid>
private void datagrid_celleditending(object sender, datagridcelleditendingeventargs e)
{
if (e.editaction == datagrideditaction.commit)
{
var editedperson = e.row.item as person;
if (editedperson != null)
{
// 例如:调用服务层保存更改
saveperson(editedperson);
}
}
}
在涉及数据库操作时,批量更新需考虑事务一致性。
public void saveallchanges()
{
using (var transaction = new transactionscope())
{
foreach (var person in people)
{
if (person.isdirty) // 假设标记为脏数据
{
savepersontodatabase(person);
person.markasclean();
}
}
transaction.complete();
}
}
在处理大量数据时,异步加载可避免ui卡顿。
public async task loadpeopleasync()
{
people.clear();
var data = await task.run(() => fetchdatafromdatabase());
foreach (var item in data)
{
people.add(item);
}
}
通过idataerrorinfo接口实现数据验证,提升用户输入质量。
public class person : idataerrorinfo
{
public string name { get; set; }
public int age { get; set; }
public string error => null;
public string this[string columnname]
{
get
{
switch (columnname)
{
case nameof(name):
return string.isnullorempty(name) ? "name is required." : null;
case nameof(age):
return age < 0 ? "age cannot be negative." : null;
}
return null;
}
}
}
通过标记未保存的更改(脏数据),实现“保存”与“撤销”功能。
public class person : inotifypropertychanged
{
private string _name;
private bool _isdirty;
public string name
{
get => _name;
set
{
if (_name != value)
{
_name = value;
_isdirty = true;
onpropertychanged(nameof(name));
}
}
}
public bool isdirty => _isdirty;
public void markasclean() => _isdirty = false;
public event propertychangedeventhandler propertychanged;
protected virtual void onpropertychanged(string propertyname)
{
propertychanged?.invoke(this, new propertychangedeventargs(propertyname));
}
}
wpfapp/ ├── models/ │ └── person.cs ├── viewmodels/ │ ├── baseviewmodel.cs │ └── peopleviewmodel.cs ├── views/ │ └── mainwindow.xaml └── app.xaml
public class baseviewmodel : inotifypropertychanged
{
public event propertychangedeventhandler propertychanged;
protected void onpropertychanged(string propertyname)
{
propertychanged?.invoke(this, new propertychangedeventargs(propertyname));
}
}
<window x:class="wpfapp.mainwindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
title="data crud demo" height="450" width="800">
<grid>
<datagrid
itemssource="{binding people}"
canuseraddrows="true"
autogeneratecolumns="false"
celleditending="datagrid_celleditending">
<datagrid.columns>
<datagridtextcolumn header="name" binding="{binding name}" />
<datagridtextcolumn header="age" binding="{binding age}" />
</datagrid.columns>
</datagrid>
<button content="save all" command="{binding saveallcommand}" horizontalalignment="right" margin="10" />
</grid>
</window>
public class peopleviewmodel : baseviewmodel
{
public observablecollection<person> people { get; } = new observablecollection<person>();
public icommand saveallcommand { get; }
public peopleviewmodel()
{
saveallcommand = new relaycommand(saveallchanges);
loadinitialdata();
}
private void loadinitialdata()
{
people.add(new person { name = "alice", age = 30 });
people.add(new person { name = "bob", age = 25 });
}
private void saveallchanges()
{
using (var transaction = new transactionscope())
{
foreach (var person in people)
{
if (person.isdirty)
{
// 模拟数据库保存
console.writeline($"saving {person.name}, age={person.age}");
person.markasclean();
}
}
transaction.complete();
}
}
}
| 功能 | 实现方式 |
|---|---|
| 数据绑定 | 使用binding类和datacontext,结合inotifypropertychanged接口 |
| 集合绑定 | 采用observablecollection<t>实现动态更新 |
| 新增数据 | 通过datagrid的canuseraddrows属性或按钮触发新增逻辑 |
| 数据更新 | 利用roweditending或celleditending事件提交更改 |
| 性能优化 | 使用异步加载和依赖属性减少ui阻塞 |
| 数据验证 | 实现idataerrorinfo接口提供实时错误提示 |
| 脏数据跟踪 | 通过标记未保存的更改实现“保存”与“撤销”功能 |
以上就是wpf数据新增与更新的完整指南的详细内容,更多关于wpf数据新增与更新的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论