【问题标题】:Disable ToolbarItem Xamarin.Forms禁用 ToolbarItem Xamarin.Forms
【发布时间】:2015-01-06 16:35:32
【问题描述】:

我的页面中有以下内容:

<ContentPage.ToolbarItems>
    <ToolbarItem Text="Run" Command="{Binding RunCommand}" />
</ContentPage.ToolbarItems>

该命令启动异步任务。 只要异步任务仍在运行,我就尝试通过将其绑定到布尔属性来禁用控件,如下所示:

<ContentPage.ToolbarItems>
    <ToolbarItem Text="Run" Command="{Binding RunCommand}" IsEnabled="{Binding MyBoolProperty}" />
</ContentPage.ToolbarItems>

我的问题是 ToolbarItem 似乎没有“IsEnabled”属性。有没有办法使用 Xamarin.Forms 实现我想要做的事情?

【问题讨论】:

  • 注意,我尝试用“Button”替换“ToolbarItem”,结果惨遭失败:“Object type Xamarin.Forms.Button cannot be convert to target type: Xamarin.Forms.ToolbarItem”。
  • 如果您在 UI 线程上运行它,则取决于您的操作的预期长度,按钮保持按下状态。这是一个丑陋的黑客,你不应该将它用于网络访问,因为这会锁定你的应用很长时间
  • 也许源已经更新,但现在有一个IsEnabled property。不过,我仍然无法更改设置后的值。

标签: c# xaml xamarin xamarin.forms


【解决方案1】:

在 William 和 Xamarin 支持的帮助下,我终于能够找到功能的工作原理。

这有点反直觉,因为我们希望启用/禁用按钮 (ToolbarItem),但我们实际上必须管理绑定到按钮的命令的状态。一旦我们理解了这种模式,它就有意义了。

ICommand 类型的 Command 对象,具有 CanExecute 属性(感谢 William 指出) 现在你不想直接访问/使用它,除非它是为了实际检查命令是否可以执行。

无论您认为代码中的哪个位置合适,要更改命令的状态,您都需要添加以下行:

((Command)_myCommand).ChangeCanExecute();

此行将强制为指定命令重新评估 CanExecute 属性。

我个人决定将它添加到我跟踪不活动的位置,因为它在我的应用程序中是有意义的。

public bool Inactive { 
    get { 
        return _inactive;
    } 
    set {
        if (_inactive != value) {
            _inactive = value;
            ((Command)_myCommand).ChangeCanExecute();
            OnPropertyChanged ();
        }
    }
}

在视图中,没有需要注意的变化:

<ToolbarItem Text="Run" Command="{Binding MyCommand}" />

现在,当您创建 Command 对象时,将完成大量工作。我们通常使用单参数构造函数,因为它通常就足够了,它是我们定义命令的地方。有趣的是,还有一个 2 参数构造函数,您可以在其中提供确定 CanExecute 属性值的函数/操作。

_myCommand = new Command (async () => {
                                          Inactive = false;
                                          await Run();
                                          Inactive = true;
                                      },
                                      () => {
                                          return Inactive;
                                      });


public ICommand MyCommand {
    get { 
        return _myCommand;
    }
}

编辑:我知道你在技术上应该在 Run() 中更改 Inactive 的值,但出于演示目的...

【讨论】:

  • 我的代码不适用于此示例。这真的禁用了按钮还是只是避免执行代码?你有这个实现的完整示例吗?谢谢。
  • 两者都有(禁用按钮并避免执行)。你在哪个平台?我已经在 iOS 和 Android 上进行了测试。另外,我知道有一个问题,当 ToolbarItem 的 order 设置为 Secondary 时,您看不到启用与否之间的区别,但如果禁用,代码仍然不会执行。
  • 我已将 MyCommand 的属性声明添加到答案中以完全关闭循环。
  • @LostBalloon 您将如何纯粹在 c# 中实现此模式?我正在像这样生成我的工具栏项目: ToolbarItems.Add(new ToolbarItem("add", "plus.png", () => { CreateItem(); }));
  • 在添加之前先执行 var tbi = new ToolbarItem("add", "plus.png", () =&gt; { CreateItem(); }); 然后 tbi.Command = ViewModel.MyCommand 其中 ViewModel 是您绑定上下文中的视图模型,然后只是 ToolbarItems.Add(tbi); 其余的应该非常相似
【解决方案2】:

