使用CustomRenderer时如何保持BaseView的双向可绑定属性和事件:ViewRenderer <a,b =“”> </a,>

时间:2014-08-18 17:25:54

标签: xamarin.forms

首先,我想在X.F中使用名为JVFloatLabeledEntry的自定义UITextField。以下是对此自定义UITextField https://github.com/gshackles/JVFloatSharp

的引用

所以这是我的步骤:

XF方面: 1. JVFloatLabeledEntry.cs

public class JVFloatLabeledEntry : Entry
    {
        public Color FloatingLabelColor { get; private set;}
        public Color FloatingLabelActiveColor { get; private set;}

        public JVFloatLabeledEntry () : base()
        {
            WidthRequest = 300;
            HeightRequest = 44;
            FloatingLabelColor = Color.Gray;
            FloatingLabelActiveColor = Color.Black;
        }           
    }

iOS方面: 2. JVFloatLabeledTextField.cs这是我想要使用的自定义UITextField。你可以在github https://github.com/gshackles/JVFloatSharp找到这个文件 3. JVFloatLabeledEntryRenderer.cs这是我的CustomRenderer,它创建一个全新的JVFloatLabeledTextField并将其设置为NativeControl

[assembly: ExportRenderer (typeof (JVFloatLabeledEntry), typeof (JVFloatLabeledEntryRenderer))]
namespace DutyFreeCollection.iOS
{
    public class JVFloatLabeledEntryRenderer : ViewRenderer<JVFloatLabeledEntry, JVFloatLabeledTextField>
    {
        public JVFloatLabeledEntryRenderer () {}

        protected override void OnElementChanged (ElementChangedEventArgs<JVFloatLabeledEntry> e)
        {
            base.OnElementChanged (e);

            var jfflEntry = e.NewElement;
            if (jfflEntry != null) {
                const float JVFieldHMargin = 10.0f;
                const float JVFieldFontSize = 16.0f;
                const float JVFieldFloatingLabelFontSize = 11.0f;
                // Now whenever I use JVFloatLabeledEntry on XF side, this newView is instead used
                var newView = new JVFloatLabeledTextField (
                    new RectangleF(JVFieldHMargin, 0, (float)jfflEntry.WidthRequest, (float)jfflEntry.HeightRequest))
                {
                    Text = jfflEntry.Text,
                    Placeholder = jfflEntry.Placeholder,
                    Font = UIFont.SystemFontOfSize (JVFieldFontSize),
                    ClearButtonMode = UITextFieldViewMode.WhileEditing,
                    FloatingLabelFont = UIFont.BoldSystemFontOfSize (JVFieldFloatingLabelFontSize),
                    FloatingLabelTextColor = jfflEntry.FloatingLabelColor.ToUIColor(),
                    FloatingLabelActiveTextColor = jfflEntry.FloatingLabelActiveColor.ToUIColor(),
                    BorderStyle = UITextBorderStyle.RoundedRect
                };

                SetNativeControl (newView);
            }
        }
    }
}

我的问题是在将新的JVFloatLabeledTextField设置为本机控件之后,所有成员(如事件TextChanged)和XF端的Entry的TextProperty之类的属性都消失了。即。

JVFloatLabeledEntry floatLabeledEntry = new JVFloatLabeledEntry();
floatLabeledEntry.TextChanged += (object sender, TextChangedEventArgs e) => {
// Never comes here, event TextChanged of JVFloatLabeledEntry is gone, but why? Since JVFloatLabeledEntry derived from Entry, why is the event TextChanged gone?
};

此自定义条目的所有其他成员也会发生同样的事情,例如

floatLabeledEntry.SetBinding(JVFloatLabeledEntry.TextProperty, "ANY_BINDING_FIELD"); // The two-way binding is gone as well.

我真的到了瓶颈,有人可以告诉我如何保留JVFloatLabeledEntry(CustomEntry)的基类Entry属性绑定和EventHandlers。非常感谢你。

2 个答案:

答案 0 :(得分:1)

如果我正确理解了这个问题,那么问题在于你初始化iOS本机控件的方式 - 没有你在本机上听的事件(包括缺少绑定),你正在初始化本能控制以一种发射后的方式。

您需要添加代码才能将本机事件转换为表单事件。我对您正在使用的自定义控件不够熟悉,但在启动控件后,在渲染器中,您需要挂钩其事件,这就是:

