我是MvvmCross和Xamarin的新手,也许我在这里想念一些东西,但是当我尝试将一些数据从rownums
传递到ViewModel
时就像这里所描述的那样(差不多)
https://www.mvvmcross.com/documentation/fundamentals/mvxinteraction
但问题是 - View
中的MvxInteraction
变量始终为空,即使我传递了字符串!
View
ViewModel代码:
public IMvxInteraction<MenuViewModel.YesNoQuestion> Interaction
{
get
{
return _interaction;
}
set
{
if (_interaction != null) // <-- Always NULL!
_interaction.Requested -= OnInteractionRequested;
_interaction = value;
_interaction.Requested += OnInteractionRequested;
}
}
查看代码:
public class MenuViewModel : MvxViewModel
{
private IDataScanner _dataScanner { get; set; }
//demo
public class YesNoQuestion
{
public string Question { get; set; }
}
private MvxInteraction<YesNoQuestion> _interaction = new MvxInteraction<YesNoQuestion>();
// need to expose it as a public property for binding (only IMvxInteraction is needed in the view)
public IMvxInteraction<YesNoQuestion> Interaction
{
get
{
return _interaction;
}
}
private void DoFinishProfileCommand()
{
// 1. do cool stuff with profile data
// ...
// 2. request interaction from view
// 3. execution continues in callbacks
var request = new YesNoQuestion
{
Question = "Do you want to save your profile?"
};
_interaction.Raise(request);
}
// demo
public class DataEventArgs : EventArgs
{
public List<string> DataList;
}
public delegate void ScanDoneEvent(object sender, DataEventArgs args);
public event ScanDoneEvent ScanDone;
protected virtual void OnScanDone(List<string> dataList)
{
ScanDone?.Invoke(this, new DataEventArgs { DataList = dataList });
}
public MenuViewModel(IDataScanner dataScanner)
{
_dataScanner = dataScanner;
RunScan();
}
private ObservableCollection<string> _filesCollection;
public ObservableCollection<string> FilesCollection
{
get { return _filesCollection; }
set
{
_filesCollection = value;
RaisePropertyChanged(() => FilesCollection);
}
}
private async void RunScan()
{
var files = await _dataScanner.GetDataListAsync().ConfigureAwait(false);
FilesCollection = new ObservableCollection<string>(files);
DoFinishProfileCommand();
}
}
UPD 09.11.2017
最后让它以我想要的方式运作。
而不是MvxInteraction我只是简单地使用服务,因为nmilcoff(非常感谢btw的答案)建议,当我从它调用toast时将它包装在 [Activity]
public class MenuView : MvxActivity
{
public MenuView()
{
var set = this.CreateBindingSet<MenuView, MenuViewModel>();
set.Bind(this).For(view => view.Interaction).To(viewModel => viewModel.Interaction).OneWay();
set.Apply();
}
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.menu_view);
}
//demo
private IMvxInteraction<MenuViewModel.YesNoQuestion> _interaction;
public IMvxInteraction<MenuViewModel.YesNoQuestion> Interaction
{
get
{
return _interaction;
}
set
{
if (_interaction != null)// <-- Always NULL!
_interaction.Requested -= OnInteractionRequested;
_interaction = value;
_interaction.Requested += OnInteractionRequested;
}
}
private async void OnInteractionRequested(object sender, MvxValueEventArgs<MenuViewModel.YesNoQuestion> eventArgs)
{
var yesNoQuestion = eventArgs.Value.Question;
// show dialog
Toast.MakeText(this, yesNoQuestion, ToastLength.Long).Show();
}
}
中。
所以,最终的代码在这里。
ToastService:
runOnUiThread
MenuViewModel:
public class ToastService : IToastService
{
private readonly IMvxAndroidCurrentTopActivity _topActivity;
public ToastService(IMvxAndroidCurrentTopActivity topActivity)
{
_topActivity = topActivity;
}
public void ShowToast(string message)
{
_topActivity.Activity.RunOnUiThread(
() => Toast.MakeText(_topActivity.Activity.ApplicationContext, message, ToastLength.Long).Show()
);
}
}
答案 0 :(得分:2)
您可能会发现StarWarsSample有趣,因为它使用MvxInteraction。
正如您在该应用中所看到的,您需要稍后在View代码中声明绑定。您可以将Fluent Binding块移动到Activity的OnCreate(Android.OS.Bundle bundle)
方法吗?像这样:
protected override void OnCreate(Android.OS.Bundle bundle)
{
base.OnCreate(bundle);
var set = this.CreateBindingSet<MenuView, MenuViewModel>();
set.Bind(this).For(view => view.Interaction).To(viewModel => viewModel.Interaction).OneWay();
set.Apply();
}
但这可能不会起作用,因为您在代码中过早地请求MvxInteraction。因此,我建议您改为使用依赖服务:
1)使用显示toast的方法在Core级别创建一个接口:
public interface IToastService
{
void ShowToast(string message);
}
2)在平台级别创建服务的实现:
public class ToastService : IToastService
{
private readonly IMvxAndroidCurrentTopActivity _topActivity;
public ToastService(IMvxAndroidCurrentTopActivity topActivity)
{
_topActivity = topActivity;
}
public void ShowToast(string message)
{
Toast.MakeText(activity.ApplicationContext, message, ToastLength.Short).Show();
}
}
3)使用IoC Container注册您的服务。像这样的东西(在你的平台项目的Setup类中):
protected override void InitializeLastChance()
{
base.InitializeLastChance();
Mvx.RegisterType<IToastService, ToastService>();
}
那就是它。您已准备好随时随地注入/解决您的IToast服务!