【问题标题】:Why I can't bind the background color in different platform?为什么我不能在不同的平台上绑定背景颜色?
【发布时间】:2020-09-19 18:33:28
【问题描述】:

这里是 XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="App1.MainPage">

    <BoxView>
        <BoxView.BackgroundColor>
            <OnPlatform x:TypeArguments="Color">
                <On Platform="Android" Value="{Binding First}"></On>
                <On Platform="iOS" Value="{Binding Second}"></On>
            </OnPlatform>
        </BoxView.BackgroundColor>
    </BoxView>
</ContentPage>

这里是代码隐藏:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace App1
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(false)]
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            this.BindingContext = this;
        }
        public Color First {
            get {
                return Color.FromHex("#575757");
            }
        }
        public Color Second
        {
            get
            {
                return Color.FromHex("#ffffff");
            }
        }
    }
}

我运行程序后,报错: 指定的演员表无效。

它有什么问题?

【问题讨论】:

  • @MihailDuchev 不,不一样。如果我从 Color.FromHex("#575757"); 修改代码返回 Color.Red; .它运行成功,没有任何错误。
  • 我刚刚尝试将 Second 更改为返回 Color.Green,但它会因同样的错误而崩溃。
  • 好吧,这是我的错。我只是按照你说的做了,结果证明是真的崩溃了。顺便说一句,在您上面提供的文章中,这是一个已在 2017.01.24 修复的错误。为什么我又遇到了,竟然用最新版的Xamarin.Forms? @MihailDuchev
  • 是的,我的错,我很快就读完了。我会看看这个。

标签: xamarin xamarin.forms


【解决方案1】:

我不得不深入研究文档才能找到它。 OnPlatform 不能为 Color 属性获取可绑定值。

来自OnPlatform markup extension docs:

XAML 解析器期望将正确类型的值提供给使用 OnPlatform 标记扩展的属性。如果需要类型转换,OnPlatform 标记扩展将尝试使用 Xamarin.Forms 提供的默认转换器执行它。但是,默认转换器无法执行某些类型转换,在这些情况下,应将 Converter 属性设置为 IValueConverter 实现。

当您打开标签&lt;BoxView.BackgroundColor&gt; 时,xaml 分析器将期望Color 类型的值,就像您在下一行中定义的那样。之后,您将传递一个扩展 BindingBase 类的值并返回此类型的值。解析器期望开箱即用的可绑定值和 Color 对象存在强制转换冲突。

幕后发生的事情是(看看 cmets):

<BoxView>
    <BoxView.BackgroundColor> <!-- You are saying that we want to modify a property of type Color -->
        <OnPlatform x:TypeArguments="Color"> <!-- Here the analyzer expects type Color, nothing else will work | checked build time -->
            <On Platform="Android" Value="{Binding First}"></On> <!-- The parser expects type Color, but is receiving type BindingBase | checked run time -->
            <On Platform="iOS" Value="{Binding Second}"></On> <!-- The parser expects type Color, but is receiving type BindingBase | checked run time -->
        </OnPlatform>
     </BoxView.BackgroundColor>
</BoxView>

根据文档,您可以尝试在转换器中定义演员表,这不是最好的方法,因为您将在幕后隐藏这部分转换。另一种(更好的)方法是将BackgroundColor 绑定到一个属性并在那里定义逻辑,如下所示:

<BoxView BackgroundColor="{Binding BgColor}" />

在代码隐藏中:

public Color BgColor => Device.RuntimePlatform == Device.Android ? Color.FromHex("#575757") : Color.FromHex("#ffffff");

注意:最后一个代码假定您仅针对 2 个平台进行开发 - iOS 和 Android。如果您/计划开发到其他平台,您需要扩展RuntimePlatform检查。

【讨论】:

    【解决方案2】:

    您粘贴的 Xaml 假设 OnPlatform 对象是 Binding to string 的目标,然后 OnPlatform 根据平台返回正确的字符串。

    很遗憾,这不起作用,因为 OnPlatform 不是 BindableObject 并且不能成为 Binding 的目标。

    这个答案很好地解释了:https://stackoverflow.com/a/41829242/8187800

    有两种方法可以解决这个问题。

    1. 在 xaml 中硬编码颜色字符串。

      <BoxView>
        <BoxView.BackgroundColor>
          <OnPlatform x:TypeArguments="Color">
              <On Platform="Android" Value="#575757"></On>
              <On Platform="iOS" Value="#ffffff"></On>
          </OnPlatform>
         </BoxView.BackgroundColor>
      </BoxView>
      

      请参考https://forums.xamarin.com/discussion/33117/setting-platform-specific-background-color-in-xaml

    2. 将颜色更改为 BindingBase 。

         <OnPlatform x:TypeArguments="BindingBase">
              <On Platform="Android" Value="{Binding First}"></On>
              <On Platform="iOS" Value="{Binding Second}"></On>
          </OnPlatform>
      

      这样会有一个警告,但我们可以忽略它

    【讨论】:

    • 如您在第二种方法中所展示的那样,拥有它并不是一个好主意。 Rider 甚至将其标记为错误:Invalid type: expected type is Color, actual type is OnPlatform&lt;BindingBase&gt;
    • 我更喜欢第二种方式,但我担心它在运行程序时是否会导致一些崩溃。 @MihailDuchev 的方式更可靠。
    • 还有,微软会用第二种方式修复这个bug吗?看来你是微软的员工。请您将此错误报告给您的公司吗?谢谢。
    • @MelonNG Bug 仍然存在
    猜你喜欢
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-03
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    相关资源
    最近更新 更多