3

这是我在 Deczalof 的帮助下一直在编写的代码:

这是我拥有的 XAML 代码

<t:PopupEntryFrame2 x:Name="newDeckNameEntry" TextChanged="newDeckNameEntry_TextChanged" />

后面有代码:

public partial class CopyDeckPopup : Rg.Plugins.Popup.Pages.PopupPage
{
    string originalName;
    string originalDescription;
    List<Deck> listDecks;

    public CopyDeckPopup(string clickedDeckName, string clickedDeckDescription)
    {
        InitializeComponent();
        listDecks = App.DB.GetAllDecks();
        newDeckNameEntry.Text = clickedDeckName;
        newDeckDescriptionEntry.Text = clickedDeckDescription;
        originalName = clickedDeckName;
        originalDescription = clickedDeckDescription;
        OK_Button.IsEnabled = false;
    }

    private async void Cancel_Button_Clicked(object sender, EventArgs e)
    {
        await PopupNavigation.Instance.PopAsync(false);
    }

    private async void OK_Button_Clicked(object sender, EventArgs e)
    {
        if (IsBusy)
            return;
        IsBusy = true;
        await PopupNavigation.Instance.PopAsync(false);
        var newDeckNameEntryTextTrim = newDeckNameEntry.Text.Trim();
        var newDeckDescriptionEntryTextTrim = newDeckDescriptionEntry.Text.Trim();
        if (newDeckNameEntryTextTrim != originalName || newDeckDescriptionEntryTextTrim != originalDescription)
        {
            App.DB.CopyDeckToDb2(originalName, newDeckNameEntryTextTrim, newDeckDescriptionEntryTextTrim);
            MessagingCenter.Send<PopupPage>(new PopupPage(), "PageRefresh");
        }
        IsBusy = false;
    }

    void newDeckNameEntry_TextChanged(object sender, EntryTextChangedEventArgs e)
    {
        NewDeckNameEntryValidator(e.NewTextValue);
    }

    void newDeckDescriptionEntry_TextChanged(object sender, EntryTextChangedEventArgs e)
    {
        var deckName = newDeckNameEntry.Text.Trim();
        var isDeckAvailable = listDecks.Where(x => x.Name == deckName).SingleOrDefault();
        if (isDeckAvailable == null)
        {
            OK_Button.IsEnabled = e.NewTextValue != originalDescription ? true : false;
        }
    }

    void NewDeckNameEntryValidator(string newDeckNameEntry)
    {
        var newDeckNameEntryTrimmed = newDeckNameEntry.Trim();
        var isDeckNameAvailable = listDecks.Where(x => x.Name == newDeckNameEntryTrimmed).SingleOrDefault();
        if (string.IsNullOrWhiteSpace(newDeckNameEntryTrimmed) ||
            isDeckNameAvailable != null ||
            newDeckNameEntryTrimmed.StartsWith("::") ||
            newDeckNameEntryTrimmed.EndsWith("::") ||
            newDeckNameEntryTrimmed.Count(c => c == ':') > 2)
        {
            OK_Button.IsEnabled = false;
            return;
        }
        OK_Button.IsEnabled = true;
    }

}

以及模板的 C# 代码:

public class PopupEntryFrame2 : CustomFrame
{

    CustomEntry entry { get; set; }

    public PopupEntryFrame2()
    {

        entry = new CustomEntry();
        entry.SetBinding(PopupEntryFrame2.TextProperty, new Binding("Text", source: this));

        entry.TextChanged += (s, a) =>
        {
            OnTextChanged(new EntryTextChangedEventArgs(a.NewTextValue, a.OldTextValue));
        };

        Content = entry;

        CornerRadius = 5;
        HasShadow = false;
        SetDynamicResource(BackgroundColorProperty, "EntryFrameBackgroundColor");
        SetDynamicResource(BorderColorProperty, "EntryFrameBorderColor");
        SetDynamicResource(CornerRadiusProperty, "EntryFrameCornerRadius");
        SetDynamicResource(HeightRequestProperty, "PopupEntryFrameHeight");
        SetDynamicResource(MarginProperty, "PopupEntryFrameMargin");
        SetDynamicResource(PaddingProperty, "PopupEntryFramePadding");
    }

    public class EntryTextChangedEventArgs : EventArgs
    {

        public EntryTextChangedEventArgs(String newValue = null, String oldValue = null)
        {
            NewTextValue = newValue;
            OldTextValue = oldValue;
        }

        public String NewTextValue { get; }

        public String OldTextValue { get; }

    }

    public event EventHandler TextChanged;


    protected virtual void OnTextChanged(EntryTextChangedEventArgs args)
    {
        TextChanged?.Invoke(this, args);
    }

    public static readonly BindableProperty TextProperty =
        BindableProperty.Create(nameof(Text), typeof(string), typeof(PopupEntryFrame2), default(string));

    public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }

}

我在构建时遇到的错误是:

CopyDeckPopup.xaml(22,63): XamlC error XFC0002: EventHandler "newDeckNameEntry_TextChanged" 
with correct signature not found in type "DecksTab.Pages.DeckOptions.CopyDeckPopup"
4

