C# 如何在Xamarin表单的编辑器中实现占位符?

C# 如何在Xamarin表单的编辑器中实现占位符?,c#,xamarin,mvvm,xamarin.forms,C#,Xamarin,Mvvm,Xamarin.forms,我读到编辑器控件没有占位符,所以我一直在尝试解决方法,但没有成功。我知道条目控件有一个占位符,但我需要多行字段,因为我将使用它作为一个字段,用户可以在其中编写注释,而不仅仅是一行 这是我的方法: 我尝试将编辑器和标签放入网格控件中,标签位于编辑器的顶部。编辑器的InputTransparent标志设置为true。然后,根据编辑器是否有文本,我只需切换标签的IsVisible属性。但是,问题是我使用的是MVVM模式,因此我不知道如何控制ViewModel中的TextChanged事件。我也尝试过代

我读到编辑器控件没有占位符,所以我一直在尝试解决方法,但没有成功。我知道条目控件有一个占位符,但我需要多行字段,因为我将使用它作为一个字段,用户可以在其中编写注释,而不仅仅是一行

这是我的方法:

我尝试将编辑器和标签放入网格控件中,标签位于编辑器的顶部。编辑器的
InputTransparent
标志设置为
true
。然后,根据
编辑器是否有文本,我只需切换标签的
IsVisible
属性。但是,问题是我使用的是MVVM模式,因此我不知道如何控制
ViewModel
中的
TextChanged
事件。我也尝试过代码隐藏,但是找不到标签的名称

这是我的XAML代码-我只发布了相关代码:

<Grid Grid.Row="1">
  <Editor Text="{Binding UserComment, Mode=TwoWay}" TextChanged="EditorTextChanged"                                          HorizontalOptions="FillAndExpand"/>
  <Label x:Name="PlaceholderLabel" Text="Write a comment" InputTransparent="True"                                             HorizontalOptions="StartAndExpand"/>
  </Grid>

您要寻找的是自定义呈现程序,因为Xamarin.Forms只是本机元素的另一个级别,所以您可以使用自定义呈现程序“访问”本机元素:

您可以创建基本自定义编辑器:

using Xamarin.Forms;

namespace EditorWithPlaceholder
{
    public class PlaceholderEditor : Editor
    {
        public static BindableProperty PlaceholderProperty
            = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(PlaceholderEditor));

        public static BindableProperty PlaceholderColorProperty
            = BindableProperty.Create(nameof(PlaceholderColor), typeof(Color), typeof(PlaceholderEditor), Color.Gray);

        public string Placeholder
        {
            get { return (string) GetValue(PlaceholderProperty); }
            set { SetValue(PlaceholderProperty, value); }
        }

        public Color PlaceholderColor
        {
            get { return (Color) GetValue(PlaceholderColorProperty); }
            set { SetValue(PlaceholderColorProperty, value); }
        }
    }
}
以及每个平台上的渲染器:

安卓:

using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace EditorWithPlaceholder.Droid.Renderers
{
    public class PlacehoderEditorRenderer : EditorRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);

            if (Element == null)
                return;

            var element = (PlaceholderEditor) Element;

            Control.Hint = element.Placeholder;
            Control.SetHintTextColor(element.PlaceholderColor.ToAndroid());
        }
    }
}
使用Xamarin.Forms;
使用Xamarin.Forms.Platform.Android;
[程序集:导出渲染器(类型化(占位符编辑器)、类型化(占位符编辑器或渲染器))]
命名空间编辑器WithPlaceholder.Droid.Renderers
{
公共类PlacehoderEditorRenderer:EditorRenderer
{
受保护的覆盖无效OnElementChanged(ElementChangedEventArgs e)
{
基础。一个要素发生变化(e);
if(元素==null)
返回;
var元素=(占位符编辑器)元素;
Control.Hint=element.Placeholder;
Control.SetHintTextColor(element.placeholder.ToAndroid());
}
}
}
iOS:

使用系统;
使用cirrium.FluentLayouts.Touch;
使用基础;
使用UIKit;
使用Xamarin.Forms;
使用Xamarin.Forms.Platform.iOS;
[程序集:导出渲染器(类型化(占位符编辑器)、类型化(占位符编辑器或渲染器))]
命名空间编辑器WithPlaceholder.iOS.Renders
{
公共类占位符EditorRenderer:EditorRenderer
{
专用UILabel _占位符标签;
受保护的覆盖无效OnElementChanged(ElementChangedEventArgs e)
{
基础。一个要素发生变化(e);
if(元素==null)
返回;
CreatePlaceholderLabel((占位符编辑器)元素,控件);
控制。结束+=结束;
Control.TextChanged+=OnChanged;
}
私有void CreatePlaceholderLabel(占位符编辑器元素,UITextView父元素)
{
_占位符标签=新UILabel
{
Text=元素。占位符,
TextColor=element.placeholder.ToUIColor(),
BackgroundColor=UIColor.Clear,
Font=UIFont.FromName(element.FontFamily,(nfloat)element.FontSize)
};
_Placeholder Label.SizeToFit();
parent.AddSubview(\u占位符标签);
parent.subviewsdonottranslationautoresizingmaskintoconstraints();
parent.AddConstraints(
_Placeholder Label.AtLeftOf(父项,7),
_占位符标签。带占位符中心(父项)
);
parent.layoutifneed();
_占位符label.Hidden=parent.HasText;
}
私有void onned(对象发送方、事件args args)
{
if(!((UITextView)sender).HasText&&u占位符标签!=null)
_占位符label.Hidden=false;
}
私有void OnChanged(对象发送方、事件args args)
{
如果(_占位符标签!=null)
_占位符label.Hidden=((UITextView)sender.HasText;
}
受保护的覆盖无效处置(布尔处置)
{
如果(处置)
{
控制。结束-=未结束;
Control.Changed-=OnChanged;
_占位符标签?.Dispose();
_占位符标签=空;
}
基地。处置(处置);
}
}
}
我希望这些信息有帮助

供参考:

以下是您自己提到的行之有效的方法:

<AbsoluteLayout
             HorizontalOptions="FillAndExpand"
             VerticalOptions="FillAndExpand">
                <Editor
                    Text="{Binding Address, Mode=TwoWay}"
                    HorizontalOptions="FillAndExpand"
                    AbsoluteLayout.LayoutFlags="PositionProportional, WidthProportional"
                    AbsoluteLayout.LayoutBounds="0,0,1.01,100">
                </Editor>
                <Label Text="MyPlaceHolder" IsVisible="{Binding IsAddrerssPlaceHolderVisible}" HorizontalTextAlignment="Center"
                                       AbsoluteLayout.LayoutBounds="0.5,0.5, 1, 0.5" VerticalTextAlignment="Center"
                                       AbsoluteLayout.LayoutFlags="All" InputTransparent="True"/>
</AbsoluteLayout>

它甚至不需要我之前错误提到的任何东西!它的工作原理很简单:D

我已经在MVVM中成功地实现了您的方法。您可以将任何事件转换为要从viewmodel运行的命令,为此,您可以使用行为NuGet。@Vahid您可以演示如何执行吗?:)我已经试过了,但是我的代码有点问题。出于某种原因,它不会使标签不可见,即使当它通过isAddressSplaceHolderVible=false;时也是如此;。我已经用一个断点进行了测试,这正是我在自己的项目中使用的断点,它工作起来很有魅力。您是否已将PropertyChanged通知程序事件放置在IsAddressSplaceHoldService的setter中,如上面的代码中所示,它是“RaisePropertyChanged()”?请显示您的IsAddressSplaceHoldService属性。是的,这里:
private bool\u labelIsVisible{get;set;}=true;public bool LabelIsVisible{get{return{u LabelIsVisible;}set{{u LabelIsVisible=value;OnPropertyChanged(nameof(LabelIsVisible));}
我还尝试在代码中将LabelIsVisible设置为false时打印它。它说的是假的,但这并不能让它隐形。
using System;
using Cirrious.FluentLayouts.Touch;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace EditorWithPlaceholder.iOS.Renderers
{
    public class PlaceholderEditorRenderer : EditorRenderer
    {
        private UILabel _placeholderLabel;

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

            if (Element == null)
                return;

            CreatePlaceholderLabel((PlaceholderEditor) Element, Control);

            Control.Ended += OnEnded;
            Control.TextChanged += OnChanged;
        }

        private void CreatePlaceholderLabel(PlaceholderEditor element, UITextView parent)
        {
            _placeholderLabel = new UILabel
            {
                Text = element.Placeholder,
                TextColor = element.PlaceholderColor.ToUIColor(),
                BackgroundColor = UIColor.Clear,
                Font = UIFont.FromName(element.FontFamily, (nfloat)element.FontSize)
            };
            _placeholderLabel.SizeToFit();

            parent.AddSubview(_placeholderLabel);

            parent.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
            parent.AddConstraints(
                _placeholderLabel.AtLeftOf(parent, 7),
                _placeholderLabel.WithSameCenterY(parent)
            );
            parent.LayoutIfNeeded();

            _placeholderLabel.Hidden = parent.HasText;
        }

        private void OnEnded(object sender, EventArgs args)
        {
            if (!((UITextView) sender).HasText && _placeholderLabel != null)
                _placeholderLabel.Hidden = false;
        }

        private void OnChanged(object sender, EventArgs args)
        {
            if (_placeholderLabel != null)
                _placeholderLabel.Hidden = ((UITextView) sender).HasText;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                Control.Ended -= OnEnded;
                Control.Changed -= OnChanged;

                _placeholderLabel?.Dispose();
                _placeholderLabel = null;
            }

            base.Dispose(disposing);
        }
    }
}
<AbsoluteLayout
             HorizontalOptions="FillAndExpand"
             VerticalOptions="FillAndExpand">
                <Editor
                    Text="{Binding Address, Mode=TwoWay}"
                    HorizontalOptions="FillAndExpand"
                    AbsoluteLayout.LayoutFlags="PositionProportional, WidthProportional"
                    AbsoluteLayout.LayoutBounds="0,0,1.01,100">
                </Editor>
                <Label Text="MyPlaceHolder" IsVisible="{Binding IsAddrerssPlaceHolderVisible}" HorizontalTextAlignment="Center"
                                       AbsoluteLayout.LayoutBounds="0.5,0.5, 1, 0.5" VerticalTextAlignment="Center"
                                       AbsoluteLayout.LayoutFlags="All" InputTransparent="True"/>
</AbsoluteLayout>
public bool IsAddrerssPlaceHolderVisible
        {
            get => _isAddrerssPlaceHolderVisible;
            set
            {
                _isAddrerssPlaceHolderVisible= value;
                RaisePropertyChanged();
            }
        }

public string Address
        {
            get => _address;
            set
            {
                _address = value;
                if (value.Length > 0)
                {
                    IsAddrerssPlaceHolderVisible= false;
                }
                else
                {
                    IsAddrerssPlaceHolderVisible= true;
                }
                RaisePropertyChanged();
            }
        }