Xamarin Forms 自定义控件和可绑定属性无法按预期工作

乔福尔

我制作了一个名为 ImageButton 的自定义控件,它允许我为 Up、Down 和 Inactive 状态设置不同的图像。它还可以在“正常”模式或“锁定”模式下运行。

除了一小部分之外,它工作正常……我在 XAML 中设置的值不会立即应用。它只使用默认值。

这是 ImageButton.cs

public class ImageButton : Image
{
    public enum State
    {
        Inactive,
        Up,
        Down
    };

    public static readonly BindableProperty CommandProperty =
        BindableProperty.Create("Command", typeof(ICommand), typeof(ImageButton), null);

    public static readonly BindableProperty SourceUpProperty =
        BindableProperty.Create("SourceUp", typeof(string), typeof(ImageButton), null);

    public static readonly BindableProperty SourceDownProperty =
        BindableProperty.Create("SourceDown", typeof(string), typeof(ImageButton), null);

    public static readonly BindableProperty SourceInactiveProperty =
        BindableProperty.Create("SourceInactive", typeof(string), typeof(ImageButton), null);

    public static readonly BindableProperty ToggleProperty =
        BindableProperty.Create("Toggle", typeof(bool), typeof(ImageButton), false);

    public static readonly BindableProperty ToggleStateProperty =
        BindableProperty.Create("ToggleState", typeof(State), typeof(ImageButton), State.Up, BindingMode.TwoWay);

    public ImageButton()
    {
        Initialize();
    }

    public void Initialize()
    {
        switch (ToggleState) // <- this is returning "State.Up" (the default) no matter what is set in the xaml.
        {
            case State.Up:
                Source = SourceUp; 
                break;
            case State.Down:
                Source = SourceDown;
                break;
            case State.Inactive:
                Source = SourceInactive;
                break;
            default:
                Source = SourceUp;
                break;
        }
        GestureRecognizers.Add(new TapGestureRecognizer
        {
            Command = TransitionCommand
        });
    }

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    private ICommand TransitionCommand
    {
        get
        {
            return new Command(async () =>
            {
                if (ToggleState != State.Inactive)
                {
                    AnchorX = 0.48;
                    AnchorY = 0.48;
                    await this.ScaleTo(0.8, 50, Easing.Linear);
                    if (Toggle)
                    {
                        if (ToggleState == State.Down)
                            ToggleState = State.Up;
                        else
                            ToggleState = State.Down;
                    }
                    await this.ScaleTo(1, 50, Easing.Linear);
                    if (Command != null)
                    {
                        Command.Execute(null);
                    }
                }
            });
        }
    }

    public string SourceUp
    {
        get { return (string)GetValue(SourceUpProperty); }
        set { SetValue(SourceUpProperty, value); }
    }

    public string SourceDown
    {
        get { return (string)GetValue(SourceDownProperty); }
        set { SetValue(SourceDownProperty, value); }
    }

    public string SourceInactive
    {
        get { return (string)GetValue(SourceInactiveProperty); }
        set { SetValue(SourceInactiveProperty, value); }
    }

    public bool Toggle
    {
        get { return (bool)GetValue(ToggleProperty); }
        set { SetValue(ToggleProperty, value); }
    }

    public State ToggleState
    {
        get { return (State)GetValue(ToggleStateProperty); }
        set
        {
            SetValue(ToggleStateProperty, value);
            switch (value)
            {
                case State.Up:
                    Source = SourceUp;
                    break;
                case State.Down:
                    Source = SourceDown;
                    break;
                case State.Inactive:
                    Source = SourceInactive;
                    break;
                default:
                    Source = SourceUp;
                    break;
            }
        }
    }
}

如果我使用“源”进行设置,则该按钮有效,如下所示:

<custom:ImageButton 
    Source="i_left.png"
    SourceUp="i_left.png"
    SourceDown="i_right.png"
    SourceInactive="i_close.png"
    Toggle="True"
    ToggleState="Up"
    WidthRequest="{StaticResource IconMedium}"
    HeightRequest="{StaticResource IconMedium}"
    Command="{Binding ImageButton1Command}"/>

我不需要指定“Source”,因为在构造函数中我根据初始状态设置了它。
但似乎“ToggleState”尚未设置为我的 xaml 值。

我正在尝试像这样设置它

<custom:ImageButton 
    SourceUp="i_left.png"
    SourceDown="i_right.png"
    SourceInactive="i_close.png"
    Toggle="True"
    ToggleState="Down"
    WidthRequest="{StaticResource IconMedium}"
    HeightRequest="{StaticResource IconMedium}"
    Command="{Binding ImageButton1Command}"/>

加载时它应该在“i_right.png”图像上,但它不是。

按答案编辑:以下课程按预期工作!

public class ImageButton : Image
{
    public enum State
    {
        Inactive,
        Up,
        Down
    };

    public static readonly BindableProperty CommandProperty =
        BindableProperty.Create("Command", typeof(ICommand), typeof(ImageButton), null, propertyChanged: OnStateChanged);

    public static readonly BindableProperty SourceUpProperty =
        BindableProperty.Create("SourceUp", typeof(ImageSource), typeof(ImageButton), null, propertyChanged: OnStateChanged);

    public static readonly BindableProperty SourceDownProperty =
        BindableProperty.Create("SourceDown", typeof(ImageSource), typeof(ImageButton), null, propertyChanged: OnStateChanged);

