【问题标题】:How do I recognize changes to an object using and EF6 Generated class in order to implement CanExecute?如何使用 EF6 Generated 类识别对象的更改以实现 CanExecute?
【发布时间】:2017-08-21 05:33:46
【问题描述】:

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

我正在使用实体框架和 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 类来处理这个问题的方法。任何帮助都会很棒。

【问题讨论】:

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


    【解决方案1】:

    如果我理解正确,您想在 selectedUser 发生更改后尽快启用连接到 saveUser 命令的按钮?

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

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

    但是您也可以向 RelayCommand 添加一个 CanExecute 方法,并在那里检查实体是否具有正确的值。 例如,CanExecute 方法可以检查用户名:

    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,您可以在其中直接处理对用户属性所做的所有更改。这些属性的变化可以触发 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();
        }
    }
    

    【讨论】:

    • 确实有帮助。我的问题是逻辑。您的示例: if (selectedUser.username == "foo") 我不想检查特定值,我想知道属性是否发生了变化。在这种情况下,特别是已启用或超级用户 bool 已更改。但是,这是我正在使用的第一个类,我将继续使用具有其他属性的其他类并希望使用相同的方法。我绝对是在 VIewModel 上处理所有这些,并且在此过程中根本不与模型交谈。
    • 嗨瑞恩,我在上面的答案中添加了一个额外的建议。我认为只要用户/UserViewModel 中的属性发生更改,您就可以触发 canExecuteChanged 事件。但请务必检查命令的 CanExecute 方法中的无效输入。
    • 好的。我整晚都在阅读,创建一个实现 INotifyPropertyChanged 的​​视图模型类似乎是最好的方法。我只需要弄清楚如何使用该对象并将其传递回 WCF 服务以更新数据库。我会沿着这条路走下去。谢谢你的建议。
    • 您能否用答案更新您的问题,或者将其标记为答案,以帮助人们将来搜索相同的答案?
    猜你喜欢
    • 2012-06-20
    • 1970-01-01
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-28
    相关资源
    最近更新 更多