1 回答 1

3

为了实现您的目标,您可以简单地添加Entry您的PopupEntryFrame class并定义一个与原始 中的事件相关的Event那里。TextChangedEntry

这是按照下面的代码所示完成的(基于您的!)

using Test.Renderers;

namespace Test.Templates
{
    public class PopupEntryFrame : CustomFrame
    {

        Entry entry { get; set; }

        public PopupEntryFrame()
        {

            entry = new Entry();

            entry.TextChanged += (s, a) =>
            {
                OnTextChanged(new EntryTextChangedEventArgs());
            };

            Content = entry;

            CornerRadius = 5;
            HasShadow = false;
            SetDynamicResource(BackgroundColorProperty, "EntryFrameBackgroundColor");
            SetDynamicResource(BorderColorProperty, "EntryFrameBorderColor");
            SetDynamicResource(CornerRadiusProperty, "EntryFrameCornerRadius");
            SetDynamicResource(HeightRequestProperty, "PopupEntryFrameHeight");
            SetDynamicResource(MarginProperty, "PopupEntryFrameMargin");
            SetDynamicResource(PaddingProperty, "PopupEntryFramePadding");
        }

        public class EntryTextChangedEventArgs : EventArgs
        {
            // class members  
        }

        public event EventHandler TextChanged;
        protected virtual void OnTextChanged(EntryTextChangedEventArgs args)
        {
            TextChanged?.Invoke(this, args);
        }

    }
}

就是这样。通过这样做,您现在可以编写如下代码

<t:PopupEntry x:Name="newDeckDescriptionEntry" TextChanged="newDeckDescriptionEntry_TextChanged">

更新

在有人建议使用的评论中ContentView,让我们看看如何使用该方法实现相同的结果。

免责声明

首先,重要的是要知道Frame继承自ContentView(实际上它继承了它的Content属性!)。事实上,从文档中我们知道

[Xamarin.Forms.ContentProperty("Content")]
[Xamarin.Forms.RenderWith(typeof(Xamarin.Forms.Platform._FrameRenderer))]
public class Frame : Xamarin.Forms.ContentView, Xamarin.Forms.IBorderElement, Xamarin.Forms.IElementConfiguration<Xamarin.Forms.Frame>

这意味着通过创建一个继承自的类/控件Frame意味着我们已经在使用该ContentView方法。

创建内容视图

首先,我们创建 aContentView并将其内容设置为 anew PopupFrame()本身包含 a Entry,如下所示

public class PopupEntry : ContentView
{

    Entry entry { get; set; }

    public PopupEntry()
    {

        entry = new Entry();

        Content = new PopupFrame()
        {
            Content = entry
        };

    }

}

添加事件

接下来,按照 OP 的要求,我们Event为我们定义一个ContentViewTextEntry更改时触发的。在文档之后,这可以通过添加以下代码来实现:

public class EntryTextChangedEventArgs : EventArgs
{
    // class members  
}

public event EventHandler TextChanged;
protected virtual void OnTextChanged(EntryTextChangedEventArgs args)
{
    TextChanged?.Invoke(this, args);
}

现在,我们可以将原始TextChanged事件从Entry控件“链接”到Event我们的新事件ContentView,如下所示:

entry.TextChanged += (s, a) =>
{
    OnTextChanged(new EntryTextChangedEventArgs());
};

然后,我们的 ContentView 代码将如下所示

public class PopupEntry : ContentView
{

    Entry entry { get; set; }

    public PopupEntry()
    {

        entry = new Entry();

        entry.TextChanged += (s, a) =>
        {
            OnTextChanged(new EntryTextChangedEventArgs());
        };

        Content = new PopupFrame()
        {
            Content = entry
        };


    }

    public class EntryTextChangedEventArgs : EventArgs
    {
        // class members  
    }

    public event EventHandler TextChanged;
    protected virtual void OnTextChanged(EntryTextChangedEventArgs args)
    {
        TextChanged?.Invoke(this, args);
    }

}

包起来

有了这个ContentView定义,我们现在可以编写如下代码

<t:PopupEntry x:Name="newDeckDescriptionEntry" TextChanged="newDeckDescriptionEntry_TextChanged"/>

就是这样!我希望这很有用。

快乐编码!

PS:

关于事件声明的一点说明:由于 EntryTextChangedEventArgs 是原始 TextChangedEventArgs 的副本,我们可以定义 EntryTextChangedEventArgs 类,如

public class EntryTextChangedEventArgs : EventArgs
{

    public EntryTextChangedEventArgs(String newValue = null, String oldValue = null)
    {
        NewTextValue = newValue;
        OldTextValue = oldValue;
    }

    public String NewTextValue { get; }

    public String OldTextValue { get; }

}

然后在实例化这个类时,我们直接用来自 TextChangedEventArgs 的值来提供它,如下所示

entry = new Entry();

entry.TextChanged += (s, a) =>
{
    OnTextChanged(new EntryTextChangedEventArgs(a.NewTextValue, a.OldTextValue));
};
于 2020-11-21T22:14:35.440 回答