C# 在Xamarin.Forms中,如何将同一viewmodel的更改通知回上一页?(可以转到第二页,但不能返回)

C# 在Xamarin.Forms中,如何将同一viewmodel的更改通知回上一页?(可以转到第二页,但不能返回),c#,mvvm,xamarin.forms,viewmodel,C#,Mvvm,Xamarin.forms,Viewmodel,我有两个页面,“主页”,“设置页面”,包括相同的“我的视图”(那里有一些选择器)。 当我在主页中单击“Go Setting”(或显示更多设置)按钮时,这些值将同步到设置页面。但是,当我在设置页面上单击“应用”时,这些值没有返回 我是c#和Xamarin的新手,尝试在线搜索和Microsoft文档。但我找不到解决这个问题的方法 我也在关注这个链接: 并且在我的代码中使用了相同的全局值 MyView(ContentView) 主页(包括MyView) 设置页面(包括相同的MyView) GLobal

我有两个页面,“主页”,“设置页面”,包括相同的“我的视图”(那里有一些选择器)。 当我在主页中单击“Go Setting”(或显示更多设置)按钮时,这些值将同步到设置页面。但是,当我在设置页面上单击“应用”时,这些值没有返回

我是c#和Xamarin的新手,尝试在线搜索和Microsoft文档。但我找不到解决这个问题的方法