    public static readonly BindableProperty SourceInactiveProperty =
        BindableProperty.Create("SourceInactive", typeof(ImageSource), typeof(ImageButton), null, propertyChanged: OnStateChanged);

    public static readonly BindableProperty ToggleProperty =
        BindableProperty.Create("Toggle", typeof(bool), typeof(ImageButton), false);

    public static readonly BindableProperty ToggleStateProperty =
        BindableProperty.Create("ToggleState", typeof(State), typeof(ImageButton), State.Up, BindingMode.TwoWay, propertyChanged: OnStateChanged);

    public ImageButton()
    {
        Initialize();
    }

    public void Initialize()
    {
        GestureRecognizers.Add(new TapGestureRecognizer
        {
            Command = TransitionCommand
        });
    }

    static void OnStateChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var imageButton = bindable as ImageButton;
        imageButton.SetState();
    }

    public void SetState()
    {
        switch (ToggleState)
        {
            case State.Up:
                Source = SourceUp;
                break;
            case State.Down:
                Source = SourceDown;
                break;
            case State.Inactive:
                Source = SourceInactive;
                break;
            default:
                Source = SourceUp;
                break;
        }
    }

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    private ICommand TransitionCommand
    {
        get
        {
            return new Command(async () =>
            {
                if (ToggleState != State.Inactive)
                {
                    AnchorX = 0.48;
                    AnchorY = 0.48;
                    await this.ScaleTo(0.8, 50, Easing.Linear);
                    if (Toggle)
                    {
                        if (ToggleState == State.Down)
                            ToggleState = State.Up;
                        else
                            ToggleState = State.Down;
                    }
                    await this.ScaleTo(1, 50, Easing.Linear);
                    if (Command != null)
                    {
                        Command.Execute(null);
                    }
                }
            });
        }
    }

    public ImageSource SourceUp
    {
        get { return (ImageSource)GetValue(SourceUpProperty); }
        set { SetValue(SourceUpProperty, value); }
    }

    public ImageSource SourceDown
    {
        get { return (ImageSource)GetValue(SourceDownProperty); }
        set { SetValue(SourceDownProperty, value); }
    }

    public ImageSource SourceInactive
    {
        get { return (ImageSource)GetValue(SourceInactiveProperty); }
        set { SetValue(SourceInactiveProperty, value); }
    }

    public bool Toggle
    {
        get { return (bool)GetValue(ToggleProperty); }
        set { SetValue(ToggleProperty, value); }
    }

    public State ToggleState
    {
        get { return (State)GetValue(ToggleStateProperty); }
        set { SetValue(ToggleStateProperty, value); }
    }
}
沙拉达·古拉吉

在调用构造函数时 - 尚未设置来自 XAML 的可绑定属性。因此,您将获得默认值。要检测属性的更新并正确设置控件的状态 - 您可以使用属性更改的回调方法

我的建议是对每个可绑定属性使用属性更改回调,其值可能会影响控件的当前状态(因为您永远无法确定加载期间从 XAML 设置属性值的顺序/顺序)。

例如:

 public static readonly BindableProperty ToggleStateProperty =
    BindableProperty.Create("ToggleState", typeof(State), typeof(ImageButton), State.Up, BindingMode.TwoWay, propertyChanged: OnToggleStateChanged);


 static void OnToggleStateChanged (BindableObject bindable, object oldValue, object newValue)
 {
      // Property changed implementation goes here
      Initialize();
 }

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何将对象作为可绑定属性传递给Xamarin.Forms自定义控件

Xamarin Forms自定义控件数据绑定问题

自定义控件中的Xamarin.Forms绑定集合

自定义控件的Xamarin数据绑定值评估为Xamarin.Forms.Binding

具有可绑定属性的自定义视图在Xamarin.Forms SAP上未正确绑定

Xamarin Forms中的自定义控件不起作用

[Xamarin.Forms] ListView中的自定义控件

Xamarin.Forms 绑定不适用于嵌套的自定义控件

ReactiveUI中的Xamarin.Forms控件是否需要自定义绑定?

在Xamarin.Forms中绑定自定义视图

在 Xamarin Forms 中绑定自定义条目

Xamarin.Forms:颜色资源不适用于自定义控件的颜色属性

如何在Xamarin.Forms中为自定义组件创建可绑定命令?

自定义Xamarin.Forms布局

Xamarin Forms自定义步进器

Xamarin Forms 绑定到没有硬编码属性名称的自定义单元格

无法创建Xamarin Forms Picker自定义rendere

xamarin.forms中我的自定义控件的HeightRequest的自定义BindableProperty

分段控件Xamarin Forms定制

Xamarin Forms在解码自定义属性:(null)时无法加载类型Plugin.SharedTransitions.SharedTransitionShell

Xamarin Forms ListView数据绑定

Xamarin Forms 无法解析 DateTime

Xamarin.Forms无法更新

Xamarin Forms Settings插件可绑定

Xamarin Forms - 从自定义渲染器检查控件是否具有从 XAML 设置的属性

xamarin.forms从xaml绑定到属性

Xamarin.Forms,XAML,绑定和isVisible

如何使 xamarin 自定义控件中的 2 个可绑定属性相互识别?

无法使IOC在Xamarin Forms中工作