此示例是删除,而不是禁用,但也可能很方便。

    ToolbarItem delToolbar;       

    ...

        delToolbar = new ToolbarItem
        {
            Order = ToolbarItemOrder.Primary,                
            Text = "delete",              
            Command = new Command(async () =>
            {                                       
                ToolbarItems.Remove(delToolbar);
            })
        };
        ToolbarItems.Add(delToolbar);

【讨论】:

    【解决方案3】:

    我在这些情况下学到的做法如下:

    public Command RunCommand 
    { 
        get { return new Command(async() => await OnRunCommand()); }
    }    
    
    private bool _isRunning;
    
    public async Task OnRunCommand() 
    {
        if (_isRunning) return;
        _isRunning = true;
    
        // do stuff
    
        _isRunning = false;
    }
    

    缺点:这会使工具栏项处于正常状态,用户可以继续点击它。

    优势:这将不允许同时执行 OnRunCommand 任务,这很好。

    如果你想通过显示禁用的图像来禁用按钮,你应该创建一个渲染器。

    如果您不想在任务运行时显示工具栏项,请考虑从页面中删除工具栏项并稍后重新添加。

    【讨论】:

    • 是的,我认为这是一个可能的“最坏情况”解决方案,但我真的不想破坏按钮的用户体验。我考虑提供一个弹出窗口,告诉他们耐心等待,因为任务已经在运行,尽管我更希望能够禁用它。对于一个像按钮一样的项目,我对这个非常基本的遗漏感到惊讶。
    • ToolbarItem 可能在 Xamarin Forms 1.3.0 中有一个 IsEnabled BindableProperty,现在我想到了。我会试试看。
    • 不幸的是,现在似乎还不是这样。
    • Xamarin Forms 1.3.2 pre-1 公开了一个 CanExecute 属性,可用于直观地禁用 ToolbarItem。
    • 您好,感谢您的信息。我试过了,但由于某种原因我无法获得 CanExecute 属性。 (我在这里检查过:forums.xamarin.com/discussion/31273/…,它应该存在,正如你提到的)我得到以下异常:“位置 9:75。找不到名称 CanExecute 的属性”,我似乎也无法在代码中找到它。奇怪的事情......
    【解决方案4】:

    就使用CanExecute 命令而言,LostBalloon 的答案是正确的。但我面临的问题是ToolbarItems 视觉状态 没有改变。我希望辅助工具栏项(即菜单项)在禁用时灰色(换句话说,当 CanExecute 返回 false 时)。一些作者说这是一个错误。可能是一个错误,但以下解决方案对我有用。

    结果:

    将禁用的工具栏项设为灰色:

    Resources/layout/Toolbar.xml 文件中的主题设置为MyToolbarTheme

    <androidx.appcompat.widget.Toolbar
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/MyToolbarTheme"
     />
    

    Resources/values/styles.xml中添加主题MyToolbarTheme

    <style name="MyToolbarTheme" parent="ThemeOverlay.AppCompat.Light">
        <item name="android:textColor">@color/menu_item_color_selector</item>
        </style>
    

    现在创建一个新文件Resources/color/menu_item_color_selector.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_enabled="true" android:color="#000"/>
        <item android:color="#999"/>
    </selector>
    

    旁注:

    1. 您可以使用不同的父主题,例如,您可以使用com.google.android.material.appbar.MaterialToolbar 来代替androidx.appcompat.widget.Toolbar。无论哪种方式都可以。

    2. 一些作者引用属性actionMenuTextColor 来更改菜单项字体颜色,但这个对我不起作用(不知道为什么)。相反,我使用的是android:textColor,它可以工作。

    3. 您可以在Toolbar.xml 中使用android:background 来设置工具栏本身的背景。

    4. 您可以通过在MyToolbarTheme 中设置colorControlNormal 来更改3 个点的颜色

    <item name="colorControlNormal">#0FF000</item>
    
    1. 您在 Visual Studio 中创建的任何 Android XML 资源文件都必须将构建操作 AndroidResource 和自定义工具字段设置为 MSBuild:UpdateGeneratedFiles(设置在文件的属性窗口中)

    2. 除了#5,Toolbar.xml文件必须在MainActivity.cs中引用:

    protected override void OnCreate(Bundle bundle)
    {
        ToolbarResource = Resource.Layout.Toolbar;
        base.OnCreate(bundle);
        ...
    }
    
    1. 确保您在Toolbar.xml 中使用android:theme 标签,而不是android:popupTheme。不明白为什么,但popupTheme 对我不起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-22
      • 1970-01-01
      • 2019-03-08
      相关资源
      最近更新 更多