我有两个页面,"主页","设置",包括相同的" myview"(那里的一些选择器(。当我单击主页中的" Go设置"(或显示更多设置(按钮时,值将同步到设置页面。但是,当我在设置页面上单击"应用"时,值不会返回。
我是C#和Xamarin中的新手,并试图在线搜索和Microsoft文档。但是我找不到解决此问题的方法。
我还遵循此链接:如何将多个页面的bindingContext设置为xamarin.forms中的同一viewModel?并在我的代码中执行了相同的全球价值。
- 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
}
- 主页(包括myview(
public SearchPage ()
{
InitializeComponent ();
BindingContext = GlobalVar.MyViewModel;
}
private async void Click_GoSetting(object sender, EventArgs e)
{
await Navigation.PushAsync(new 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
}
- globalvar.cs
private static MyViewModel _myViewModel = new MyrViewModel();
public static MyViewModel MyViewModel
{
get
{
return _myViewModel;
}
}
- 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>();
}
}
也许我应该将设置页面上的更改通知ViewModel?或在ViewModel中的"集合"中做某事?
令人困惑的点是,两个页面使用相同的ViewModel嵌入了相同的视图,但仅通知从第1页到Page2的更改,而不是Page2到Page1。
任何想法,提前提前。
解决方案一:
使用事件可以将值传递回上一页。
在第二页中定义事件:
public delegate void EventHandler(string status);
public event EventHandler EventPass;
页面消失时调用事件:
protected override void OnDisappearing()
{
base.OnDisappearing();
EventPass("Back Code");
}
在第一页中,当Naviagtion 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);
}
解决方案两个:
使用属性字典在应用程序中存储简易尺寸的数据,当Enter in Page中调用它以获取已存储的数据。
在您要存储数据的第二页中,以波纹管写作:
Application.Current.Properties ["value"] = valuedata;
返回第一页时,覆盖了更新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中的所有todo都只是继承了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,也将被撤销。
,但仍然有些困惑,为什么以前的代码像"单向"绑定。