Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue Presenting TEditor from "modal" Xamarin Forms Page (iOS) #3

Open
bie5865 opened this issue Mar 31, 2017 · 10 comments
Open

Issue Presenting TEditor from "modal" Xamarin Forms Page (iOS) #3

bie5865 opened this issue Mar 31, 2017 · 10 comments

Comments

@bie5865
Copy link

bie5865 commented Mar 31, 2017

I'm able to present the TE control fine via a Xamarin Forms Page that was that was "Pushed" on the Navigation stack. However, I run into issues if the page that I'm trying to present the control from was a modal, the control will not present. The app doesn't crash either. I've tried both the sample application as well as consuming the nuget package in a simple application.

Steps to Reproduce:

  1. Download Sample.
  2. In the App class switch the MainPage to Present a new page.
public class App : Application
{
    public App()
    {
       this.MainPage = new NavigationPage(new SecondPage());
     }
  1. Have the second page present a ContentPage with that will present the TEditor Control.
public SecondPage()
{
	var nextButton = new Button { Text = "Next Page" };
	
        Content = new StackLayout
	{
		Children = { nextButton}
	};

	var contentPage = new ContentPage { Content = new TEditorHtmlView(), BackgroundColor = Color.White };
	nextButton.Clicked += (object sender, EventArgs e) => { Navigation.PushModalAsync(contentPage); };
}
  1. The TEditor Control will not present
@bie5865
Copy link
Author

bie5865 commented Apr 4, 2017

Also, the control will not present if Xamarin forms main page is a Master Detail. I'm taking a look at the TEditorImplementation class in the iOS project. I think I might have to check for instances where there is no UINavigationController present.

@jessejiang0214
Copy link
Contributor

Please follow the sample code in repo, TEditor cannot be used in that way "new ContentPage { Content = new TEditorHtmlView(), BackgroundColor = Color.White };"

TEditor should be used in a Navigation Page, please make sure your Detail page is Navigation page.

@swansca79
Copy link

swansca79 commented Apr 13, 2017

The master detail problem can be fixed with this code in the iOS project. You'll need to add the Xamarin.Forms Package.

public class TEditorImplementation : BaseTEditor
    {
        public override Task<string> ShowTEditor(string html, ToolbarBuilder toolbarBuilder = null)
        {
            TaskCompletionSource<string> taskRes = new TaskCompletionSource<string>();
            var tvc = new TEditorViewController();
	     tvc.Title = Title;
            ToolbarBuilder builder = toolbarBuilder;
            if (toolbarBuilder == null)
                builder = new ToolbarBuilder().AddAll();
            tvc.BuildToolbar(builder);
            tvc.SetHTML(html);

			UINavigationController nav = null;
			foreach (var vc in UIApplication.SharedApplication.Windows[0].RootViewController.ChildViewControllers) {
				if (vc is UINavigationController) {
					nav = (UINavigationController)vc;
					break;
				} else if (vc is PhoneMasterDetailRenderer) {
					PhoneMasterDetailRenderer renderer = vc as PhoneMasterDetailRenderer;
					nav = findNavControllerRecursive(renderer.ViewController.ChildViewControllers);
					if (nav != null) {
						break;
					}
					break;
				} else if (vc is TabletMasterDetailRenderer) {
					TabletMasterDetailRenderer renderer = vc as TabletMasterDetailRenderer;
					nav = findNavControllerRecursive(renderer.ViewController.ChildViewControllers);
					if (nav != null) {
						break;
					}
					break;
				}
            }
            
			if (nav != null) { 
				tvc.NavigationItem.SetRightBarButtonItem(new UIBarButtonItem("Done", UIBarButtonItemStyle.Done, async (item, args) => {
					nav.PopViewController(true);
					taskRes.SetResult(await tvc.GetHTML());
				}), true);
	
				nav.PushViewController(tvc, true);
			}
			
            return taskRes.Task;
        }

		UINavigationController findNavControllerRecursive(UIViewController[] input) {
			UINavigationController nav = null;
			foreach (UIViewController each in input) {
				if (each is UINavigationController) {
					nav = each as UINavigationController;
					break;
				}
				nav = findNavControllerRecursive(each.ChildViewControllers);
			}
			return nav;
		}
    }

@bie5865
Copy link
Author

bie5865 commented May 1, 2017

Thank you thank you, that worked perfect!

@HugoSanchezGarcia
Copy link

Hi! I'm trying to apply the solution exposed by @swansca79 but when my plc calls TEditor.CrossTEditor.Current.ShowTEditor it seems that it's not firing the ios overrided one... so the editor never shows up in IOS... Any clue? Detailed example?
How did you achieved it @bie5865 ?
Thanks!

@WilliamRigby
Copy link

WilliamRigby commented May 29, 2017

I'm having a similar problem where I call this new overrided function in my iOS project using the Xamarin Dependency service, and it still doesn't show up. The function call never returns, but an error is not thrown. It's like the Thread just exits or something. The editor shows up in the sample app though. I don't see what could be different unless there is an issue with executing on the UIThread.

Here is where I'm pushing the new page on the stack:

await Navigation.PushAsync(new ContentPage { Content = new InterviewRichTextEditor() });

Here is my code Xamarin.Forms StackLayout class that is calling the iOS specific things. It's this first line that is never being returned from:

`

string html = await DependencyService.Get<IRichTextEditor>().CallShowTEditor("<!-- This is an HTML comment --><p>This is a test of the <strong>TEditor</strong> by <a title=\"XAM consulting\" href=\"http://www.xam-consulting.com\">XAM consulting</a></p>");
if (!string.IsNullOrEmpty(html))
        {
            _displayWebView.Source = new HtmlWebViewSource() { Html = html };
        }

`

Here is my interface:

`

public interface IRichTextEditor
{
    Task<string> CallShowTEditor(string html, ToolbarBuilder toolbarBuilder = null);
}

`

Here is my implementation in the iOS project:

`

    [assembly: Xamarin.Forms.Dependency(typeof(iOSRichTextEditor))]
    namespace Kindred.IntegriTrack.Mobile.iOS
    {
    public class iOSRichTextEditor : BaseTEditor, IRichTextEditor
    {

    public iOSRichTextEditor() { }

    public Task<string> CallShowTEditor(string html, ToolbarBuilder toolbarBuilder = null)
    {
        Task<string> temp = null;
        Xamarin.Forms.Device.BeginInvokeOnMainThread( () => {
            temp = ShowTEditor(html, toolbarBuilder);
        });
        return temp;
    }

    public override Task<string> ShowTEditor(string html, ToolbarBuilder toolbarBuilder = null)
    {
        TaskCompletionSource<string> taskRes = new TaskCompletionSource<string>();
        var tvc = new TEditorViewController();
        tvc.Title = "what";
        ToolbarBuilder builder = toolbarBuilder;
        if (toolbarBuilder == null)
            builder = new ToolbarBuilder().AddAll();
        tvc.BuildToolbar(builder);
        tvc.SetHTML(html);

        UINavigationController nav = null;
        foreach (var vc in UIApplication.SharedApplication.Windows[0].RootViewController.ChildViewControllers)
        {
            if (vc is UINavigationController)
            {
                nav = (UINavigationController)vc;
                break;
            }
            else if (vc is PhoneMasterDetailRenderer)
            {
                PhoneMasterDetailRenderer renderer = vc as PhoneMasterDetailRenderer;
                nav = findNavControllerRecursive(renderer.ViewController.ChildViewControllers);
                if (nav != null)
                {
                    break;
                }
                break;
            }
            else if (vc is TabletMasterDetailRenderer)
            {
                TabletMasterDetailRenderer renderer = vc as TabletMasterDetailRenderer;
                nav = findNavControllerRecursive(renderer.ViewController.ChildViewControllers);
                if (nav != null)
                {
                    break;
                }
                break;
            }
        }

        if (nav != null)
        {
            tvc.NavigationItem.SetRightBarButtonItem(new UIBarButtonItem("Done", UIBarButtonItemStyle.Done, async (item, args) => {
                nav.PopViewController(true);
                taskRes.SetResult(await tvc.GetHTML());
            }), true);

            nav.PushViewController(tvc, true);
        }

        return taskRes.Task;
    }

    UINavigationController findNavControllerRecursive(UIViewController[] input)
    {
        UINavigationController nav = null;
        foreach (UIViewController each in input)
        {
            if (each is UINavigationController)
            {
                nav = each as UINavigationController;
                break;
            }
            nav = findNavControllerRecursive(each.ChildViewControllers);
        }
        return nav;
    }

}
}

`

@swansca79
Copy link

I'm not sure if you can override the method in that manner when the source is in a nuget package. I think it has to do with the bait and switch technique used for most Xamarin packages. I made several changes to the source and created my own package that I use locally. I would assume @bie5865 did the same.

@WilliamRigby
Copy link

I'm not convinced that the override function really addresses the problem I'm having, since a separate Xamarin Forms application ran fine with the TEditor. Are there different Xamarin Forms startup options that I should be aware of? For example we are starting the App with a NavigationPage:

 MainPage = new NavigationPage(new LogInPage());

@swansca79
Copy link

There are other options, like a TabbedPage or a MasterDetailPage, that's what my code snippet is fixing. Since you are using NavigationPage, you shouldn't need to change anything. The original problem for this issue was launching the editor from a Modal page, so just make sure you aren't doing that.

@WilliamRigby
Copy link

Would it be possible to send you a zipped up simple project where I have been able to replicate the behavior? The whole project is just two pages, with a MastersDetail page, and each page is getting called via the MD page. The behavior of the editor not showing up and the thread just dying exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants