【问题标题】:MvvmCross Android Dialog Bing Programmatically - ViewModel is not updated以编程方式 MvvmCross Android Dialog Bing - ViewModel 未更新
【发布时间】:2013-01-22 15:45:41
【问题描述】:

这是关于MvvmCross Android Dialog Bing Programmatically的帖子的跟进

我已经在一个 Droid 项目中实现了对话框的绑定:

    this.Root = new RootElement("Customer Info")
    {
        new Section("Private Configuration")
        {
            new EntryElement("Pin:").Bind(this, "{'Value':{'Path':'Configuration.Pin'}}"),
            new EntryElement("Name:").Bind(this, "{'Value':{'Path':'Configuration.Name', 'Mode':'TwoWay'}}"),
        };
    };

我在Configuration.Name 绑定中添加了TwoWay,仅用于测试目的。

现在的问题是绑定只在 OneWay 中起作用。 如果我更改视图中的某些内容,则该对象不会更新,但如果对象发生更改,则会通知视图。这发生在上述两种绑定中(在绑定 Mode 中有或没有 TwoWay)。

这是唯一剩下的一个完整的 Droid.Dialog 项目,使用绑定和多个视图,由 viewModels 控制,使用 MvvmCross 框架。

根据我能够调试的情况(在 VS2010 中只有 Droid 代码,没有 PCL),每次我更改 EntryElement 中的文本时,都会调用 OnTextChanged 方法并且属性 Value 正在更新。

EntryElement.cs

    public virtual void OnTextChanged(string newText)
    {
        //Log.Info("Just playing","New text:" + newText);
        OnUserValueChanged(newText);
    }

ValueElement.cs

    protected void OnUserValueChanged(TValueType newValue)
    {
        Value = newValue;
        FireValueChanged();
    }

    protected virtual void FireValueChanged()
    {
        var handler = ValueChanged;
        if (handler != null)
            handler(this, EventArgs.Empty);
    }

这是我在 core 和 droid 项目中的代码

核心

BaseViewModel.cs

    public class BaseViewModel : MvxViewModel, IMvxServiceConsumer
    {
        protected IConfigurationDataStore ConfigDataStore
        {
            get
            {
                if (_configDataStore == null)
                    _configDataStore = this.GetService<IConfigurationDataStore>();

                return _configDataStore;
            }
        }
        private IConfigurationDataStore _configDataStore;
    }

EditConfigurationViewModel.cs

    public class EditConfigurationViewModel : BaseViewModel, IEditConfigurationViewModel
    {
        public ConfigurationSet Configuration
        {
            get { return _configuration; }
            set
            {
                if (_configuration != value)
                {
                    _configuration = value;
                    RaisePropertyChanged(() => Configuration);
                }
            }
        }
        private ConfigurationSet _configuration;

        public EditConfigurationViewModel(string id)
        {
            Guid value;
            if (string.IsNullOrEmpty(id) || !Guid.TryParse(id, out value))
            {
                Configuration = new ConfigurationSet();
            }
            else
            {
                Configuration = ConfigDataStore.GetConfiguration(value);
            }
        }

        public void SaveConfiguration()
        {
            ConfigDataStore.UpdateConfiguration(Configuration);
        }
    }

ConfigurationSet.cs

    public class ConfigurationSet : MvxNotifyPropertyChanged
    {
        public string Pin
        {
            get { return _pin; }
            set
            {
                if (_pin != value)
                {
                    _pin = value;
                    RaisePropertyChanged(() => Pin);
                }
            }
        }
        private string _pin;

        public string Name
        {
            get { return _name; }
            set
            {
                //if (_name != value)
                //{
                    _name = value;
                    RaisePropertyChanged(()=> Name);
                //}
            }
        }
        private string _name;

        public string PrivateDescription
        {
            get { return _privateDescription; }
            set
            {
                if (_privateDescription != value)
                {
                    _privateDescription = value;
                    RaisePropertyChanged(() => PrivateDescription);
                }
            }
        }
        private string _privateDescription;
    }

机器人

EditConfigurationView

    public class EditConfigurationView : MvxBindingDialogActivityView<EditConfigurationViewModel>, IMvxServiceConsumer
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            DroidResources.Initialise(typeof(Resource.Layout));

            Root = new RootElement()
                {
                    new Section("Private Configuration")
                    {
                        new EntryElement("Pin:").Bind(this, "{'Value':{'Path':'Configuration.Pin'}}"),
                        new EntryElement("Name:").Bind(this, "{'Value':{'Path':'Configuration.Name'}}"),
                        new EntryElement("Description:").Bind(this, "{'Value':{'Path':'Configuration.PrivateDescription'}}")
                    }
                };
        }

        public override void OnBackPressed()
        {
            ViewModel.SaveConfiguration();

            base.OnBackPressed();
        }

        protected override void OnViewModelSet()
        {

        }
    }

