[英]In Xamarin.Forms, how to notify the changes of the same viewmodel back to the previous page? (can pass to the second page, but not back)
我有兩個頁面,“主頁”,“設置頁面”,包括相同的“MyView”(那里有一些選擇器)。 當我從主頁單擊“開始設置”(或顯示更多設置)按鈕時,值會同步到設置頁面。 但是當我在設置頁面上單擊“應用”時,值沒有回來。
我是 c# 和 Xamarin 的新手,並嘗試在線搜索和 Microsoft 文檔。 但我找不到解決這個問題的方法。
我也在關注這個鏈接: How to set BindingContext of multiple pages to the same ViewModel in Xamarin.Forms? 並在我的代碼中做了相同的全局值。
public MyView()
{
InitializeComponent();
BindingContext = GlobalVar.MyViewModel;
Setting1.SetBinding(Picker.ItemsSourceProperty, "ObList1");
Setting1.ItemDisplayBinding = new Binding("obj_text");
Setting1.SetBinding(Picker.SelectedItemProperty, "SelectedItem1");
//also other pickers
}
public SearchPage ()
{
InitializeComponent ();
BindingContext = GlobalVar.MyViewModel;
}
private async void Click_GoSetting(object sender, EventArgs e)
{
await Navigation.PushAsync(new SettingPage());
}
public partial class SettingPage : ContentPage
{
MyViewModel viewModel { get; set; } = GlobalVar.MyViewModel;
public SettingPage ()
{
BindingContext = viewModel;
}
private async void Click_ApplySetting(object sender, EventArgs e)
{
await Navigation.PopAsync(true);
}
//some other method deal with viewModel
}
private static MyViewModel _myViewModel = new MyrViewModel();
public static MyViewModel MyViewModel
{
get
{
return _myViewModel;
}
}
public class MyViewModel : BaseViewModel
{
public ObservableCollection<obj> ObList1 { get; set; }
public ObservableCollection<obj> ObList2 { get; set; }
public ObservableCollection<obj> ObList3 { get; set; }
public obj SelectedItem1 { get; set; }
public obj SelectedItem2 { get; set; }
public obj SelectedItem3 { get; set; }
public MyViewModel()
{
ObList1 = new ObservableCollection<obj>();
ObList2 = new ObservableCollection<obj>();
ObList3 = new ObservableCollection<obj>();
}
}
也許我應該將 SettingPage 上的更改通知給 viewmodel? 或者在視圖模型的“集合”中做一些事情?
令人困惑的一點是,兩個頁面使用相同的視圖模型嵌入了相同的視圖,但僅通知從 Page1 到 Page2 的更改,而不是從 Page2 到 Page1。
任何想法,提前謝謝。
解決方案一:
使用事件可以將值傳遞回上一頁。
在 SecondPage 中定義事件:
public delegate void EventHandler(string status);
public event EventHandler EventPass;
頁面消失時調用事件:
protected override void OnDisappearing()
{
base.OnDisappearing();
EventPass("Back Code");
}
在FirstPage中,當Naviagtion地方需要在這里添加Event時:
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);
}
解決方案二:
使用Properties Dictionary在Application 中存儲簡單的小尺寸數據,當進入頁面時會調用它來獲取已存儲的數據。
在第二頁你想存儲數據的地方,寫如下:
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 如果要動態更新數據,需要使用INotifyPropertyChanged 。
示例實現:
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>();
}
}
因此,您的 ViewModel 中的所有待辦事項只是繼承 ViewModelBase 類並使用它:
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
}
解決了。
MyViewModel(更新)
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
}
ps:此處為BaseViewModel代碼(未更改,來自模板代碼)
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
}
}
似乎通過調用SetProperty,OnPropertyChanged 也會被撤銷。
但是對於為什么以前的代碼像一種“單向”綁定仍然有點困惑。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.