无法将命令绑定到 MvvmCross 按钮
Cannot Bind a Command to a MvvmCross Button
我正在尝试创建一个导航到 mvvmCross 中另一个页面的按钮。应用程序正确启动,但按下按钮时没有任何反应。
我使用的是 Bable project 的修改版本,它已更新为使用 mvvmcross 8。并且被精简为仅包含我认为在两个视图模型之间移动的最小值。
这是当前代码:
核心class库:
FirstViewModel.cs
using MvvmCross.Commands;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;
namespace Babel2.Core.ViewModels {
public class FirstViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public FirstViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public IMvxCommand GoCommand => new MvxCommand(() => _navigationService.Navigate<SecondViewModel>());
} }
SecondViewModel.cs
using MvvmCross.ViewModels;
namespace Babel2.Core.ViewModels
{
public class FirstViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public FirstViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public IMvxCommand GoCommand => new MvxCommand(() => _navigationService.Navigate<SecondViewModel>());
}
}
App.cs
using MvvmCross.IoC;
using MvvmCross.ViewModels;
namespace Babel2.Core
{
public class App : MvxApplication
{
public override void Initialize()
{
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
RegisterAppStart<ViewModels.FirstViewModel>();
}
}
}
Android 项目
FirstView.axml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="Second Page Go!"
local:MvxBind="Click GoCommand" />
</LinearLayout>
SecondView.axml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
android:text="Second View" />
</LinearLayout>
SplashScreen.axml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Loading...." />
</LinearLayout>
FirstView.cs
using Android.App;
using Android.OS;
using MvvmCross.Platforms.Android.Views;
namespace Babel2.Droid.Views
{
[Activity(Label = "View for FirstViewModel")]
public class FirstView : MvxActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.FirstView);
}
}
}
SecondView.cs
using Android.OS;
using Android.Views;
using MvvmCross.Platforms.Android.Views.Fragments;
namespace Babel2.Droid.Views
{
public class SecondView : MvxFragment
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
View view = inflater.Inflate(Resource.Layout.SecondView, container, false);
return view;
}
}
}
LinkerPleaseInclude.cs
using System.Collections.Specialized;
using System.Windows.Input;
using Android.App;
using Android.Views;
using Android.Widget;
using MvvmCross;
namespace Babel2.Droid
{
[Preserve(AllMembers = true)]
public class LinkerPleaseInclude
{
public void Include(Button button)
{
button.Click += (s,e) => button.Text = button.Text + "";
}
public void Include(CheckBox checkBox)
{
checkBox.CheckedChange += (sender, args) => checkBox.Checked = !checkBox.Checked;
}
public void Include(Switch @switch)
{
@switch.CheckedChange += (sender, args) => @switch.Checked = !@switch.Checked;
}
public void Include(View view)
{
view.Click += (s, e) => view.ContentDescription = view.ContentDescription + "";
}
public void Include(TextView text)
{
text.TextChanged += (sender, args) => text.Text = "" + text.Text;
text.Hint = "" + text.Hint;
}
public void Include(CheckedTextView text)
{
text.TextChanged += (sender, args) => text.Text = "" + text.Text;
text.Hint = "" + text.Hint;
}
public void Include(CompoundButton cb)
{
cb.CheckedChange += (sender, args) => cb.Checked = !cb.Checked;
}
public void Include(SeekBar sb)
{
sb.ProgressChanged += (sender, args) => sb.Progress = sb.Progress + 1;
}
public void Include(Activity act)
{
act.Title = act.Title + "";
}
public void Include(INotifyCollectionChanged changed)
{
changed.CollectionChanged += (s,e) => { var test = $"{e.Action}{e.NewItems}{e.NewStartingIndex}{e.OldItems}{e.OldStartingIndex}"; };
}
public void Include(ICommand command)
{
command.CanExecuteChanged += (s, e) => { if (command.CanExecute(null)) command.Execute(null); };
}
// public void Include(MvvmCross.Platform.IoC.MvxPropertyInjector injector)
// {
// injector = new MvvmCross.Platform.IoC.MvxPropertyInjector ();
// }
public void Include(System.ComponentModel.INotifyPropertyChanged changed)
{
changed.PropertyChanged += (sender, e) => {
var test = e.PropertyName;
};
}
}
}
Setup.cs
using Babel2.Core;
using Microsoft.Extensions.Logging;
using MvvmCross.Platforms.Android.Core;
using Serilog.Extensions.Logging;
namespace Babel2.Droid
{
public class Setup : MvxAndroidSetup<App>
{
protected override ILoggerProvider CreateLogProvider()
{
return new SerilogLoggerProvider();
}
protected override ILoggerFactory CreateLogFactory()
{
return new SerilogLoggerFactory();
}
}
}
SplashScreen.cs
using Android.App;
using Android.Content.PM;
using MvvmCross.Platforms.Android.Views;
namespace Babel2.Droid
{
[Activity(
Label = "Babel2.Droid"
, MainLauncher = true
, Icon = "@drawable/icon"
, Theme = "@style/AppTheme"
, NoHistory = true
, ScreenOrientation = ScreenOrientation.Portrait)]
public class SplashScreen : MvxSplashScreenActivity
{
public SplashScreen()
: base(Resource.Layout.SplashScreen)
{
}
}
}
您需要将 ViewModel 与 View 连接起来,在您的情况下,它将是:
public class FirstView : MvxActivity<FirstViewModel>
你的第二个视图也是一样的:
public class SecondView : MvxFragment<SecondViewModel>
记得勾选Playground repo to explore how to use the framework. Also, you can check the Star Wars sample repo。
另一方面,不要忘记为每个视图添加展示属性,请阅读official docs about Android View Presenters。
我正在尝试创建一个导航到 mvvmCross 中另一个页面的按钮。应用程序正确启动,但按下按钮时没有任何反应。
我使用的是 Bable project 的修改版本,它已更新为使用 mvvmcross 8。并且被精简为仅包含我认为在两个视图模型之间移动的最小值。
这是当前代码:
核心class库:
FirstViewModel.cs
using MvvmCross.Commands;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;
namespace Babel2.Core.ViewModels {
public class FirstViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public FirstViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public IMvxCommand GoCommand => new MvxCommand(() => _navigationService.Navigate<SecondViewModel>());
} }
SecondViewModel.cs
using MvvmCross.ViewModels;
namespace Babel2.Core.ViewModels
{
public class FirstViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public FirstViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public IMvxCommand GoCommand => new MvxCommand(() => _navigationService.Navigate<SecondViewModel>());
}
}
App.cs
using MvvmCross.IoC;
using MvvmCross.ViewModels;
namespace Babel2.Core
{
public class App : MvxApplication
{
public override void Initialize()
{
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
RegisterAppStart<ViewModels.FirstViewModel>();
}
}
}
Android 项目
FirstView.axml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="Second Page Go!"
local:MvxBind="Click GoCommand" />
</LinearLayout>
SecondView.axml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
android:text="Second View" />
</LinearLayout>
SplashScreen.axml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Loading...." />
</LinearLayout>
FirstView.cs
using Android.App;
using Android.OS;
using MvvmCross.Platforms.Android.Views;
namespace Babel2.Droid.Views
{
[Activity(Label = "View for FirstViewModel")]
public class FirstView : MvxActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.FirstView);
}
}
}
SecondView.cs
using Android.OS;
using Android.Views;
using MvvmCross.Platforms.Android.Views.Fragments;
namespace Babel2.Droid.Views
{
public class SecondView : MvxFragment
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
View view = inflater.Inflate(Resource.Layout.SecondView, container, false);
return view;
}
}
}
LinkerPleaseInclude.cs
using System.Collections.Specialized;
using System.Windows.Input;
using Android.App;
using Android.Views;
using Android.Widget;
using MvvmCross;
namespace Babel2.Droid
{
[Preserve(AllMembers = true)]
public class LinkerPleaseInclude
{
public void Include(Button button)
{
button.Click += (s,e) => button.Text = button.Text + "";
}
public void Include(CheckBox checkBox)
{
checkBox.CheckedChange += (sender, args) => checkBox.Checked = !checkBox.Checked;
}
public void Include(Switch @switch)
{
@switch.CheckedChange += (sender, args) => @switch.Checked = !@switch.Checked;
}
public void Include(View view)
{
view.Click += (s, e) => view.ContentDescription = view.ContentDescription + "";
}
public void Include(TextView text)
{
text.TextChanged += (sender, args) => text.Text = "" + text.Text;
text.Hint = "" + text.Hint;
}
public void Include(CheckedTextView text)
{
text.TextChanged += (sender, args) => text.Text = "" + text.Text;
text.Hint = "" + text.Hint;
}
public void Include(CompoundButton cb)
{
cb.CheckedChange += (sender, args) => cb.Checked = !cb.Checked;
}
public void Include(SeekBar sb)
{
sb.ProgressChanged += (sender, args) => sb.Progress = sb.Progress + 1;
}
public void Include(Activity act)
{
act.Title = act.Title + "";
}
public void Include(INotifyCollectionChanged changed)
{
changed.CollectionChanged += (s,e) => { var test = $"{e.Action}{e.NewItems}{e.NewStartingIndex}{e.OldItems}{e.OldStartingIndex}"; };
}
public void Include(ICommand command)
{
command.CanExecuteChanged += (s, e) => { if (command.CanExecute(null)) command.Execute(null); };
}
// public void Include(MvvmCross.Platform.IoC.MvxPropertyInjector injector)
// {
// injector = new MvvmCross.Platform.IoC.MvxPropertyInjector ();
// }
public void Include(System.ComponentModel.INotifyPropertyChanged changed)
{
changed.PropertyChanged += (sender, e) => {
var test = e.PropertyName;
};
}
}
}
Setup.cs
using Babel2.Core;
using Microsoft.Extensions.Logging;
using MvvmCross.Platforms.Android.Core;
using Serilog.Extensions.Logging;
namespace Babel2.Droid
{
public class Setup : MvxAndroidSetup<App>
{
protected override ILoggerProvider CreateLogProvider()
{
return new SerilogLoggerProvider();
}
protected override ILoggerFactory CreateLogFactory()
{
return new SerilogLoggerFactory();
}
}
}
SplashScreen.cs
using Android.App;
using Android.Content.PM;
using MvvmCross.Platforms.Android.Views;
namespace Babel2.Droid
{
[Activity(
Label = "Babel2.Droid"
, MainLauncher = true
, Icon = "@drawable/icon"
, Theme = "@style/AppTheme"
, NoHistory = true
, ScreenOrientation = ScreenOrientation.Portrait)]
public class SplashScreen : MvxSplashScreenActivity
{
public SplashScreen()
: base(Resource.Layout.SplashScreen)
{
}
}
}
您需要将 ViewModel 与 View 连接起来,在您的情况下,它将是:
public class FirstView : MvxActivity<FirstViewModel>
你的第二个视图也是一样的:
public class SecondView : MvxFragment<SecondViewModel>
记得勾选Playground repo to explore how to use the framework. Also, you can check the Star Wars sample repo。
另一方面,不要忘记为每个视图添加展示属性,请阅读official docs about Android View Presenters。