I don't know why my Xamarin.Forms custom renderer doesn't work if I put it into a library and only on iOS, somebody could help me?
[assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
namespace Plugin.HtmlLabel.iOS
{
public class HtmlLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control == null) return;
UpdateMaxLines();
UpdateText();
}
It works fine on Android, UWP and iOS if into the project.
https://github.com/matteobortolazzo/HtmlLabelPlugin
Add a do-nothing Initialize static method to your HtmlLabelRenderer class to insure your renderer types are loaded before Forms
Example:
public static void Initialize()
{
}
Usage:
In your AppDelegate before Forms.Init(), call your Initialize method:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Plugin.HtmlLabel.iOS.HtmlLabelRenderer.Initialize();
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
Related
In earlier versions, you could have a class which implements ServletContextListener and put your code in the contextInitialized method, so that it runs when the server starts. This is useful for loading up the database into memory. How does one achieve this in a Vaadin 8 project?
In exactly the same way: By registering a ServletContextListener. You can use the #WebListener annotation for this. For example:
public class WebConfig {
#WebServlet("/*")
#VaadinServletConfiguration(ui = VaadinUI.class, productionMode = false)
public static class JdbcExampleVaadinServlet extends VaadinServlet {
}
#WebListener
public static class JdbcExampleContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
try {
DatabaseService.init();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
DatabaseService.shutdown();
}
}
}
I am making use of Prism in my xamarin forms project.I was able to use dependency injection(constructor injection) in my View Model without any problems.I am also making use of background services to push long running tasks in the background.How do I inject dependency in my Background services?When I try to pass the interface object as a paramater to the constructor(SyncingBackgroundingCode) ,the object(SqliteService) is null.I have registered and resolved the objects in the dependency injection container.
How to handle this case?Can anybody provide an example or link to implement this scenario?
This is the piece of code where im trying to implement dependency injection.
This is in Droid :-
public class AndroidSyncBackgroundService : Service
{
CancellationTokenSource _cts;
public override IBinder OnBind (Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand (Intent intent, StartCommandFlags flags, int startId)
{
_cts = new CancellationTokenSource ();
Task.Run (() => {
try {
//INVOKE THE SHARED CODE
var oBackground = new SyncingBackgroundingCode();
oBackground.RunBackgroundingCode(_cts.Token).Wait();
}
catch (OperationCanceledException)
{
}
finally {
if (_cts.IsCancellationRequested)
{
var message = new CancelledTask();
Device.BeginInvokeOnMainThread (
() => MessagingCenter.Send(message, "CancelledTask")
);
}
}
}, _cts.Token);
return StartCommandResult.Sticky;
}
public override void OnDestroy ()
{
if (_cts != null) {
_cts.Token.ThrowIfCancellationRequested ();
_cts.Cancel ();
}
base.OnDestroy ();
}
}
This is in PCL:-
public class SyncingBackgroundingCode
{
public SQLiteConnection _sqlconnection;
SqliteCalls oSQLite = new SqliteCalls();
ISqliteService _SqliteService;
public SyncingBackgroundingCode(ISqliteService SqliteService)
{
//object is null
}
public async Task RunBackgroundingCode(CancellationToken token)
{
DependencyService.Get<ISQLite>().GetConnection();
await Task.Run (async () => {
token.ThrowIfCancellationRequested();
if (App.oSqliteCallsMainLH != null)
{
App.bRunningBackgroundTask = true;
oSQLite = App.oSqliteCallsMainLH;
await Task.Run(async () =>
{
await Task.Delay(1);
oSQLite.ftnSaveOnlineModeXMLFormat("Offline", 0);
oSQLite.SyncEmployeeTableData();
oSQLite.SaveOfflineAppCommentData();
oSQLite.SaveOfflineAdditionToFlowData();
await Task.Delay(500);
var msgStopSyncBackgroundingTask = new StopSyncBackgroundingTask();
MessagingCenter.Send(msgStopSyncBackgroundingTask, "StopSyncBackgroundingTask");
});
}
}, token);
}
}
Unfortunately Xamarin and Xamarin Forms don't give frameworks like Prism anywhere to tie into to handle IoC scenarios. There are a couple of ways you can handle this though.
First the Container is a public property on the PrismApplication in your background service you could do something like:
public class FooBackgroundService
{
private App _app => (App)Xamarin.Forms.Application.Current;
private void DoFoo()
{
var sqlite = _app.Container.Resolve<ISQLite>();
}
}
Another slightly more involved way would be to use the ServiceLocator pattern. You might have something like the following:
public static class Locator
{
private static Func<Type, object> _resolver;
public static T ResolveService<T>() =>
(T)_resolver?.Invoke(typeof(T));
public static void SetResolver(Func<Type, object> resolver) =>
_resolver = resolver;
}
In your app you would then simply set the resolver. Prism actually does something similar to this with the ViewModel locator, which then allows it to inject the correct instance of the NavigationService.
public class App : PrismApplication
{
protected override void OnInitialized()
{
SetServiceLocator();
NavigationService.NavigateAsync("MainPage");
}
protected override void RegisterTypes()
{
// RegisterTypes
}
private void SetServiceLocator()
{
Locator.SetResolver(type => Container.Resolve(type, true));
}
}
Finally your service would simply reference the Service Locator like:
public class BarBackgroundService
{
public void DoBar()
{
var sqlite = Locator.ResolveService<ISQLite>();
// do foo
}
}
I am developing an App using Xamarin.Forms for listing the news from different sources. I use a webView to open the link corresponding to the news. But I want to show the progress while loading the webpage into web view, like the progress bar on Safari App. For this I have used the ProgressBar element like this:
<StackLayout>
<!-- WebView needs to be given height and width request within layouts to render. -->
<ProgressBar Progress ="" HorizontalOptions="FillAndExpand" x:Name="progress"/>
<WebView x:Name="webView"
HeightRequest="1000"
WidthRequest="1000"
VerticalOptions= "FillAndExpand"
Navigating="webOnNavigating"
Navigated="webOnEndNavigating"/>
</StackLayout>
and in the code I have used
void webOnNavigating (object sender, WebNavigatingEventArgs e)
{
progress.IsVisible = true;
}
void webOnEndNavigating (object sender, WebNavigatedEventArgs e)
{
progress.IsVisible = false;
}
But I want to show also the progress of loading the data, not just an indication that is loading and load. I want the user to know that the data are loading. Is there a way to achieve this.
The implementations should be platform specific via custom renders. Luckily this topics has been discussed already for different platforms here on SO.
The Android version based on this thread:
[assembly: ExportRenderer(typeof(WebView), typeof(GenericWebViewRenderer))]
namespace WebViewWithProgressBar.Droid
{
public class GenericWebViewRenderer : WebViewRenderer
{
Context ctx;
public GenericWebViewRenderer(Context context) : base(context)
{
ctx = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (Control == null)
return;
var progressBar = new Android.Widget.ProgressBar(ctx, null, Android.Resource.Attribute.ProgressBarStyleHorizontal);
Control.SetWebChromeClient(new MyWebChromeClient(progressBar));
Control.AddView(progressBar);
}
class MyWebChromeClient : Android.Webkit.WebChromeClient
{
Android.Widget.ProgressBar progressBar;
public MyWebChromeClient(Android.Widget.ProgressBar progressBar)
{
this.progressBar = progressBar;
}
public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)
{
progressBar.SetProgress(newProgress, true);
}
}
}
}
On iOS it is a bit trickier, here is a very simple mock that does it job pretty well:
[assembly: ExportRenderer(typeof(WebView), typeof(GenericWebViewRenderer))]
namespace WebViewWithProgressBar.iOS
{
public class GenericWebViewRenderer : ViewRenderer<WebView, UIWebView>
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var progressBar = new UIProgressView(UIProgressViewStyle.Bar);
progressBar.TintColor = UIColor.Green;
progressBar.TrackTintColor = UIColor.Black;
progressBar.ProgressTintColor = UIColor.Red;
var webView = new UIWebView(Frame);
webView.AddSubview(progressBar);
SetNativeControl(webView);
Control.Delegate = new MyUIWebViewDelegate(progressBar);
webView.LoadRequest(new NSUrlRequest(new NSUrl("https://google.com")));
}
}
class MyUIWebViewDelegate : UIWebViewDelegate
{
UIProgressView progressBar { get; }
public MyUIWebViewDelegate(UIProgressView progressBar)
{
this.progressBar = progressBar;
}
public override void LoadStarted(UIWebView webView)
{
progressBar.SetProgress(0.1f, false);
}
public override void LoadingFinished(UIWebView webView)
{
progressBar.SetProgress(1.0f, true);
}
public override void LoadFailed(UIWebView webView, NSError error)
{
// TODO:
}
}
}
}
For more details please check here.
P.S.: This code examples are available on github.
I would like to know about Vaadin's detach() method. How can I understand below definition from API ?
Called before the UI is removed from the session.
I got a problem when creating custom listener such as BroadCaster .
MyCustomListener.java
public interface MyCustomListener {
void fireEvent(MyCustomEvent event);
}
MyCustomEvent.java
public class MyCustomEvent {
private String message;
public MyCustomEvent(final String message) {
this.message = message;
}
public final String getMessage() {
return message;
}
}
MyCustomDispatcher.java
public final class MyCustomDispatcher {
private static LinkedList<MyCustomListener> customListeners = new LinkedList<MyCustomListener>();
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
private MyCustomDispatcher() {
}
public static synchronized void register(final MyCustomListener listener) {
customListeners.add(listener);
}
public static synchronized void unregister(final MyCustomListener listener) {
customListeners.remove(listener);
}
public static synchronized void invokeMyCustomEvent(final String message) {
if (message == null || message.trim().length() <= 0) {
return;
}
for (final MyCustomListener listener : customListeners) {
executorService.execute(new Runnable() {
public void run() {
listener.fireEvent(new MyCustomEvent(message));
}
});
}
}
}
I call this listener from my UI class as ...
public class HelloWorldUI extends UI implements MyCustomListener {
#Override
protected void init(VaadinRequest request) {
System.out.println("Getting initialized !");
MyCustomDispatcher.register(this);
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
setSizeFull();
layout.addComponent(new Label("Hello World !"));
}
#Override
public void detach() {
System.out.println("Listener was Unregister !");
MyCustomDispatcher.unregister(this);
super.detach();
}
#Override
public void fireEvent(MyCustomEvent event) {
// Do Something
}
}
I call unregister() method of my custom listener inside detach() method for
from some examples for custom listener
to avoid receiving messages for UIs no longer in use (and ensuring that the detached UI can be garbage collected).
Cleaning up resources in a UI
My problem was due to detach() method because when I refreshed my browser , my listener instance was deleted (from detach() method). So , I can't get fireEvent() anymore. I debugged , detach() method was called after init() method of my UI when refreshing browser. But if I remove calling unregister(MyCustomListener listener) from detach() method , that may cause nesting events (previous listeners were still alive).
What am I wrong ? How can I fix it ? Any suggestions ?
Sorry ! this is stupid question . Vaadin's component were server-side codes and I should avoid using static as I much as I can. When I am using my custom listeners as static-resources , these events were share all others. If someone invokes one event , every users will get same.
Static collection of listeners (sharing events) may only suitable for server-push.
I shouldn't create custom listeners as like this.
Thanks #HenriKerola for explanation of using static fields in vaadin and about the creating new UI instance when browser was refresh.
I need to create simple HTML editor. I know desktop application I can get access to DOM and set DesignMode=true. How can I do it for WebView in winrt application?
So seems I've found solution how to set DesignMode for WebView in WinRT applications.
I just needed invoke javascript method that could change document.designMode property to "on"
In my case I implemented extension for WebView where added DependencyProperty.
public static class WebViewEx
{
public static readonly DependencyProperty DesignModeProperty = DependencyProperty.RegisterAttached(
"DesignMode", typeof(bool),
typeof(WebViewEx),
new PropertyMetadata(null, OnDesignModePropertyChanged));
private async static void OnDesignModePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
if (DesignMode.DesignModeEnabled)
return;
WebView view = dependencyObject as WebView;
if (view == null)
return;
if (e.NewValue == e.OldValue)
return;
await view.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
if ((bool)e.NewValue)
{
await view.InvokeScriptAsync("eval", new string[] { "document.designMode = \"on\";" });
}
else
{
await view.InvokeScriptAsync("eval", new string[] { "document.designMode = \"off\";" });
}
});
}
public static void SetDesignMode(DependencyObject element, bool value)
{
element.SetValue(DesignModeProperty, value);
}
public static bool GetDesignMode(DependencyObject element)
{
return (bool)element.GetValue(DesignModeProperty);
}
}
That allows me to turn on\off DesignMode from XAML
<WebView x:Name="webViewBody" Source="about:blank" controls:WebViewEx.DesignMode="true"/>
Mandatory requirement to Invoke javascript methods is webview should be initialized. In my case I set source property to "about:blank"