3

I am trying to implement Ooui in order to make my viewmodels supports ASP.NET Core and to target the web. I have a class library who is share across WPF, Xamarin.Forms using the MvvmLight framework. So i try to get the better approach for ooui. An advise will be apprecieted. For now i am not able to make the DisplayAlert work on every pages.

public class BaseController : Controller, IDialogService, INavigationService
{
    private static Stack<Page> _stack = null;

    protected Page CurrentPage => page.Navigation.NavigationStack.LastOrDefault();
    protected Page RootPage => page.Navigation.NavigationStack.FirstOrDefault();

    static BaseController()
    {
        _stack = new Stack<Page>();
    }

    private IHttpContextAccessor _service;
    private IApplicationBuilder app;
    protected NavigationPage page;


    private HttpContext Context
    {
        get { return _service.HttpContext; }
    }

    public string CurrentPageKey => throw new NotImplementedException();

    public BaseController()
    {
        if (!SimpleIoc.Default.IsRegistered<IDialogService>())
            SimpleIoc.Default.Register<IDialogService>(() => this);

        if (!SimpleIoc.Default.IsRegistered<INavigationService>())
            SimpleIoc.Default.Register<INavigationService>(() => this);

        _service = SimpleIoc.Default.GetInstance<IHttpContextAccessor>();
        app = SimpleIoc.Default.GetInstance<IApplicationBuilder>();
    }

    public async Task ShowError(string message, string title, string buttonText, Action afterHideCallback)
    {
        await CurrentPage.DisplayAlert(title, message, buttonText);
        afterHideCallback();
    }

    public async Task ShowError(Exception error, string title, string buttonText, Action afterHideCallback)
    {
        await CurrentPage.DisplayAlert(title, error.Message, buttonText);
        afterHideCallback();
    }

    public async Task ShowMessage(string message, string title)
    {
        await CurrentPage.DisplayAlert(title, message, "OK");
    }

    public async Task ShowMessage(string message, string title, string buttonText, Action afterHideCallback)
    {
        await CurrentPage.DisplayAlert(title, message, buttonText);
        afterHideCallback();
    }

    public async Task<bool> ShowMessage(string message, string title, string buttonConfirmText, string buttonCancelText, Action<bool> afterHideCallback)
    {
        var result = await page.DisplayAlert(title, message, buttonConfirmText, buttonCancelText);
        afterHideCallback(result);
        return result;
    }

    public async Task ShowMessageBox(string message, string title)
    {
        await CurrentPage.DisplayAlert(title, message, "OK");
    }

    public void GoBack()
    {
        page.PopAsync();
        page.PushAsync(_stack.Pop());
    }

    public void NavigateTo(string pageKey)
    {
        _stack.Push(CurrentPage);

        page.PopAsync();            
        page.PushAsync(SimpleIoc.Default.GetInstance<Page>(pageKey));
    }

    public void NavigateTo(string pageKey, object parameter)
    {
        throw new NotImplementedException();
    }
}



public class HomeController : BaseController
    {        
        public HomeController()
            : base()
        {
            SimpleIoc.Default.Register<Page>(() => new Next(), "Next");
            SimpleIoc.Default.Register<Page>(() => new MainPage(), "MainPage");
        }

        public IActionResult Index()
        {
            page = new NavigationPage(new MainPage());            
            //NavigateTo("MainPage");
            return new ElementResult(page.GetOouiElement(), "Hello from XAML!");
        }

        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
Cédric B
  • 77
  • 8
  • What is the error you are getting exactly? – Bruno Caceiro Sep 27 '18 at 16:17
  • I ain't got no error (only the dialog isn't display on each page) but i am trying to take the best approach. I am have to get a single controller like or maybe use a different way. I came across UI.Publish so i guess this is maybe a better for navigating threw xamarin pages. – Cédric B Sep 27 '18 at 19:11
  • But is any dialog displaying at all? – Bruno Caceiro Sep 27 '18 at 20:37
  • Did you put a breakpoint to see if the methods are being called? – Bruno Caceiro Sep 27 '18 at 20:38
  • Yes, the methods are called. The dialog is displayed but i can't click on it. It seems like it's not rendering in the front. I am able to display the dialog and to click on it on the mainpage but not to click on the next page. – Cédric B Sep 27 '18 at 21:24
  • @CédricB Could you post a project with reproducable issue? I suspect `CurrentPage` property is not referencing proper page and hence issue occurs. – Dipen Shah Sep 28 '18 at 04:20
  • 1
    so your dialog is rendered but it isn't in the front? have you tried the css property `z-index` ? – товіаѕ Oct 02 '18 at 08:01
  • @TobiasWürth That's it ! Thank you, i apply a z-index on the dialog that works. – Cédric B Oct 02 '18 at 18:21
  • I'm glad to hear it helped, I posted a proper answer explaining this. – товіаѕ Oct 03 '18 at 07:36
  • Well, unfortunalety. I only can set the z-index property threw dev-mode in chrome. I am not able to do this in ooui. It's using DialogModalService with angular it seems. So i try this with no success. https://stackoverflow.com/questions/38206928/angular-ui-modal-with-high-z-index-not-on-top – Cédric B Oct 03 '18 at 17:31

2 Answers2

0

Based on your comment my assumption was correct.

