如何更改ActionBar的操作视图';与Xamarin的菜单项

本文关键字:Xamarin 菜单项 视图 何更改 ActionBar 操作 | 更新日期: 2023-09-27 17:59:43

我在ActionBar中有一个带有图标的菜单项,当用户单击它、运行任务,然后将其更改回图标时,我想将其更改为ProgressBar。下面是我的代码,但单击菜单项时不会发生任何事情。

活动:ImportReferenceView.cs

public class ImportReferenceView : MvxActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.ImportReferenceView);
        ActionBar.SetDisplayShowCustomEnabled(true);
    }
    public override bool OnCreateOptionsMenu(Android.Views.IMenu menu)
    {
        MenuInflater.Inflate(Resource.Menu.import_actions, menu);
        return true;
    }
    public override bool OnOptionsItemSelected(Android.Views.IMenuItem item)
    {
        switch (item.ItemId)
        {
            case Resource.Id.action_import:
                item.SetActionView(Resource.Layout.progressbar);
                item.ExpandActionView();
                var vm = ((ImportReferenceViewModel)ViewModel);
                Task task = Task.Run(() =>    vm.ImportCommand.Execute(vm.SelectedTableReferences));
                Task.WaitAll(new Task[] { task });
                item.CollapseActionView();
                item.SetActionView(null);
                break;
            default:
                break;
        }
        return true;
    }
}

菜单操作:import_actions.xml

<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
  <item
      android:id="@+id/action_import"
      android:showAsAction="always"
      android:icon="@drawable/action_down"
      android:title="Refresh"/>
</menu>

progressbar视图:progressbar.axml

<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/progressBar2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

我正试图用Xamarin实现类似于本文的操作栏/操作视图部分中描述的功能

任何帮助或建议都将不胜感激

如何更改ActionBar的操作视图';与Xamarin的菜单项

以下是我的操作方法:

public override bool OnCreateOptionsMenu(IMenu menu)
{
    MenuInflater.Inflate(Resource.Menu.home_menu, menu);
    _refreshWrapper = new RefreshActionButtonWrapper(menu);
    var set = this.CreateBindingSet<HomeView, HomeViewModel>();
    set.Bind(_refreshWrapper).For("IsBusy").To(vm => vm.MyService.IsBusy);
    set.Apply();
    return true;
}

我使用MvvvmCross数据绑定将IsBusy属性绑定到包装类。你不必那样做。您可以直接设置IsBusy属性(请参阅下面的示例)。

public class RefreshActionButtonWrapper
{
    private readonly IMenu _optionsMenu;
    public RefreshActionButtonWrapper(IMenu optionsMenu)
    {
        _optionsMenu = optionsMenu;
    }
    private bool _isBusy;
    public bool IsBusy
    {
        get { return _isBusy; }
        set
        {
            _isBusy = value;
            var dispatcher = MvxMainThreadDispatcher.Instance;
            dispatcher.RequestMainThreadAction(() => SetRefreshActionButtonState(_isBusy));
        }
    }
    public void SetRefreshActionButtonState(bool refreshing)
    {
        if (_optionsMenu == null) return;
        var refreshItem = _optionsMenu.FindItem(Resource.Id.refresh_action);
        if (refreshing)
        {
            refreshItem.SetActionView(Resource.Layout.actionbar_indeterminate_progress);
        }
        else
        {
            refreshItem.SetActionView(null);
        }
    }
}

诀窍是更改主线程上的操作视图。MvvmCross提供了一种在主线程上调用请求的方法:

var dispatcher = MvxMainThreadDispatcher.Instance;
dispatcher.RequestMainThreadAction(() => SetRefreshActionButtonState(_isBusy));

然后你可以做这样的事情。使用wait等待导入功能完成。我喜欢将IsBusy状态包装在try/finaly中,以确保IsBusy始终设置为false,即使在异常情况下也是如此。

public override bool OnOptionsItemSelected(Android.Views.IMenuItem item)
{
    switch (item.ItemId)
    {
        case Resource.Id.action_import:
            try
            {
                _refreshWrapper.IsBusy = true;
                var vm = ((ImportReferenceViewModel)ViewModel);
                await Task.Run(() => vm.ImportCommand.Execute(vm.SelectedTableReferences));             
            }
            finally 
            {
                _refreshWrapper.IsBusy = false;
            }
            break;
        default:
            break;
    }
    return true;
}

BTW:如果您从MvxActivity<ImportReferenceViewModel>您将拥有一个强类型的ViewModel属性,并且不必强制转换它。