i would like to add a TextInputEdit text in my Xamarin.Forms project, is possible to add in code or in XAML? i need to add reference to Mono.Android dll?
You can use Customizing an Entry to realize it .
Creating the Custom Entry Control :
public class MyEntry : Entry
{
}
Consuming the Custom Control:
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<local:MyEntry Text="In Shared Code" />
...
</ContentPage>
Creating the Custom Renderer on Android :
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace CustomRenderer.Android
{
class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.SetBackgroundColor(global::Android.Graphics.Color.LightGreen);
}
}
}
}
Here is the official sample for reference.
Related
I am trying to create an optimized Event Tracker for my Xamarin.forms prism application. I would like to know whether there is any method to find out when the page load is finished. If someone could help me, please save my time.
You can implement page loading methods for different platforms through custom renderer.
For iOS, override the viewDidLoad method, ViewDidLoad(Called after the controller's view is loaded into memory.)
[assembly:ExportRenderer (typeof(ContentPage), typeof(MyRenderer))]
namespace Demo.iOS
{
public class MyRenderer : PageRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
}
}
}
For Android, rewrite the OnAttachedToWindow method, OnAttachedToWindow(This is called when the view is attached to a window.)
[assembly: ExportRenderer(typeof(ContentPage), typeof(MyRenderer))]
namespace Demo.Droid
{
public class MyRenderer : PageRenderer
{
public MyPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
}
}
}
I'm trying to port an Android existing custom ViewRenderer to iOS.
I'm using version 4.8 of Xamarin.Forms.
Specifically, I need to match Android's OnAttachedToWindow & OnDetachedFromWindow.
The Android Code is like the following:
public partial class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
...
}
protected override void OnDetachedFromWindow()
{
base.OnDetachedFromWindow();
...
}
}
According to this link, I would need to override ViewWillAppear which is the iOS equivalent to OnAttachedToWindow.
The custom Renderer for iOS is the following:
public partial class HybridWebViewRenderer : ViewRenderer<HybridWebView, WkWebViewRenderer>, IWKScriptMessageHandler
{
}
But the overrides are not available.
How can I do that?
ViewWillAppear and ViewWillDisappear are the life cycle method of UIViewController.So you could create the custom renderer of ContentPage
in the ContentPage that contains the WebView
using Foundation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using App1;
using App1.iOS;
[assembly:ExportRenderer(typeof(MainPage),typeof(MyPageRenderer))]
namespace App1.iOS
{
public class MyPageRenderer:PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
MessagingCenter.Send<Object,UIViewController>(this,"ViewWillAppear",this); // send message when the method been called .
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
MessagingCenter.Send<Object, UIViewController>(this, "ViewWillDisappear", this);
}
}
}
in WebViewRenderer
Subscribe the message in the constructor .
MessagingCenter.Subscribe<Object, UIViewController > (this, "ViewWillDisappear",(arg,controller)=> {
// controller is the current UIViewController
});
In my Xamarin.Forms app, I have a custom renderer:
[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
namespace MyApp.Controls
{
public class CustomEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
Control.Style = (Windows.UI.Xaml.Style)App.Current.Resources["CustomTextBoxStyle"];
}
}
}
}
But I only want to use it on 1 of my Entry controls, not all of them. How can I accomplish this?
create a custom control MyEntry that inherits from Entry
then in your renderer, specify that it only applies to type MyEntry
[assembly: ExportRenderer(typeof(MyEntry), typeof(CustomEntryRenderer))]
The line Resources.Add("eventAggregator", Container.Resolve()); raises Null exception.
UPDATE
I've added all classes to explain more. As #Axemasta said, there is no need to register IEventAggregator and I removed registration. Now I don't how to connect the Listview EventAggregator behavior to the EventAggregator.
This is whole App.xaml code file.
public partial class App : PrismApplication
{
/*
* The Xamarin Forms XAML Previewer in Visual Studio uses System.Activator.CreateInstance.
* This imposes a limitation in which the App class must have a default constructor.
* App(IPlatformInitializer initializer = null) cannot be handled by the Activator.
*/
public App() : this(null) { }
public App(IPlatformInitializer initializer) : base(initializer) { }
protected override async void OnInitialized()
{
InitializeComponent();
Resources.Add("eventAggregator", Container.Resolve<IEventAggregator>());// Removed on update
FlowListView.Init();
await NavigationService.NavigateAsync("NavigationPage/MainPage");
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<MainPage>();
}
}
}
The behavior class:
public class ScrollToMyModelBehavior : BehaviorBase<ListView>
{
private IEventAggregator _eventAggregator;
public IEventAggregator EventAggregator
{
get => _eventAggregator;
set
{
if (!EqualityComparer<IEventAggregator>.Default.Equals(_eventAggregator, value))
{
_eventAggregator = value;
_eventAggregator.GetEvent<ScrollToMyModelEvent>().Subscribe(OnScrollToEventPublished);
}
}
}
private void OnScrollToEventPublished(ListItem model)
{
AssociatedObject.ScrollTo(model, ScrollToPosition.Start, true);
}
protected override void OnDetachingFrom(ListView bindable)
{
base.OnDetachingFrom(bindable);
// The Event Aggregator uses weak references so forgetting to do this
// shouldn't create a problem, but it is a better practice.
EventAggregator.GetEvent<ScrollToMyModelEvent>().Unsubscribe(OnScrollToEventPublished);
}
}
The Event class:
public class ScrollToMyModelEvent : PubSubEvent<ListItem>
{
}
The page view model:
public MainPageViewModel(INavigationService navigationService, IEventAggregator eventAggregator)
: base (navigationService)
{
Title = "صفحه اصلی";
ListHeight = 100;
ListWidth = 250;
_eventAggregator = eventAggregator;
Items items = new Items();
ListViewItemSouce = items.GetItems();
MyModels = items.GetItems();
SelectedModel = ListViewItemSouce[3];
_eventAggregator.GetEvent<ScrollToMyModelEvent>().Publish(SelectedModel);
}
The page view:
<StackLayout HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="{Binding ListWidth}" HeightRequest="{Binding ListHeight}"
Grid.Row="1" Grid.Column="1">
<local:NativeListView x:Name="lst3" ItemsSource="{Binding ListViewItemSouce}" Margin="1" BackgroundColor="Transparent" RowHeight="47" HasUnevenRows="false">
<ListView.Behaviors>
<local:ScrollToMyModelBehavior EventAggregator="{StaticResource eventAggregator}" /> // Error raised that there is not such a static property
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Word}" TextColor="Black"/>
</DataTemplate>
</ListView.ItemTemplate>
</local:NativeListView>
</StackLayout>
You do not need to register IEventAggregator when the app initialises, much like INavigationService or IPageDialog, you can use it straight out of the box!
To use EventAggregator you should do the following things:
Create an Event
You will first need to create an Event (using Prism) that you can pass to the EventAggregator. Your event should inherit from PubSubEvent, you can pass this an object (optional). So your event would look like this:
using System;
using Prism.Events;
namespace Company.App.Namespace.Events
{
public class SampleEvent : PubSubEvent
{
}
}
Looking at a recent app, I most commonly use this when passing data between custom popup views (like a dictionary of params).
Subscribe to the Event
When IEventAggregator fires, anything that has subscribe to the event will execute any code specified. In the class you want to recieved the event you will have to do the following:
Pass the class IEventAggregator through the constructor (prism does the DI afterall)
Initialise a local IEventAggregator for use in this class
Subscribe IEventAggregator to a handler method.
Here is what the code may look like:
public class TheClassListeningForAnEvent
{
private readonly IEventAggregator _eventAggregator;
public TheClassListeningForAnEvent(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<SampleEvent>().Subscribe(OnEventRecieved);
}
void OnEventRecieved()
{
//Do something here
}
}
Fire the Event
Now you have registered for the event, you can fire the event. Pass the IEventAggregator into whatever class you want to fire the event from and use the Publish Method:
public class TheClassPublishingAnEvent
{
private readonly IEventAggregator _eventAggregator;
public TheClassListeningForAnEvent(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<SampleEvent>().Publish();
}
}
Thats the long and the short of it. You could pass anything to the IEventAggregator, you would just need to handle for this in the methods you are subscribing.
Hopefully that is enough to get you going using IEventAggregator!
Just verify if you are adding below code in IOS, Android and UWP projects.
IOS- Appdelegate
public class AppdelegateInitializer : IPlatformInitializer
{
public void RegisterTypes(IUnityContainer container)
{
}
}
Android - MainActivity
public class MainActivityInitializer : IPlatformInitializer
{
public void RegisterTypes(IUnityContainer container)
{
}
}
UWP-- MainPage.cs
public class UwpInitializer : IPlatformInitializer
{
public void RegisterTypes(IUnityContainer container)
{
}
}
My guidance on this has evolved as features have been added to Prism to make this sort of thing even easier.
In the past the reason you would resolve and add the IEventAggregator as a StaticResource is that there was no way to inject this. We now have the ContainerProvider which amazingly allows you to add types in XAML that require Dependency Injection. To start you can refactor your ScrollToBehavior to use a DI Pattern by adding the IEventAggregator as a constructor parameter, removing the Bindable Property (if you choose).
public class ScrollToBehavior : BehaviorBase<ListView>
{
private IEventAggregator _eventAggregator { get; }
public ScrollToBehavior(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
}
As I mentioned you can use the ContainerProvider in XAML to resolve and provide a type that requires DI, as follows:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ioc="clr-namespace:Prism.Ioc;assembly=Prism.Forms"
xmlns:behavior="using:AwesomeProject.Behaviors
x:Class="AwesomeProject.Views.ViewA">
<ListView>
<ListView.Behaviors>
<ioc:ContainerProvider x:TypeArguments="behavior:ScrollToBehavior" />
</ListView.Behaviors>
</ListView>
</ContentPage>
I want to call a base.Dispose() on the OnDisappearing() from my Android project in Xamarin.Forms.
I have done something like this :-
namespace Project.Mobile.Droid
{
[assembly: ExportRenderer(typeof(ItemListPage), typeof(DisposeRenderer))]
class DisposeRenderer : ViewRenderer
{
public DisposeRenderer() { }
}
}
How can I go ahead with this?
Iam new to Xamarin.Forms, so it would be a great help if someone helps me on this.
As long as your ItemListPage implements IDisposable, you could try the following :-
using System;
using DisposableControlSample;
using DisposableControlSample.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(DisposablePage), typeof(DisposablePageRenderer))]
namespace DisposableControlSample.Droid
{
public class DisposablePageRenderer : PageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
e.NewElement.Disappearing += (sender, args) =>
{
var disposablePage = sender as IDisposable;
if (disposablePage != null)
{
disposablePage.Dispose();
}
};
}
}
}