簡體   English   中英

在Xamarin.Forms中,如何將同一個viewmodel的變化通知回上一頁? (可以跳轉到第二頁,但不能返回)

[英]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? 並在我的代碼中做了相同的全局值。

  1. 我的視圖(內容視圖)
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
}
  1. 主頁(包括 MyView)
public SearchPage ()
{
    InitializeComponent ();
    BindingContext = GlobalVar.MyViewModel;
}

private async void Click_GoSetting(object sender, EventArgs e)
{
    await Navigation.PushAsync(new SettingPage());
}
  1. SettingPage(包括同一個MyView)
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
}
  1. 全局變量
        private static  MyViewModel _myViewModel = new MyrViewModel();
        public static MyViewModel MyViewModel
        {
            get
            {
                return _myViewModel;
            }
        }
  1. 視圖模型
    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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM