0

I am building a Xamarin.Forms application with Prism, it shows what Bluetooth devices are connected.

In this application, I need a footer in all the pages showing the connection status of the device. To do that, I’ve made a static class called Pen with the property IsConnected updated from the BleService.

I also need a button in the footer that is visible when the Pen is disconnected and when it is pressed I can call the Connect method of the BleService.

For the footer, I’ve made a ControlTemplate in the App.xaml containing a button.

Now, I’m using Prism and I don’t know how to bind the button to a ViewModel (App.xaml does not have a ViewModel) in order to call the Connect Command of the BleService.

Iain Smith
  • 9,230
  • 4
  • 50
  • 61
Andufer
  • 1
  • 1

2 Answers2

0

The App.xaml and App.aml.cs files contain the logic required to configure a Prism application and navigate to the root page on startup.

From the documentation

So you cant create a ViewModel for this as it's not a View and this would break the MVVM pattern. Prism is an MVVM framework, that works by loading Views (And their ViewModels) through a Navigation Service. So this approach for a "global" view is not going to work with binding.

Creating a control template is not going to fix this either, it just allows you to have a reusable template defined in the app.xaml.

What I would suggest is to either:

  1. Add this footer to all views, which is a bit of an overhead.

OR

  1. Show a popup when the BleService changes rather than having a footer view.

Another option would be to create some custom renders. You can do this natively on iOS adding the View to the RootViewController. For the other platforms, I'm not too sure, so you could go down some custom renderer road to try to get it with a footer but I don't think it is worth the headache.

Again not ideal solutions but some platforms can control this very well so I can see why Xamarin.Forms doesn't have this, built in.

Community
  • 1
  • 1
Iain Smith
  • 9,230
  • 4
  • 50
  • 61
  • Thanks a lot. I opt for the first solution. I can't lose more time. – Andufer May 29 '19 at 08:14
  • What about creating a partial view with isVisible and pass it as true in the other pages when you want to show it. Much easier. – Ali123 May 29 '19 at 11:04
0

I found a solution, but I'd like to know what do you think about.

In the App.Xaml, in the Control Template, I've binded the Command of the connection button as you can see below:

<buttons:SfButton Grid.Column="0" Grid.Row="2"
    Command="{TemplateBinding Parent.BindingContext.ConnectCommand}"
    IsVisible="{Binding IsNotConnected, Source={x:Static local:Pen.Current}}"/>

Then I've modified the class ViewModelBase, so any new View will inherit the link to Bluetooth Service and the Command Execution:

public class ViewModelBase : BindableBase, INavigationAware, IDestructible
{
    protected INavigationService NavigationService { get; private set; }
    protected IBLEService BLEService { get; private set; }

    private string _title;
    public string Title
    {
        get { return _title; }
        set { SetProperty(ref _title, value); }
}

public ViewModelBase(INavigationService nS,IBLEService bS)
{
    NavigationService = nS;
    BLEService = bS;
}

public virtual void Destroy()
{
}

private DelegateCommand connectCommand;
public DelegateCommand ConnectCommand => connectCommand ?? 
    (connectCommand = new DelegateCommand(ExecuteConnectCommand));

async void ExecuteConnectCommand()
{
    await BLEService.Connect();
}

What do you think about? Thanks a lot and have a nice day, Andrea

Andufer
  • 1
  • 1