[英]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
.为了实现你的目标,你可以简单地将
Entry
您PopupEntryFrame
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">
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
的评论中,让我们看看如何使用该方法实现相同的结果。
First of all, it is important to know that Frame
inherits itself from ContentView
(from which acctualy it inherits its Content
property!).首先,重要的是要知道
Frame
从ContentView
继承自身(实际上它继承了它的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
方法。
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
};
}
}
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
,当Entry
的Text
更改时将触发该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);
}
}
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!快乐编码!
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.