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