Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

access and open DisplayActionSheet from view model

i have a toolbar in my content page where there is one item called add , on clicking over add i want to open DisplayActionSheet

i have created ContentPage Toolbar in xaml and attached ICommand to it in view model. Now DisplayActionSheet is accessible only in View hence i am not sure how will i able to access it and render it from view model.

xaml file

<ContentPage.ToolbarItems>
    <ToolbarItem Name="" Icon="ic_add.png"    Order="Primary" Priority="0" Command="{Binding OnAddContactCommand}"/>
    <ToolbarItem Name="" Icon="ic_search.png" Order="Primary" Priority="1" Command="{Binding OnContactSearchCommand}" />
</ContentPage.ToolbarItems>

View model

public ICommand OnContactSearchCommand => new Command(OnContactSearch);
public ICommand OnAddContactCommand => new Command(OnAddContactSearch);

events

private async void OnAddContactSearch()
{   
   //var action = await DisplayActionSheet(AppResources.select_contact_source, AppResources.cancel, null, AppResources.manual, AppResources.phonebook);
}

private void OnContactSearch()
{
   Debug.WriteLine("OnContactSearch");
}
like image 925
Hunt Avatar asked Dec 23 '22 09:12

Hunt


2 Answers

Like @Alessandro said Application.Current.MainPage works fine for action sheets and alerts as well. To hide view specific stuff from view model I created an IMessageBoxService which is injected into the view models' contructors that need it. Note that I am using the Autofac IoC container. For Xamarin's DependencyService you have change the constructors and look up the service in code.

IMessageBoxService.cs

public interface IMessageBoxService
{
    void ShowAlert(string title, string message, Action onClosed = null);
    // ...
    Task<string> ShowActionSheet(string title, string cancel, string destruction, string[] buttons = null);
}

MessageBoxService.cs

public class MessageBoxService : IMessageBoxService
{
    private static Page CurrentMainPage { get { return Application.Current.MainPage; } }

    public async void ShowAlert(string title, string message, Action onClosed = null)
    {
        await CurrentMainPage.DisplayAlert(title, message, TextResources.ButtonOK);
        onClosed?.Invoke();
    }

    public async Task<string> ShowActionSheet(string title, string cancel, string destruction = null, string[] buttons = null)
    {
        var displayButtons = buttons ?? new string[] { };
        var action = await CurrentMainPage.DisplayActionSheet(title, cancel, destruction, displayButtons);
        return action;
    }
}

AppSetup.cs

    protected void RegisterDependencies(ContainerBuilder cb)
    {
        // ...
        cb.RegisterType<MessageBoxService>().As<IMessageBoxService>().SingleInstance();
    }

Usage

public class EditProductViewModel : AddProductViewModel
{
    private IMessageBoxService _messageBoxService;

    public ICommand DeleteCommand { get; set; }

    public EditProductViewModel(IPageNavigator navigator, IMessenger messenger,
        IMessageBoxService messageBoxService, TagDataStore tagDataStore) : base(navigator, messenger, tagDataStore)
    {
        _messageBoxService = messageBoxService;
        DeleteCommand = new Command(DeleteItem);
    }

...

    private async void DeleteItem()
    {
        var action = await _messageBoxService.ShowActionSheet(TextResources.MenuTitleDeleteProduct,
            TextResources.ButtonCancel, TextResources.ButtonDelete);
        if (action == TextResources.ButtonDelete)
        { } // delete

If you are doing viewmodel first navigation (s. Xamarin or Jonathan Yates' blog) you may chose to make this part of the Navigator service. It's a matter of taste

like image 103
Kay Avatar answered Dec 29 '22 00:12

Kay


try with

Application.Current.MainPage.DisplayActionSheet();
like image 31
Alessandro Caliaro Avatar answered Dec 28 '22 22:12

Alessandro Caliaro