[英]How to pass values from custom PageRenderer to Shared Xaml Page code behind in Xamarin
I have a Xamarin page in which I had to use Android native page renderer in order to support platform specific API. 我有一个Xamarin页面,在其中必须使用Android本机页面渲染器才能支持特定于平台的API。
BasePage.xaml
passes control to MyPage.xaml
with Navigation.PushAsync()
BasePage.xaml
通过Navigation.PushAsync()
将控制权传递给MyPage.xaml
XAML page : MyPage.xaml XAML页面:MyPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Views.MyPage" Title="My Page">
<ContentPage.Content>
</ContentPage.Content>
</ContentPage>
Android Custom page renderer for the above is something like below. 上面的Android自定义页面渲染器如下所示。
[assembly: ExportRenderer(typeof(MyPage), typeof(MyPageRenderer))]
namespace MyApp.Droid.Renderers
{
public class MyPageRenderer : PageRenderer
{
private Context _localContext;
private global::Android.Views.View view;
private Activity activity;
public event EventHandler ItemAdded;
public MyPageRenderer(Context context) : base(context)
{
_localContext = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
try
{
SetupUserInterface();
SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(@"ERROR: ", ex.Message);
}
}
private void SetupUserInterface()
{
activity = this.Context as Activity;
view = activity.LayoutInflater.Inflate(Resource.Layout.axml_layout, this, false);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);
view.Measure(msw, msh);
view.Layout(0, 0, r - l, b - t);
}
private void SetupEventHandlers()
{
//blah blah
}
private void ButtonTapped(object sender, EventArgs e)
{
//do something
//Here Navigate back to page which triggered this with outcome parameter or some event
ItemAdded(this, EventArgs.Empty);
}
}
}
My intention is send back control to MyPage.xaml.cs
or BasePage.xaml.cs
from MyPageRenderer
with outcome of ButtonTapped
.I am using event ItemAdded
and handle it in code behind of that page. 我的本意是控制送回
MyPage.xaml.cs
或BasePage.xaml.cs
从MyPageRenderer
与成果ButtonTapped
。我现在用的事件ItemAdded
,并在代码处理它该网页的后面。 I can not access ItemAdded
event which is in android specific renderer only from shared project. 我无法仅从共享项目访问android特定渲染器中的
ItemAdded
事件。
I have to update ViewModel
of BasePage
so that I update the content of the items there when MyPage has been popped after adding new item by back button. 我必须更新
BasePage
ViewModel
,以便在通过“后退”按钮添加新项目后弹出MyPage时更新那里项目的内容。
Problem: I can access MyPage and BasePage but can not access renderer method and variables from Shared project because Android project depends on shared not vice versa. 问题:我可以访问MyPage和BasePage,但是不能访问Shared项目中的渲染器方法和变量,因为Android项目依赖于共享而不是相反。
I have to do something like below which is working for non-native render page BasePage: 我必须执行以下操作 ,该操作适用于非本地渲染页面 BasePage:
var myPage = new MyPage();
myPage.ItemAdded += OnItemAdded;
await Navigation.PushAsync(myPage);
MyPage: 我的页面:
public event EventHandler ItemAdded;
.
.
void SomeMethod(){
ItemAdded(this, EventArgs.Empty);
}
Question: How do we pass control from NativeRenderer back to Xamarin Forms shared code? 问题:我们如何将控制权从NativeRenderer传递回Xamarin Forms共享代码?
I know we can pass control to MainActivity
class but I want to pass control to BasePage.xaml.cs
which I did not get from documentation. 我知道我们可以将控制权传递给
MainActivity
类,但是我想将控制权传递给BasePage.xaml.cs
,而这并不是我从文档中得到的。 If anyone has worked on PageRenderer please suggest. 如果有人在PageRenderer上工作过,请提出建议。
in "MyPage" Class 在“ MyPage”类中
public class MyPage : ContentPage
{
public void RaiseSomeButtonClicked() => OnSomeButtonClickeded();
private void OnSomeButtonClicked()
{
//by using aggregators you can publish any event and subscribe it in you BasePage.xaml.cs
((App)App.Current).Container.Resolve<IEventAggregator>()
.GetEvent<SomeButtonClickedEvent>().Publish(new SomeButtonClickedEvent());
}
}
in "MyPageRenderer" Class : 在“ MyPageRenderer”类中:
public class MyPageRenderer : PageRenderer
{
MyPage myPage;
//...
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
myPage = (MyPage)e.NewElement;
//...
}
private void ButtonTapped(object sender, EventArgs e)
{
//do something
myPage.RaiseSomeButtonClicked();
}
}
in "BasePage.xaml.cs", subscribe this event. 在“ BasePage.xaml.cs”中,订阅此事件。
public partial class BasePage : ContentPage
{
private readonly SubscriptionToken _SomeButtonClickedEventSubscription;
public BasePage()
{
InitializeComponent();
_SomeButtonClickedEventSubscription = eventAggregator.Value.GetEvent<SomeButtonClickedEvent>().SubscribeAsync(async e =>
{
//anything you want to do when button clicked!
}, threadOption: ThreadOption.UIThread, keepSubscriberReferenceAlive: true);
}
}
You should define Your event class in this way: 您应该通过以下方式定义事件类:
public class SomeButtonClickedEvent : PubSubEvent<SomeButtonClickedEvent>
{
//you can define parameters here, if the event needs to pass a parameter.
}
With reference to zohre moradi 's answer I could achieve this as below. 参考zohre moradi的答案,我可以如下实现。 This does not use
IEventAggregator
- Subscribe/Publish
of events methods. 这不使用
IEventAggregator
事件的Subscribe/Publish
方法。 If event is only required at one page IEventAggregator
can be avoided. 如果仅在一页上需要事件,则可以避免使用
IEventAggregator
。
MyPage.xaml.cs MyPage.xaml.cs
public event EventHandler ItemAdded;
public void RaiseItemAdded()
{
ItemAdded(this, EventArgs.Empty);
}
//have to close return call back after item addition in MyPage
public async void CallPopAsync()
{
await Navigation.PopAsync();
}
MyPageRenderer.cs MyPageRenderer.cs
MyPage mypage;
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
mypage= (MyPage)e.NewElement;
if (e.OldElement != null || Element == null)
{
return;
}
try
{
SetupUserInterface();
SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(@"ERROR: ", ex.Message);
}
}
private void ButtonTapped(object sender, EventArgs e)
{
//do something
myPage.RaiseItemAdded();
//notify
Toast.MakeText(this.Context, "Item created", ToastLength.Long).Show();
myPage.CallPopAsync();
}
And in BasePage.xaml.cs 并在BasePage.xaml.cs中
//in some method
var myPage = new MyPage();
myPage.ItemAdded += OnItemAdded;
await Navigation.PushAsync(myPage);
private void OnItemAdded(object sender, EventArgs e)
{
//call method to update binding object of viewmodel
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.