Xamarin.forms Xamarin表单自定义控件和可绑定属性未按预期工作
我制作了一个名为ImageButton的自定义控件,它允许我为向上、向下和非活动状态设置不同的图像。 它也可以在“正常”模式或“锁定”模式下运行 除了一小块外,它工作得很好。。。我在XAML中设置的值不会立即应用。它只使用默认值 这是ImageButton.csXamarin.forms Xamarin表单自定义控件和可绑定属性未按预期工作,xamarin.forms,custom-controls,Xamarin.forms,Custom Controls,我制作了一个名为ImageButton的自定义控件,它允许我为向上、向下和非活动状态设置不同的图像。 它也可以在“正常”模式或“锁定”模式下运行 除了一小块外,它工作得很好。。。我在XAML中设置的值不会立即应用。它只使用默认值 这是ImageButton.cs public class ImageButton : Image { public enum State { Inactive, Up, Down };
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;
}
}
}
}
在调用构造函数时,XAML中的可绑定属性尚未设置。因此,您将获得默认值。要检测属性的更新,并正确设置控件的状态,可以使用 我的建议是对每个可绑定属性使用property changed回调,其值可能会影响控件的当前状态(因为您永远不能太确定在加载期间从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();
}
在调用构造函数时,XAML中的可绑定属性尚未设置。因此,您将获得默认值。要检测属性的更新,并正确设置控件的状态,可以使用 我的建议是对每个可绑定属性使用property changed回调,其值可能会影响控件的当前状态(因为您永远不能太确定在加载期间从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();
}
非常感谢。我简单地尝试了一下,并注意到,正如您所说,XAML设置的属性值的顺序/顺序是一个问题。我会重新考虑一下逻辑,看看是否能把它理顺。它运行得非常好!非常感谢。我现在还有另一个控件要修复。。再次感谢!非常感谢。我简单地尝试了一下,并注意到,正如您所说,XAML设置的属性值的顺序/顺序是一个问题。我会重新考虑一下逻辑,看看是否能把它理顺。它运行得非常好!非常感谢。我现在还有另一个控件要修复。。再次感谢!
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); }
}
}
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();
}