newView.TextChangedEvent+=(s,e) => jfflEntry.OnTextChanged(jffl, new TextChangedEventArgs(e.NewText);

上面的代码已经完成,但它应该让你知道该怎么做,如果不是 - 只要问一下“不清楚”

答案 1 :(得分:0)

这是我的解决方案:

[assembly: ExportRenderer (typeof (JVFloatLabeledEntry), typeof (JVFloatLabeledEntryRenderer))]
namespace DutyFreeCollection.iOS
{
    public class JVFloatLabeledEntryRenderer : ViewRenderer<JVFloatLabeledEntry, JVFloatLabeledTextField>
    {
        private UIColor defaultTextColor;

        public JVFloatLabeledEntryRenderer () {}

        protected override void OnElementChanged (ElementChangedEventArgs<JVFloatLabeledEntry> e)
        {
            base.OnElementChanged (e);

            var jfflEntry = e.NewElement;
            if (jfflEntry != null) {
                const float JVFieldHMargin = 10.0f;
                const float JVFieldFontSize = 16.0f;
                const float JVFieldFloatingLabelFontSize = 11.0f;

                var newView = new JVFloatLabeledTextField (
                    new RectangleF(JVFieldHMargin, 0, (float)jfflEntry.WidthRequest, (float)jfflEntry.HeightRequest))
                {
                    Text = jfflEntry.Text,
                    Placeholder = jfflEntry.Placeholder,
                    Font = UIFont.SystemFontOfSize (JVFieldFontSize),
                    ClearButtonMode = UITextFieldViewMode.WhileEditing,
                    FloatingLabelFont = UIFont.BoldSystemFontOfSize (JVFieldFloatingLabelFontSize),
                    FloatingLabelTextColor = jfflEntry.FloatingLabelColor.ToUIColor(),
                    FloatingLabelActiveTextColor = jfflEntry.FloatingLabelActiveColor.ToUIColor(),
                    BorderStyle = UITextBorderStyle.RoundedRect
                };                      

                SetNativeControl (newView);


                this.UpdatePlaceholder ();
                this.UpdatePassword ();
                this.UpdateText ();
                this.UpdateColor ();
                this.UpdateKeyboard ();

                newView.EditingChanged += delegate (object sender, EventArgs a) {
                    jfflEntry.Text = newView.Text;
                };
                newView.ShouldReturn = new UITextFieldCondition (this.OnShouldReturn);
//              newView.EditingDidBegin += delegate (object sender, EventArgs args) {
//                  jfflEntry.IsFocused = true;
//              };
//              newView.EditingDidEnd += delegate (object sender, EventArgs args) {
//                  jfflEntry.IsFocused = false;
//              };
                this.defaultTextColor = newView.TextColor;
                MessagingCenter.Subscribe<IVisualElementRenderer> (this, "Xamarin.ResignFirstResponder", delegate (IVisualElementRenderer sender) {
                    if (newView.IsFirstResponder) {
                        newView.ResignFirstResponder ();
                    }
                }, null);
            }
        }

        protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
        {
            Entry arg_06_0 = base.Element;
            if (e.PropertyName == Entry.PlaceholderProperty.PropertyName) {
                this.UpdatePlaceholder ();
            }
            else {
                if (e.PropertyName == Entry.IsPasswordProperty.PropertyName) {
                    this.UpdatePassword ();
                }
                else {
                    if (e.PropertyName == Entry.TextProperty.PropertyName) {
                        this.UpdateText ();
                    }
                    else {
                        if (e.PropertyName == Entry.TextColorProperty.PropertyName) {
                            this.UpdateColor ();
                        }
                        else {
                            if (e.PropertyName == Xamarin.Forms.InputView.KeyboardProperty.PropertyName) {
                                this.UpdateKeyboard ();
                            }
                        }
                    }
                }
            }
            base.OnElementPropertyChanged (sender, e);
        }

        private bool OnShouldReturn (UITextField view)
        {
            base.Control.ResignFirstResponder ();
//          base.Element.SendCompleted ();
            return true;
        }

        private void UpdateColor ()
        {
            if (base.Element.TextColor == Color.Default) {
                base.Control.TextColor = this.defaultTextColor;
                return;
            }
            base.Control.TextColor = base.Element.TextColor.ToUIColor ();
        }

        private void UpdateKeyboard ()
        {
            base.Control.ApplyKeyboard (base.Element.Keyboard);
        }

        private void UpdatePassword ()
        {
            if (base.Element.IsPassword && base.Control.IsFirstResponder) {
                base.Control.Enabled = false;
                base.Control.SecureTextEntry = true;
                base.Control.Enabled = base.Element.IsEnabled;
                base.Control.BecomeFirstResponder ();
                return;
            }
            base.Control.SecureTextEntry = base.Element.IsPassword;
        }

        private void UpdatePlaceholder ()
        {
            base.Control.Placeholder = base.Element.Placeholder;
        }

        private void UpdateText ()
        {
            if (base.Control.Text != base.Element.Text) {
                base.Control.Text = base.Element.Text;
            }
        }
    }
}

但是我无法设置jfflEntry.IsFocused,因为IsFocused是VisualElement中的内部属性,任何人都知道如何访问或设置Entry的IsFocused属性? 对于base.Element.SendCompleted();

也是如此