我也在关注这个链接: 并且在我的代码中使用了相同的全局值

  • MyView(ContentView)
  • 主页(包括MyView)
  • 设置页面(包括相同的MyView)
  • GLobalVar.cs
  • 视图模型
  • 公共类MyViewModel:BaseViewModel { 公共可观测集合义务1{get;set;} 公共可观测集合义务2{get;set;} 公共可观测集合义务3{get;set;} 公共对象SelectedItem1{get;set;} public obj SelectedItem2{get;set;} public obj SelectedItem3{get;set;} 公共MyViewModel() { 倾角1=新的可观测集合(); 倾角2=新的可观测集合(); 倾角3=新的可观测集合(); } } 也许我应该在设置页面上通知对viewmodel的更改?或者在viewmodel的“集合”中执行某些操作

    令人困惑的是,两个页面使用相同的viewmodel嵌入相同的视图,但只通知从Page1到Page2的更改,而不是从Page2到Page1的更改


    任何想法,请提前发送thx。

    解决方案一:

    使用可以将值传递回上一页

    在第二页中定义事件:

    public delegate void EventHandler(string status);
    public event EventHandler EventPass;
    
    页面消失时调用事件:

    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        EventPass("Back Code");
    }
    
    在第一页中,Naviagation place需要在此处添加事件时:

    string title = "PageSecondParamater";
    PageSecond pageSecond = new PageSecond(title);
    pageSecond.EventPass += PageSecond_EventPass; ;
    Navigation.PushAsync(pageSecond);
    
    现在将在此处传递值:

    private void PageSecond_EventPass(string status)
    {
        Title = status;
        Console.WriteLine("---" + status);
    }
    
    解决方案二:

    用于在应用程序中存储简单且小尺寸的数据,当进入页面时,将调用它以获取已存储的数据

    在要存储数据的第二页中,写下:

    Application.Current.Properties ["value"] = valuedata;
    
    返回到第一页时,重写OnAppearing方法以更新UI:

    protected override void OnAppearing()
    {
        base.OnAppearing();
        if (Application.Current.Properties.ContainsKey("value"))
        {
            var ValueGet = Application.Current.Properties ["value"] as DataType;
            // do something with other things
        }
    }
    
    注意:ViewModel如果要动态更新数据,需要使用

    示例实现:

    public class ObservableProperty : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    ViewModelBase建议将ICommand实现为字典结构,如:

    public abstract class ViewModelBase : ObservableProperty
    {
        public Dictionary<string,ICommand> Commands { get; protected set; }
    
        public ViewModelBase()
        {
            Commands = new Dictionary<string,ICommand>();
        }
    }
    
    解决了

    MyViewModel(更新版)

    公共类MyViewModel:BaseViewModel { 公共可观测集合义务1{get;set;} 公共可观测集合义务2{get;set;} 公共可观测集合义务3{get;set;} 私有对象_selectedItem1=新对象(); 公共对象SelectedItem1 { 获取{return\u selectedItem1;} //这条线解决了问题 //但仍然没有完全理解 set{SetProperty(ref _selectedItem1,value);} } //与_selectedItem2 _selectedItem3相同 } 备注:此处的BaseViewModel代码(未更改,来自模板代码)

    公共类BaseViewModel:INotifyPropertyChanged
    {
    //其他一些属性
    //...
    受保护的布尔设置属性(参考T backingStore,T值,
    [CallerMemberName]字符串propertyName=“”,
    操作onChanged=null)
    {
    if(EqualityComparer.Default.Equals(backingStore,value))
    返回false;
    backingStore=价值;
    onChanged?.Invoke();
    OnPropertyChanged(propertyName);
    返回true;
    }
    #区域inotifyproperty已更改
    公共事件属性更改事件处理程序属性更改;
    受保护的void OnPropertyChanged([CallerMemberName]字符串propertyName=”“)
    {
    var changed=Property changed;
    如果(已更改==null)
    返回;
    Invoke(这是新的PropertyChangedEventArgs(propertyName));
    }
    #端区
    }
    }
    
    似乎通过调用SetProperty,OnPropertyChanged也将被撤销


    但是对于为什么前面的代码类似于“单向”绑定,仍然有点困惑。

    您需要确保您的ViewModel实现了INotifyPropertyChangedThx,我忘了提到我从主细节模板创建了项目,该模板有一个BaseViewModel,我基于此创建了我的viewmodels。所以INotifyPropertyChanged可能不是问题。准确地说,它更像第一页上的一些设置,但在第二页上显示更多设置,这就是为什么我需要在那里嵌入相同的视图。只是想知道:为什么视图模型中的属性不在其setter中实现OnPropertyChanged(否则他们不会真正通知任何更改)…哇,感谢您提供了这么多选项,第一个是非常传统的事件,第二个是默认的全局参数,所以我将再次检查动态解决方案,因为我非常热衷于应用MVVM,我可能会错过那里的“OnPropertyChanged”。也感谢您的“命令”建议,我认为这就是真正的MVVM的工作原理。@Shaw很高兴能帮上忙:)@Shaw Ha,谢谢!这对其他人也有帮助。
    private void PageSecond_EventPass(string status)
    {
        Title = status;
        Console.WriteLine("---" + status);
    }
    
    Application.Current.Properties ["value"] = valuedata;
    
    protected override void OnAppearing()
    {
        base.OnAppearing();
        if (Application.Current.Properties.ContainsKey("value"))
        {
            var ValueGet = Application.Current.Properties ["value"] as DataType;
            // do something with other things
        }
    }
    
    public class ObservableProperty : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    public abstract class ViewModelBase : ObservableProperty
    {
        public Dictionary<string,ICommand> Commands { get; protected set; }
    
        public ViewModelBase()
        {
            Commands = new Dictionary<string,ICommand>();
        }
    }
    
    class LoginViewModel : ViewModelBase
    {
        string userName;
        string password;
    
        public string UserName 
        {
             get {return userName;}
            set 
            {
                userName = value;
                OnPropertyChanged("UserName");
            }
         }
    
        public string Password 
        {
            get{return password;}
            set
            {
                password = value;
                OnPropertyChanged("Password");
            }
        }
        #endregion
    
        #region ctor
        public LoginViewModel()
        {
            //Add Commands
            Commands.Add("Login", new Command(CmdLogin));
        }
        #endregion
    
    
        #region UI methods
    
        private void CmdLogin()
        {
            // do your login jobs here
        }
        #endregion
    }
    
        public class MyViewModel : BaseViewModel
        {
            public ObservableCollection<obj> ObList1 { get; set; }
            public ObservableCollection<obj> ObList2 { get; set; }
            public ObservableCollection<obj> ObList3 { get; set; }
    
            private obj _selectedItem1 = new obj();
            public obj SelectedItem1 
            {
                get { return _selectedItem1; }
    
                //this is the line solved the problem
                //but still not understood thoroughly
                set { SetProperty(ref _selectedItem1, value); }
            }
    
            //same for _selectedItem2 _selectedItem3
    
        }
    
     public class BaseViewModel : INotifyPropertyChanged
        {
            //some other attributes
            //...
    
            protected bool SetProperty<T>(ref T backingStore, T value,
                [CallerMemberName]string propertyName = "",
                Action onChanged = null)
            {
                if (EqualityComparer<T>.Default.Equals(backingStore, value))
                    return false;
    
                backingStore = value;
                onChanged?.Invoke();
                OnPropertyChanged(propertyName);
                return true;
            }
    
            #region INotifyPropertyChanged
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
            {
                var changed = PropertyChanged;
                if (changed == null)
                    return;
    
                changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
            #endregion
        }
    }