如何使用和EF6 Generated类识别对象的更改以实现CanExecute?

时间:2017-08-21 05:33:47

标签: c# entity-framework mvvm mvvm-light

我在XAML中绑定一个按钮来更新数据库中的用户。我想利用CanExecute仅在对ViewModel上的属性进行更改后才启用该按钮。

我正在使用Entity Framework和WCF数据服务来执行我的CRUD操作。

模型类

    public virtual DbSet<user> users { get; set; }

    ... 

    namespace pk.Data
    {
        using System;
        using System.Collections.Generic;

        public partial class user
        {
            public user()
            {
                this.private_account = new HashSet<private_account>();
            }

            public int id { get; set; }
            public string username { get; set; }
            public int superuser { get; set; }
            public int enabled { get; set; }

            public virtual ICollection<private_account> private_account { get; set; }
        }
    }

WCF服务

public class pkService
{

    // getUsers() - 
    //  Get all users from the database
    [OperationContract]
    public IEnumerable<user> getUsers()
    {
        using (var  context = new pkEntities())
        {
            // Needed in order to handle EF objects with Hashes 
            context.Configuration.ProxyCreationEnabled = false;
            // Pull entity object fom DB
            var results = context.users.ToList();
            // Detatch from Entity Model
            results.ForEach(e => context.Entry(e).State = EntityState.Detached);
            //Return detached object 
            return results;
        }
    }

    // updateUser(user) -
    //  Update user in the DB
    [OperationContract]
    public void updateUser(user user){
        using (var context = new pkEntities())
        {
            context.Configuration.ProxyCreationEnabled = false;
            context.Entry(user).State = EntityState.Modified;
            context.SaveChanges();
        }
    }
}

查看型号#

 public class HomeViewModel: ViewModelBase
    {
        // HomeViewModel()
        //  Class Constructor
        public HomeViewModel()
        {
            this.RefreshUsers();
            userListClick = new RelayCommand<SelectionChangedEventArgs>(_userListClick);
            saveUser = new RelayCommand(saveUser);
        }

        // users 
        //  list of all users in the system
        private IEnumerable<user> _users;
        public IEnumerable<user> users
        {
            get { return this._users; }
            set
            {
                this._users = value;
                this.RaisePropertyChanged("users");
            }

        }

        // selected user
        //  currently selected user
        private user _selectedUser;
        public user selectedUser
        {
            get { return this._selectedUser; }
            set
            {
                if (this._selectedUser != value)
                {
                    this._selectedUser = value;
                    this.RaisePropertyChanged("selectedUser");
                }
            }
        }

        // RefreshUsers() 
        //  Method for retrieving users from DB
        private void RefreshUsers()
        {
            this._pkServiceClient.getUsersCompleted += (s, e) =>
                {
                    this.users = e.Result;
                };
            this._pkServiceClient.getUsersAsync();

        }

        // serverListClick
        public ICommand userListClick { get; private set; }
        private void _userListClick(SelectionChangedEventArgs e)
        {
            ListView userList = (ListView)e.Source;
            _selectedUser = (user)userList.SelectedItem;
            this.setUserDetailsVisible(Visibility.Visible);
            this.RaisePropertyChanged("selectedUser");
        }        

        public ICommand saveUser { get; private set; }
        private void _saveUser()
        {
            this._pkServiceClient.updateUser(_selectedUser);
        }
    }
}

我相信可以绑定RelayCommand(saveUser, someCommand )并让 someCommand 返回一个我可以在我的XAML中绑定的值来控制启用状态我的按钮。

我似乎找不到使用Entity Generated类来处理这个问题的方法。任何帮助都会很棒。

1 个答案:

答案 0 :(得分:1)

如果我理解正确,您希望尽快启用连接到saveUser命令的按钮,因为对selectedUser进行了更改?

  

我相信可以绑定RelayCommand(saveUser,someCommand)并让someCommand返回一个值,我可以在我的XAML中绑定它来控制我的按钮的启用状态。

使用CompositeCommands(MSDN Documentation)可以实现这一点。在这里,您可以调用方法“RegisterCommand”并传递第二个命令,该命令会影响连接到CompositeCommand的Button的行为。因此,如果注册的Button返回CanExecute == false,则该按钮将被禁用。

但是你也可以在RelayCommand中添加一个CanExecute方法,如果实体具有正确的值,则检查它。 例如,CanExecute方法可以检查例如userName:

public HomeViewModel()
{
    this.RefreshUsers();
    userListClick = new RelayCommand<SelectionChangedEventArgs>(_userListClick);
    saveUser = new RelayCommand(saveUser, CanExecuteSaveUser);
}

private bool CanExecuteSaveUser()
    {
        if (selectedUser.username == "foo")
        {
            return true;
        }

        return false;
    }

我不会将它直接连接到您的模型。您的模型不应该受到验证UI所需逻辑的困扰。因此,您应该在ViewModel和WCF服务之间添加一个额外的层,这是一种UserViewModel,您可以在其中直接处理对User属性所做的所有更改。这些属性的更改可以触发RelayCommand的RaiseCanExecuteChanged方法。

我希望这会有所帮助,如果我误解了你,请提供进一步的解释。

修改

发表评论后,我认为您可以实施INotifyPropertyChanged事件并订阅这些事件。为此,需要向应用程序添加一个额外的userViewModel层。 非常剥离的例子:

public HomeViewModel()
{
    this.RefreshUsers();
    userListClick = new RelayCommand<SelectionChangedEventArgs>(_userListClick);
    saveUser = new RelayCommand(saveUser, CanExecuteSaveUser);
    selectedUserViewModel.PropertyChanged += SelectedUserOnPropertyChanged;
}

private void SelectedUserOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
    if (propertyChangedEventArgs.PropertyName.Equals(nameof(UserViewModel.username)))
    {
        (saveUser as RelayCommand)?.RaiseCanExecuteChanged();
    }
}