В Xamarin.Forms, как сообщить об изменениях той же модели представления обратно на предыдущую страницу?(может перейти на вторую страницу, но не обратно) - PullRequest
1 голос
/ 03 мая 2019

Я получил две страницы: «Домашняя страница», «Настройка страницы», включая тот же «MyView» (некоторые средства выбора там). Когда я нажимаю кнопку «Перейти к настройке» (или показывает дополнительные настройки) на домашней странице, значения синхронизируются со страницей настройки. Но когда я нажимаю «Применить» на странице настроек, значения не возвращаются.

Я новичок в c # и Xamarin и пытался искать в Интернете и документах Microsoft. Но я не мог найти способ исправить эту проблему.

Также я перешел по этой ссылке: Как установить BindingContext для нескольких страниц на один и тот же ViewModel в Xamarin.Forms? и сделал то же глобальное значение в моем коде.

  1. MyView (ContentView)
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. GLobalVar.cs
        private static  MyViewModel _myViewModel = new MyrViewModel();
        public static MyViewModel MyViewModel
        {
            get
            {
                return _myViewModel;
            }
        }
  1. ViewModel
    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.

Любые идеи, спасибо заранее.

Ответы [ 2 ]

0 голосов
/ 03 мая 2019

решаемая.

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 также будет отменен.

Но все еще немного сбивает с толку то, почему предыдущие коды выглядят как «односторонняя» привязка.

0 голосов
/ 03 мая 2019

Решение первое:

Использование Событие может передать значение обратно на предыдущую страницу.

Определение события в SecondPage:

public delegate void EventHandler(string status);
public event EventHandler EventPass;

Вызвать событие, когда страница исчезнет:

protected override void OnDisappearing()
{
    base.OnDisappearing();
    EventPass("Back Code");
}

В FirstPage, когда место Навигации нужно добавить событие здесь:

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 для обновления пользовательского интерфейса:

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
}
...