简体   繁体   English

如何将模板对象添加到 C# 框架模板中

[英]How can I add in a template object into a C# Frame template

Here is code I have been working on with the help of Deczalof:这是我在 Deczalof 的帮助下一直在处理的代码:

Here is the XAML code that I have这是我拥有的 XAML 代码

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

With code behind:后面有代码:

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;
    }

}

and the C# code for a template:和模板的 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); }

}

The error I get when building is this:我在构建时遇到的错误是:

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

To achieve your goal you can simply add the Entry on your PopupEntryFrame class and define an Event there that connects with the TextChanged event in the original Entry .为了实现你的目标,你可以简单地将EntryPopupEntryFrame class和定义一个Event与连接有TextChanged在原始事件Entry

This is done as illustrated in the code below (which is based on yours!)这是按照下面的代码所示完成的(基于您的代码!)

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);
        }

    }
}

And that's it.就是这样。 By doing that you can now write code like通过这样做,您现在可以编写如下代码

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

Update更新

In the comments someone suggested using ContentView , so let's take a look at how the same result could be achieved using that approach.在有人建议使用ContentView的评论中,让我们看看如何使用该方法实现相同的结果。

Disclaimer免责声明

First of all, it is important to know that Frame inherits itself from ContentView (from which acctualy it inherits its Content property!).首先,重要的是要知道FrameContentView继承自身(实际上它继承了它的Content属性!)。 In fact, from the documentation we know that事实上,从文档中我们知道

[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>

which means that by creating a Class/Control that inherits from Frame means that we are already using the ContentView approach.这意味着通过创建一个继承自Frame的 Class/Control 意味着我们已经在使用ContentView方法。

Create the ContentView创建内容视图

First of all we create a ContentView and set its content to a new PopupFrame() which itself contains an Entry , as follows首先我们创建一个ContentView并将其内容设置为一个new PopupFrame() ,它本身包含一个Entry ,如下所示

public class PopupEntry : ContentView
{

    Entry entry { get; set; }

    public PopupEntry()
    {

        entry = new Entry();

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

    }

}

Add an Event添加事件

Next, as is required by the OP, we define an Event for our ContentView that will be triggered when the Text in the Entry changed.接下来,根据 OP 的要求,我们为ContentView定义一个Event ,当EntryText更改时将触发该Event Following the Documentation , this can be achieved by adding the following piece of code:文档之后,这可以通过添加以下代码来实现:

public class EntryTextChangedEventArgs : EventArgs
{
    // class members  
}

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

Now, we can "link" the original TextChanged event from the Entry control to the new Event of our ContentView , as follows:现在,我们可以将来自Entry控件的原始TextChanged事件“链接”到我们的ContentView的新Event ,如下所示:

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

Then, our ContentView code will look like然后,我们的 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);
    }

}

Wrapping up包起来

With this ContentView defined, we can now write code like定义了这个ContentView ,我们现在可以编写如下代码

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

And that's it!就是这样! I hope this was useful.我希望这是有用的。

Happy coding!快乐编码!

PS: PS:

A little note about the Event declaration: Since EntryTextChangedEventArgs is a copy of the original TextChangedEventArgs we can define the EntryTextChangedEventArgs class like关于事件声明的一点说明:由于 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; }

}

and then when instantiating this class we just feed it directly with the values from TextChangedEventArgs, as follows然后在实例化这个类时,我们直接用来自 TextChangedEventArgs 的值提供给它,如下

entry = new Entry();

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在C#中将params object [i]传递给模板函数 - How to pass params object[i] to a template function in C# 我可以将 Xaml 组合<label>到用于创建框架的 C# 模板中吗?</label> - Can I combine a Xaml <Label> into a C# template that I use to create a Frame? 我如何理解基于什么模板是 c# 项目 - How can i understand what template is the c# project based on 我可以在 C# 中模板化 Func 吗? - Can I template a Func in C#? 如何使用 Rg.Plugins.Popup 将 XAML 和模板合并到一个 C# 模板中? - How can I combine XAML and a template into one C# template with Rg.Plugins.Popup? 如何在 C# for Visual Studio 2022 for net6.0 的新控制台模板中添加枚举? - How do I add an enum to the new console template in C# for Visual Studio 2022 for net6.0? 如何以编程方式将具有属性“模板”的Setter添加到C#/ WPF中的触发器? - How do I programmatically add a Setter with the Property “Template” to a Trigger in C#/WPF? Sendgrid - 如何访问“收件人”电子邮件地址对象以在 v3 api C# 中个性化动态模板 - Sendgrid - How do I access the "to" email address object to personalize dynamic template in v3 api C# 如何在c#中添加或使用.docx模板文件作为资源或参考? - How to add or use .docx template file as a resource or reference in c#? 我正在使用C#,缺少Windows Store App模板,该如何解决? - I'm using C#, Windows Store App template is missing, how can I fix this?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM