【问题标题】:ContentView -> Custom Frame Binding Not WorkingContentView -> 自定义框架绑定不起作用
【发布时间】:2020-04-03 18:04:21
【问题描述】:

我复制/编写了一个继承自 Frame

的类
public class Circle : Frame
{
    //private double _radius;

    public static readonly BindableProperty RadiusProperty = BindableProperty.Create(nameof(Radius), typeof(double), typeof(Circle), 126.0, BindingMode.TwoWay);
    public double Radius
    {
        get => (double)GetValue(RadiusProperty); //_radius;
        set
        {
            SetValue(RadiusProperty, value);
            OnPropertyChanged();
            AdjustSize();
        }
    }

    private void AdjustSize()
    {
        HeightRequest = Radius;
        WidthRequest = Radius;
        Margin = new Thickness(0,0,0,0);
        Padding = new Thickness(0, 0, 0, 0);
        CornerRadius = (float) (Radius / 2);
    }

    public Circle()
    {
        HorizontalOptions = LayoutOptions.Center;
    }
}

消费页面定义了这些 BinadableProperties

    public static readonly BindableProperty InnerColorProperty = BindableProperty.Create("InnerColor", typeof(Color), typeof(CircleProgressView), defaultValue: Color.FromHex("#34495E"), BindingMode.TwoWay);
    public Color InnerColor
    {
        get => (Color)GetValue(InnerColorProperty);
        set => SetValue(InnerColorProperty, value);
    }

    public static readonly BindableProperty InnerRadiusProperty = BindableProperty.Create("InnerRadius", typeof(double), typeof(CircleProgressView), 126.0, BindingMode.TwoWay);
    public double InnerRadius
    {
        get => (double)GetValue(InnerRadiusProperty);
        set => SetValue(InnerRadiusProperty, value);
    }

并且像这样使用Circle

<components:Circle Grid.Row="0" BackgroundColor="{Binding InnerColor}" Radius="{Binding InnerRadius}" >

唉,可绑定的 setter 以及因此的 AdjustSize() 永远不会被调用,也不会使用默认值。我最终得到了一个矩形,而不是一个圆圈。 BackgroundColorFrame 的一个属性,可以绑定并正常工作。

如果我删除 BindableProperty 并留下常规的 INotify 属性

public class Circle : Frame
{
    private double _radius;

    public double Radius
    {
        get => _radius;
        set
        {
            _radius = value;
            OnPropertyChanged();
            AdjustSize();
        }
    }

    private void AdjustSize()
    {
        HeightRequest = Radius;
        WidthRequest = Radius;
        Margin = new Thickness(0,0,0,0);
        Padding = new Thickness(0, 0, 0, 0);
        CornerRadius = (float) (Radius / 2);
    }

    public Circle()
    {
        HorizontalOptions = LayoutOptions.Center;
    }
}

如果我保留 InnerRadius 绑定,编译器会报错

严重性代码描述项目文件行抑制状态 错误位置 17:92。未找到“半径”的属性、可绑定属性或事件,或者值和属性之间的类型不匹配。 ...\Components\CircleProgressView.xaml 17

我可以用硬编码值替换 Radius 绑定,它运行良好,出现一个圆圈。

<components:Circle Grid.Row="0" BackgroundColor="{Binding InnerColor}" Radius="126" >

常规 C# 类中的 BindableProperty 有什么问题?

【问题讨论】:

  • 处理您要使用的属性更改property-changed callbacks
  • 还建议您避免使用双向绑定模式(您不希望半径成为输入)

标签: xamarin.forms bindableproperty


【解决方案1】:

首先,我们需要在可绑定属性的属性改变事件中处理数据,而不是普通属性的setter方法。所以修改你的 Circle 类:

public static readonly BindableProperty RadiusProperty = BindableProperty.Create(nameof(Radius), typeof(double), typeof(Circle), 125.0, BindingMode.TwoWay, propertyChanged: RadiusChanged);
public double Radius
{
    get => (double)GetValue(RadiusProperty); //_radius;
    set => SetValue(RadiusProperty, value);
}
static void RadiusChanged(BindableObject bindableObject, object oldValue, object newValue)
{
    Circle circle = bindableObject as Circle;
    circle.HeightRequest = (double)newValue;
    circle.WidthRequest = (double)newValue;
    circle.CornerRadius = (float)((double)newValue / 2);
}

这是因为我们在 XAML 中绑定数据,我们应该直接操作可绑定属性的更改事件。

其次,我看到您使用父页面的可绑定属性绑定了该属性。通常情况下,我们不会这样做。我们将使用视图模型作为页面的绑定上下文,然后将属性绑定到绑定上下文。但是,如果您确实想将父页面的可绑定属性用作 Circle 的绑定上下文,请尝试以下方式:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Sample.SecondPage"
             xmlns:components="clr-namespace:Sample"
             x:Name="Page">
    <ContentPage.Content>
        <StackLayout>
            <components:Circle BackgroundColor="{Binding InnerColor, Source={x:Reference Page}}" Radius="{Binding InnerRadius, Source={x:Reference Page}}"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

首先为您的父页面命名,然后将圈子的来源更改为该名称。

在这里,与InnerRadius 相比,我使用了不同的默认Radius 值,因此将在初始时间调用属性更改事件。

【讨论】:

  • 谢谢,成功了。我将标记为答案,但我要求澄清。您说“其次,我看到您使用父页面的可绑定属性绑定属性。通常情况下,我们不会这样做。”这对可重用的 XAML 组件有什么作用?
  • @JohnMc 我们可以使用一个单独的类来定义一个可重用的自定义控件。但我们通常使用绑定上下文来填充数据,而不是父视图的可绑定属性。
  • 我喜欢,但这里不适合。
  • 嗨@JohnMc 如果它解决了您的问题,您能否将其标记为答案?
猜你喜欢
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-16
  • 2016-12-29
  • 2017-06-13
相关资源
最近更新 更多