The dialog is rendered, but it is not displayed in the front. Defining the CSS property z-index on the element apparently solves the issue.

If this is given as HTML ...

<div class="most-top"> ... </div>

.. your css could look like this ..

.most-top {
    z-index: 99;
}
товіаѕ
  • 2,881
  • 4
  • 23
  • 53
  • I am not able to dialog with rendering it seems, across XamarinPages. See my answer up on. I delete all css folders in my solution and in still working. I don't know how xamarin pages deal with html rendering. – Cédric B Oct 03 '18 at 17:34
  • oh, too bad. i don't have another idea then – товіаѕ Oct 04 '18 at 05:47
  • I finally came across StyleSheet in xamarin project. I am able to add the stylesheet to the page but i can't access the modal-dialog. After examine of the source-code, there is no angular.js. I don't know how to assign the resource threw the DisplayAlert. – Cédric B Oct 10 '18 at 10:59
  • @CédricB I'm not sure if I got this right. You can define a css style which gets added to the page, but you cannot modify how the alert gets rendert (e.g. for defining a css class)? have you tried working with css child selectors? e.g. `#wrapper > div` to select the alert div indirectly? – товіаѕ Oct 10 '18 at 11:41
0

I finally came up the thing !!!

public abstract class OouiMvcProgram<T> : Controller where T : class {
    private string MainRoute => "{controller=" + typeof(T).Name + "}/{action=StartUp}/{id?}";
    private string ErrorRoute => $"/{typeof(T).Name}/Error";

    private static XamarinOouiApplication _xamarinApplication = null;

    /// <summary>
    /// The main path to display
    /// </summary>
    protected abstract string MainPageName { get; }

    /// <summary>
    /// Title of the window
    /// </summary>
    protected abstract string Title { get; }

    private static XamarinOouiService Navigation => _xamarinApplication.Service;

    /// <summary>
    /// Let's start the xamarin application
    /// </summary>
    /// <param name="xamarinApplication">Xamarin application</param>
    /// <param name="args"></param>
    public static void StartApplication(XamarinOouiApplication xamarinApplication, string[] args)
    {
        _xamarinApplication = xamarinApplication;

        MessagingCenter.Subscribe<Page, AlertArguments>
            (_xamarinApplication, Page.AlertSignalName, PatchDisplayAlert);

        WebHost.CreateDefaultBuilder(args)
           .UseStartup<T>()
           .Build()
           .Run();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="sender">Calling page</param>
    /// <param name="arguments"></param>
    private static void PatchDisplayAlert(Page sender, AlertArguments arguments)
    {
        //DisplayAlert on z-index
        var element = Navigation.CurrentPage.GetOouiElement();
        if (element.GetAttribute("style") == null)
            element.SetAttribute("style", "{z-index:9999;}");
    }

    /// <summary>
    /// This method gets called by the runtime. 
    /// Use this method to add services to the container.
    /// For more information on how to configure your application, 
    /// visit https://go.microsoft.com/fwlink/?LinkID=398940
    /// </summary>
    /// <param name="services"></param>
    public virtual void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    }

    /// <summary>
    /// This method gets called by the runtime. 
    /// Use this method to configure the HTTP request pipeline.
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    public virtual void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler(ErrorRoute);
        }

        app.UseOoui();
        app.UseMvc(routes => routes.MapRoute("default", MainRoute));
    }

    public IActionResult StartUp()
    {
        Navigation.Start(MainPageName);

        var element = Navigation.MainPage.GetOouiElement();

        Navigation.CurrentViewModel?.OnOouiServiceEnabled();

        return new ElementResult(element, Title);
    }        

    public IActionResult Error()
    {
        var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
        return new ElementResult(GetErrorPage(exceptionFeature).GetOouiElement(), Title);
    }

    /// <summary>
    /// Get the details of the exception that occurred
    /// https://scottsauber.com/2017/04/03/adding-global-error-handling-and-logging-in-asp-net-core/
    /// </summary>
    /// <param name="exceptionFeature"></param>
    /// <returns></returns>
    protected virtual ContentPage GetErrorPage(IExceptionHandlerPathFeature exceptionFeature)
    {
        var errorPage = new ContentPage();
        if (exceptionFeature != null)
        {
            // Get which route the exception occurred at
            string routeWhereExceptionOccurred = exceptionFeature.Path;

            // Get the exception that occurred
            Exception exceptionThatOccurred = exceptionFeature.Error;

            // TODO: Do something with the exception
            // Log it with Serilog?
            // Send an e-mail, text, fax, or carrier pidgeon?  Maybe all of the above?
            // Whatever you do, be careful to catch any exceptions, otherwise you'll end up with a blank page and throwing a 500
            errorPage.Content = new Xamarin.Forms.Label()
            {
                Text = routeWhereExceptionOccurred + "\n" +
                       exceptionThatOccurred.Message
            };
        }
        return errorPage;
    }                

    public UITarget FindByName(string name)
    {
        var target = Navigation.CurrentPage.GetEventTarget(name);
        return new UITarget(
            add:
            (eventType, handler) => target.AddEventListener(eventType, 
            (element, args) => handler.Invoke(element, args)),

            remove:
            (eventType, handler) => target.RemoveEventListener(eventType, 
            (element, args) => handler.Invoke(element, args)));
    }
}
Cédric B
  • 77
  • 8