У меня есть страница Xamarin, на которой мне пришлось использовать собственное средство визуализации страниц Android, чтобы поддерживать API для конкретной платформы.

BasePage.xaml передает управление MyPage.xaml с помощью Navigation.PushAsync()

Страница 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 для вышеуказанного выглядит примерно так, как показано ниже.

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

        }


    }
}

Я намерен вернуть управление в MyPage.xaml.cs или BasePage.xaml.cs из MyPageRenderer с результатом ButtonTapped . Я использую событие ItemAdded и обработайте это в коде за этой страницей. Я не могу получить доступ к событию ItemAdded, которое находится в специальном рендерере Android, только из общего проекта.

Мне нужно обновить ViewModel из BasePage, чтобы я обновлял содержимое элементов там, когда MyPage всплывает после добавления нового элемента с помощью кнопки возврата.

< Сильный > Проблема: Я могу получить доступ к MyPage и BasePage, но не могу получить доступ к методу рендеринга и переменным из общего проекта, поскольку проект Android зависит от общего доступа, а не наоборот.

Мне нужно сделать что-то вроде ниже , которое работает для нативной страницы рендеринга < Сильный > BasePage :

    var myPage = new MyPage();
    myPage.ItemAdded += OnItemAdded;
    await Navigation.PushAsync(myPage);

< Сильный > MyPage :

public event EventHandler ItemAdded;
.
.

void SomeMethod(){

ItemAdded(this, EventArgs.Empty);

}

Вопрос: Как передать управление от NativeRenderer обратно в общий код Xamarin Forms?

Я знаю, что мы можем передать управление классу MainActivity, но я хочу передать управление BasePage.xaml.cs, чего я не получил из документации. Если кто-то работал над PageRenderer, предложите.

0
Prateek 25 Сен 2018 в 00:53

2 ответа

Лучший ответ

В классе "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());
        }
    }

В классе "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();

        }
    }

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

Вы должны определить свой класс события следующим образом:

public class SomeButtonClickedEvent : PubSubEvent<SomeButtonClickedEvent>
    {
        //you can define parameters here, if the event needs to pass a parameter.
    }
3
zohre moradi 25 Сен 2018 в 05:19

Что касается ответа zohre moradi, я мог бы добиться этого, как показано ниже. При этом не используются IEventAggregator - Subscribe/Publish методов событий. Если событие требуется только на одной странице, можно избежать IEventAggregator.

< Сильный > 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

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

И в 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
}
0
Morse 5 Окт 2018 в 00:26