it编程 > App开发 > Windows Phone

WPF数据新增与更新的完整指南

17人参与 2025-08-14 Windows Phone

引言

在wpf开发中,数据新增与更新是构建高效用户界面的核心功能。无论是简单的表单操作,还是复杂的datagrid控件交互,掌握数据绑定与事件处理的技巧是提升开发效率的关键。本文将通过完整的代码示例深度解析实战技巧,带你全面掌握wpf中数据新增与更新的实现方法,并规避常见陷阱。

一、wpf数据绑定的核心原理

1.1 依赖属性与数据绑定

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使文本输入时立即更新数据源,而非等待焦点丢失。

1.2 observablecollection与集合绑定

在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的高级操作

2.1 使用datagrid实现新增操作

datagrid控件支持直接新增行,通过canuseraddrows属性启用此功能。

代码示例:datagrid新增行

<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事件用于验证和提交新增数据。

2.2 通过按钮触发新增

对于更复杂的场景(如弹窗表单),可通过按钮触发新增逻辑。

代码示例:弹窗新增

<button content="add new" command="{binding addnewcommand}" />

viewmodel逻辑:命令绑定

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

三、数据更新:从单元格编辑到批量提交

3.1 单元格编辑触发更新

datagrid支持单元格直接编辑,通过roweditendingcelleditending事件处理更新逻辑。

代码示例:单元格编辑

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

3.2 批量更新与事务处理

在涉及数据库操作时,批量更新需考虑事务一致性。

代码示例:批量提交

public void saveallchanges()
{
    using (var transaction = new transactionscope())
    {
        foreach (var person in people)
        {
            if (person.isdirty) // 假设标记为脏数据
            {
                savepersontodatabase(person);
                person.markasclean();
            }
        }
        transaction.complete();
    }
}

四、高级技巧:优化性能与用户体验

4.1 异步加载与ui响应

在处理大量数据时,异步加载可避免ui卡顿。

代码示例:异步加载数据

public async task loadpeopleasync()
{
    people.clear();
    var data = await task.run(() => fetchdatafromdatabase());
    foreach (var item in data)
    {
        people.add(item);
    }
}

4.2 数据验证与错误提示

通过idataerrorinfo接口实现数据验证,提升用户输入质量。

代码示例:实现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;
        }
    }
}

4.3 脏数据跟踪

通过标记未保存的更改(脏数据),实现“保存”与“撤销”功能。

代码示例:脏数据标记

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

五、完整项目结构与代码整合

5.1 项目结构建议

wpfapp/
├── models/
│   └── person.cs
├── viewmodels/
│   ├── baseviewmodel.cs
│   └── peopleviewmodel.cs
├── views/
│   └── mainwindow.xaml
└── app.xaml

5.2 viewmodel基类

public class baseviewmodel : inotifypropertychanged
{
    public event propertychangedeventhandler propertychanged;

    protected void onpropertychanged(string propertyname)
    {
        propertychanged?.invoke(this, new propertychangedeventargs(propertyname));
    }
}

5.3 主窗口xaml

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

5.4 viewmodel完整实现

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

六、wpf数据新增与更新的核心要点

功能实现方式
数据绑定使用binding类和datacontext,结合inotifypropertychanged接口
集合绑定采用observablecollection<t>实现动态更新
新增数据通过datagrid的canuseraddrows属性或按钮触发新增逻辑
数据更新利用roweditending或celleditending事件提交更改
性能优化使用异步加载和依赖属性减少ui阻塞
数据验证实现idataerrorinfo接口提供实时错误提示
脏数据跟踪通过标记未保存的更改实现“保存”与“撤销”功能

以上就是wpf数据新增与更新的完整指南的详细内容,更多关于wpf数据新增与更新的资料请关注代码网其它相关文章!

(0)

您想发表意见!!点此发布评论

推荐阅读

电脑提示wpcap.dll丢失怎么办? wpcap.dll缺失的修复技巧

08-01

基于WPF实现自定义弹窗输入功能

07-02

WPF封装实现懒加载下拉列表控件(支持搜索)

04-30

Audition焦点指示器怎么调节亮度? Au更改焦点指示器亮度的技巧

04-27

使用WPF实现一个虚拟键盘的代码示例

04-27

wps调用Outlook 批量发送电子邮件时持续弹出警告框怎么办?

02-08

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论