Xamarin表单触发器不工作自定义渲染器

时间:2016-11-30 08:16:34

标签: xamarin.forms custom-renderer

我有extendedentry和自定义渲染器类

public class ExtendedEntryRenderer : EntryRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);

        if (Control != null)
        {
            Control.Click += (sender, evt) =>
            {
                var nativeEditText = (global::Android.Widget.EditText)Control;
                nativeEditText.SetSelectAllOnFocus(true);

                new Handler().PostDelayed(delegate
                {
                     Control.InputType = 0;
                     try
                     {
                         InputMethodManager inputMethodManager = Control.Context.GetSystemService(Android.Content.Context.InputMethodService) as InputMethodManager;
                         if (inputMethodManager != null)
                         {
                             inputMethodManager.HideSoftInputFromWindow(Control.WindowToken, HideSoftInputFlags.None);
                         }
                     }
                     catch (Exception Ex)
                     {

                     }
                 }, 300L);
            };


            // Hide soft input keyboard
            Control.FocusChange += (sender, evt) =>
            {
                // Select all on entry focus
                var nativeEditText = (global::Android.Widget.EditText)Control;

                nativeEditText.SetSelectAllOnFocus(true);

                new Handler().PostDelayed(delegate
                 {
                     Control.InputType = 0;
                     try
                     {
                         InputMethodManager inputMethodManager = Control.Context.GetSystemService(Android.Content.Context.InputMethodService) as InputMethodManager;
                         if (inputMethodManager != null)
                         {
                            inputMethodManager.HideSoftInputFromWindow(Control.WindowToken, HideSoftInputFlags.None);
                         }
                     }
                     catch (Exception Ex)
                     {

                     }
                 }, 300L);
            };
        }
    }
}

我的自定义条目:

public class ExtendedEntry : Entry
{

}

我的XAML文件是这样的:

<local:ExtendedEntry x:Name="BarcodeEntry" Text="{Binding Barcode}" Margin="0,0,0,0" HorizontalOptions="FillAndExpand" VerticalOptions="Start">
    <Entry.Triggers>
        <Trigger TargetType="Entry" Property="IsFocused" Value="True">
            <Setter Property="BackgroundColor" Value="Yellow" />
            <Setter Property="TextColor" Value="Black" />
        </Trigger>
    </Entry.Triggers>       
</local:ExtendedEntry>

Trigger无法正常工作。

但是当我改为默认输入控件时:

<Entry x:Name="BarcodeEntry" Text="{Binding Barcode}" Margin="0,0,0,0"HorizontalOptions="FillAndExpand" VerticalOptions="Start">
    <Entry.Triggers>
        <Trigger TargetType="Entry" Property="IsFocused" Value="True">
            <Setter Property="BackgroundColor" Value="Yellow" />
            <Setter Property="TextColor" Value="Black" />
        </Trigger>
    </Entry.Triggers>       
</Entry>

Trigger有效。

我错了什么?

修改

Xamarin.Forms的ExportRenderer行在我的渲染器类中。

[assembly: ExportRenderer(typeof(ExtendedEntry), typeof(ExtendedEntryRenderer))]

2 个答案:

答案 0 :(得分:0)

  1. 您不必在每个活动下面做。你只能做一次

    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);
    
        if (e.NewElement != null)
        {
            var nativeEditText = (global::Android.Widget.EditText)Control;
            // Select all on entry focus
            nativeEditText.SetSelectAllOnFocus(true);
    
  2. 您在Control.Click和Control.FocusChange中拥有相同的代码。您可能想以某种方式考虑将其分离功能。 请记住,焦点丢失时也会调用FocusChange,因此您可能需要检查

    if (evt.HasFocus)
    
  3. 创建Control时,其OnFocusChangeListener设置为ExtendedEntryRenderer。但是一旦你调用Control.FocusChange + =它就会改为mono.android.view.View_OnFocusChangeListenerImplementor@a25f36e,显然会导致问题。

  4. Commment out Control.FocusChange,它会工作。当用户将焦点设置到您的Entry时,您将获得足够的Click事件。如果需要,你不会知道何时失去焦点。

答案 1 :(得分:0)

不幸的是,Xamarin中的Entry / EntryRenderer系统存在很大问题,这使得添加效果变得异常困难。更糟糕的是,我创建了一个自定义渲染器,该渲染器工作正常,但有时会由于将基本条目控件添加到布局而导致冻结。如果在条目中添加两个不同的效果,我仍然会冻结,但是我能够触发焦点并成功使用单个效果。

为避免丢失原始的焦点处理程序,我用以下方法进行了抓取:

private Android.Views.View.IOnFocusChangeListener focusListener = null;

private void ConfigureControl()
{
  EditText editText;

  editText = ((EditText)Control);
  this.focusListener = Control.OnFocusChangeListener;
  editText.FocusChange += EditText_FocusChange;

...

private void EditText_FocusChange(object sender, Android.Views.View.FocusChangeEventArgs e)
{
  EditText editText;

  editText = (EditText) sender;
  ...
  if (this.focusListener != null)
  {
    this.focusListener.OnFocusChange(editText,
      e.HasFocus);
  }

这可以使效果起作用,也可以将焦点事件触发回xamarin形式。不幸的是,在两种不同的效果下执行此操作无法正常工作-可能是因为mono.android.view.View_OnFocusChangeListenerImplementor@a25f36e处理程序无法转换为Android.Views.View.IOnFocusChangeListener或可以转换为,但确实存在一些内部错误无休止的循环。

我正在使用一种效果添加一个“ x”来清除android条目,并且我试图也使用自己创建的一种效果来选择所有焦点。两者都是显而易见的候选者,因为过于频繁地需要基本选项来证明将其留给效果器或自定义渲染器,因此它们都可以包含在Xamarin中。如果您要实现相同的目标,则可以执行我的操作-添加效果以添加'x',然后代替效果进行非常简单的全选,您可以用不太漂亮但可以实现的效果来实现回到xamarin视图中的功能代码:

  entry.Focused += (s, a) =>
  {
    Device.StartTimer(TimeSpan.FromMilliseconds(1),
      () =>
      {
        entry.CursorPosition = 0;
        entry.SelectionLength = (entry.Text ?? string.Empty).Length;
        return false;
      });
    ...
  };
  entry.Unfocused += (s, a) =>
  {
    ...
  };

我希望可以节省一些人的自定义渲染器开发时间和无休止的效果实验,直到我最终获得了如此令人沮丧的基本知识才能可靠地工作。