2017-05-08 8 views
1

ImageButtonというカスタムコントロールを作成しました。これにより、Up、Down、およびInactiveステートの異なるイメージを設定できます。 「通常」モードまたは「ラッチ」モードでも動作できます。XamarinフォームカスタムコントロールとBindableプロパティが期待どおりに動作しない

小さな小片以外は正常に動作します.XAMLで設定した値はすぐに適用されません。デフォルト値のみを使用します。

<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}"/> 

私は「ソース」を指定する必要はありません。ここで

ボタンは、私はそうのような「ソース」でそれを設定した場合に動作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; 
      } 
     } 
    } 
} 

ですなぜならコンストラクタでは私は初期状態に合わせて設定しているからです。
しかし、 "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); } 
    } 
} 

答えて

0

コンストラクタが呼び出された時点で、XAMLのバインド可能なプロパティはまだ設定されていません。したがって、デフォルト値が得られます。プロパティの更新を検出し、コントロールの状態を正しく設定するには、property-changed callback methodsを使用できます。

私は、バインド可能なすべてのプロパティに対して、コントロールの現在の状態に影響を与える可能性のあるプロパティ変更コールバックを使用することをお勧めします(順序/順序が決してわからないため、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(); 
} 
+0

ありがとうございました。私は簡単にそれを試み、あなたが言ったように、XAMLによって設定されるプロパティ値の順序/順序が問題であることに気づいた。私は論理を再考し、私がそれを並べ替えることができるかどうかを見ます。 –

+0

すごくうまくいった!ありがとうございました。私は今もまた修正する別のコントロールを持っています..もう一度ありがとう! –

関連する問題