因此,我有一个可以大量使用数据绑定的应用程序。该应用程序的一个功能是一个弹出窗口,允许用户管理一些记录。他们从列表框中选择一条记录,然后使用表单来编辑该记录的对象实例的属性。
用户通常习惯于在表格末尾选择“保存”或“取消”。保存将提交更改,而“取消”放弃更改。
但是,通过双向数据绑定,随着字段值的更改,对象将实时更新。
在WPF中是否存在通过数据绑定处理Commit / Cancel行为的“最佳实践”方法?我曾考虑过克隆要编辑的对象,以便在该克隆上进行更改,然后“保存”将更改应用于原始记录,但是我感觉这可能是Microsoft已经内置的东西,我只是不知道如何正确使用它。
答案 0 :(得分:0)
WPF提供BindingGroup
来处理您遇到的情况。 using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Linq.Expressions;
namespace EntityFrameworkRepositoryPatternTestApp
{
public class Item
{
public Guid Id { get; set; }
public string SomeString { get; set; }
public int SomeInt { get; set; }
public double SomeDouble { get; set; }
}
public class Context : DbContext
{
public DbSet<Item> Items { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ItemConfiguration());
base.OnModelCreating(modelBuilder);
}
public Context() : base("Connection")
{
}
}
public class ItemConfiguration : EntityTypeConfiguration<Item>
{
public ItemConfiguration()
{
this.ToTable("Items").HasKey(i => i.Id);
this.Property(i => i.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(i => i.SomeString).HasMaxLength(255);
this.Property(i => i.SomeInt);
this.Property(i => i.SomeDouble);
}
}
public interface IRepository<T>
{
T Add(T item);
IEnumerable<T> Get(Expression<Func<T, bool>> filter = null);
T GetById(Guid id);
void Remove(T item);
}
public class EntityFrameworkRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly IDbSet<TEntity> dbSet;
private Context Context { get; }
public TEntity Add(TEntity item)
{
this.dbSet.Add(item);
return item;
}
public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null)
{
IQueryable<TEntity> query = this.dbSet;
if (filter != null)
query = query.Where(filter);
return query.ToList();
}
public TEntity GetById(Guid id)
{
return this.dbSet.Find(id);
}
public void Remove(TEntity item)
{
this.dbSet.Remove(item);
}
public EntityFrameworkRepository(Context context)
{
this.Context = context;
this.dbSet = this.Context.Set<TEntity>();
}
}
public interface IDomainContext
{
int SaveChanges();
int SaveChangesWithoutClientValidation();
}
public interface IDomainContext<TEntity> : IDomainContext where TEntity : class
{
IRepository<TEntity> Entities { get; }
void Update(TEntity item);
void Attach(TEntity item);
void Detach(TEntity item);
}
public class DomainContext<TEntity> : IDomainContext<TEntity>, IDisposable where TEntity : class
{
private Context context;
public int SaveChanges()
{
return this.context.SaveChanges();
}
public IRepository<TEntity> Entities => this.GetRepository<TEntity>();
public void Update(TEntity item)
{
var entry = this.context.Entry(item);
foreach (var propertyName in entry.OriginalValues.PropertyNames)
{
var original = entry.OriginalValues.GetValue<object>(propertyName);
var current = entry.CurrentValues.GetValue<object>(propertyName);
if ((original == null && current != null) ||
((original != null) && !original.Equals(current)))
entry.Property(propertyName).IsModified = true;
}
}
public void Attach(TEntity item) =>
this.context.Set<TEntity>().Attach(item);
public void Detach(TEntity entity) =>
((IObjectContextAdapter)this.context).ObjectContext.Detach(entity);
public void Dispose()
{
this.context.Dispose();
}
private IRepository<T> GetRepository<T>() where T : class
{
var resultRepository = new EntityFrameworkRepository<T>(this.context);
return resultRepository;
}
public DomainContext()
{
this.context = new Context();
}
}
public class Program
{
static void Main(string[] args)
{
var domainContext = new DomainContext<Item>();
{
var item = new Item() { Id = Guid.NewGuid(), SomeDouble = 666, SomeInt = 777, SomeString = "some string"};
domainContext.Entities.Add(item);
domainContext.SaveChanges();
using (var domainContext2 = new DomainContext<Item>())
{
if (item != null)
{
domainContext2.Attach(item);
item.SomeDouble = 11.28;
domainContext2.Update(item);
domainContext2.SaveChanges();
}
}
}
domainContext.Dispose();
}
}
}
允许您同时处理多个值更改。您可以基于同时验证所有更改的结果来提交或取消更改,而不仅要分别验证每个更改。为了使编辑事务正常工作,BindingGroup
中的源应实现IEditableObject
接口。