【问题讨论】:

    标签: binding notifications viewmodel mvvmcross


    【解决方案1】:

    https://github.com/zleao/MvvmCross.Dialog看到你的回购后的第二个答案


    感谢您提供更多信息。

    我还没有运行您的示例,但是查看重现问题的简单代码很有帮助。

    我认为问题可能出在您的安装文件中 - https://github.com/zleao/MvvmCross.Dialog/blob/master/MvvmCross.Dialog.UI.Droid/Setup.cs

    那里的设置继承自MvxBaseAndroidBindingSetup,这是Cirrious.MvvmCross.Binding.Droid中所有内容的基本设置类,它本身从MvxBaseAndroidSetup继承自Cirrious.MvvmCross.Droid

    由于除了“仅绑定”之外您还使用对话框代码,因此您需要进一步设置 - 您需要从 Cirrious.MvvmCross.Dialog.Droid 添加 MvxBaseAndroidDialogBindingSetup。此类添加了许多重要步骤,包括在所有 ValueElement 实例上为 Value 注册双向绑定 - 请参阅:

        protected override void FillTargetFactories(
            Cirrious.MvvmCross.Binding.Interfaces.Bindings.Target.Construction.IMvxTargetBindingFactoryRegistry registry)
        {
            registry.RegisterFactory(new MvxPropertyInfoTargetBindingFactory(typeof (ValueElement), "Value",
                                                                             (element, propertyInfo) =>
                                                                             new MvxElementValueTargetBinding(element,
                                                                                                              propertyInfo)));
            base.FillTargetFactories(registry);
        }
    

    https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Dialog.Droid/MvxBaseAndroidDialogBindingSetup.cs


    所以 - 要尝试解决问题,请尝试从 MvxBaseAndroidDialogBindingSetup 继承 Setup


    更多关于MvvmCross层的信息,请查看http://slodge.blogspot.co.uk/2012/12/a-short-guide-to-layers-of-mvvmcross.html


    我希望这有助于解决问题。

    感谢您提供的详细信息。

    但请注意,与 Touch Dialog 代码相比,Droid.Dialog 代码还很年轻 - 因此您可能会在此过程中遇到真正的错误和问题。当你点击它们时,请在这里提问,或者如果它们是错误,请在https://github.com/slodge/MvvmCross/issues?state=open的问题上记录它们

    斯图尔特

    【讨论】:

    • 我刚刚测试了您所建议的更改,现在魔法就在那里!!! :) 我会尽快(希望明天)用更复杂和完整的场景更新 repo。感谢您的帮助!
    【解决方案2】:

    我刚刚使用修改后的 CustomerManagement 示例应用程序对此进行了测试 - 这个绑定对我来说是双向的。

    我的代码:

            Root = new RootElement()
                {
                    new Section("Customer Info")
                        {
                            new EntryElement("Name").Bind(this, "{'Value':{'Path':'Customer.Name'}}"),
                            new EntryElement("Website").Bind(this, "{'Value':{'Path':'Customer.Website'}}"),
                            new EntryElement("Phone").Bind(this, "{'Value':{'Path':'Customer.PrimaryPhone'}}"),
                        }
                };
    

    我的 ViewModel 和 Customer 对象是:

    public abstract class BaseEditCustomerViewModel
        : BaseViewModel
    {
        private Customer _customer;
        public Customer Customer
        {
            get { return _customer; }
            private set { _customer = value; RaisePropertyChanged("Customer"); }
        }
    
        // ...
    }
    
    public class Customer : MvxNotifyPropertyChanged
    {
        public Customer()
        {
        }
    
        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; RaisePropertyChanged("Name"); }
        }
    
        private string _website;
        public string Website
        {
            get { return _website; }
            set { _website = value; RaisePropertyChanged("Website"); }
        }
    
        private string _primaryPhone;
        public string PrimaryPhone
        {
            get { return _primaryPhone; }
            set { _primaryPhone = value; RaisePropertyChanged("PrimaryPhone"); }
        }
    
        // ...
    }
    

    根据您的描述,我没有发现任何明显的错误——尽管显然我看不到所有的细节——例如ViewModel 端的 Configuration 对象是什么?


    如果您怀疑这可能是一个错误,最简单的方法可能是在 https://github.com/slodge/MvvmCross/issues/new 上记录这些内容

    您可以在错误中包含的详细信息越多,查看它的速度就越快 - 例如如果您可以包含一个重现问题的示例 github 存储库,那么开发人员可以快速轻松地进行测试。相反,如果您只是提供说明,那么开发人员可能需要 1 小时或更长时间来进行测试 - 所以您需要等待他们有“空闲时间”。


    对于“调试......只有 Droid 代码,没有 PCL,在 VS2010 中”的投诉,请确保您已向 Xamarin 提出此问题 - 他们解决这些问题的唯一方法是付费客户告诉他们问题.

    【讨论】:

    • 我已经编辑了问题并添加了我在“Core”和“Droid”项目中的代码。我将准备一个示例以放入 GitHub 存储库。谢谢
    • 我在 GitHub 中添加了一个 repo,其中包含我在此处描述的一个非常简单的示例。 (github.com/zleao/MvvmCross.Dialog)
    【解决方案3】:

    这在 iOS 中也是必需的。

    public class Setup : MvxIosDialogSetup//MvxIosSetup
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多