Implementing acr.UserDialogs in Xamarin.Forms with mvvmlight - c#

For school we are developing a mobile app with Xamarin Forms.
We use mvvmlight in the project.
Now I was looking around for how to show dialogs, alerts etc. and stumbled upon acr.UserDialogs which has everything we need.
I added
UserDialogs.Init(this); to my MainActivity.cs
And when I try to register it in my ViewModelLocator:
SimpleIoc.Default.Register<IUserDialogs, UserDialogs>();
This doesn't work because UserDialogs is Static type.
I found a similiar question Here
Which gives the following suggestion
SimpleIoc.Default.Register<IUserDialogs>(UserDialogs.Instance);
But this doesn't work neither.
Anyone got any other suggestions?
Thanks

Try this way. I just tested in my environment and it works fine for me.
Put this in your MainActivity
Acr.UserDialogs.UserDialogs.Init(this);
And Bind your dialog with command in your viewmodel
private RelayCommand _yourCommand;
public RelayCommand YourCommand{
get{
return _yourCommand
?? (_yourCommand = new RelayCommand( async () => {
UserDialogs.Instance.ShowLoading("TEST");
}
}
}
I do not register arc.UserDialog in my ViewModelLocator but register 'IDialogService'
public ViewModelLocator()
{
...
SimpleIoc.Default.Register<IDialogService, DialogService>();
...
}
And My ViewModel
public class MyViewModel : ViewModelBase
{
...
private IDialogService _dialogService;
...
//ViewModel Constructor
public SignUpViewModel(INavigationService navigationService, IDialogService dialogService){
_dialogService = dialogService;
}
}

Related

Pop up a view and transfer parameters to original one with caliburn.micro

I used caliburn.micro version 4.0.173 and .NET framework 4.8.
Requirement is as below description
I have a script ViewModel. There is a button to click it and pop up a setting ViewModel.
After setting ViewModel appear, it can be setup some parameters and click button to confirm these settings. When confirm button is clicked, it can trigger to script ViewModel from setting ViewModel.
I refer this link to do this. To create a class is for event in project folder. But, when I publish in setting View, that doesn't work to subscribe in Handle of script viewmodel. How can I pass these parameters to another view model?
Thank you.
Event
public class FooEvent
{
public bool Foo { get; set; }
public FooEvent(bool foo)
{
Foo = foo;
}
}
Setting ViewModel
public class SettingViewModel : Screen
{
private IEventAggregator _eventAggregator;
public ItemViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
public void PublishFooEvent()
{
_eventAggregator.PublishOnUIThreadAsync(new FooEvent(true));
}
public void BtnSaveItem()
{
PublishFooEvent();
}
}
Script ViewModel
public class ScriptViewModel : Screen, IHandle<FooEvent>
{
private readonly IEventAggregator _eventAggregator;
[ImportingConstructor]
public ScriptViewModel(IEventAggregator eventAggregator)
{
this._eventAggregator = eventAggregator;
_eventAggregator.SubscribeOnUIThread(this);
}
public void Handle(FooEvent fooEvent)
{
}
}
I find out that problem is in other handle.
When I added interface and fixed error automatically.
IDE creates a new method (HandleAsync) which I didn't notice it.
Therefore, I type another handle manually.
It always works on HandleAsync after trigger with another viewmodel.

Using MvvmLight.Messaging.Messenger to instantiate new View + ViewModel (Window)

I have my MainView and an associated MainViewViewModel which are linked by ViewModelLocator.
Within MainViewViewModel there is a command which should trigger a new Window to open which has it's own View and ViewModel (NewView and NewViewViewModel).
In a lot of the examples I've seen it is suggested to use Mvvmlight's Messenger to do something like this:
public class MainViewViewModel
{
private void OpenNewWindow()
{
Messenger.Default.Send(new NotificationMessage("NewView"));
}
}
And then register the NewViewViewModel and handle the message like this:
public class NewViewViewModel
{
public NewViewViewModel()
{
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}
private void NotificationMessageReceived(NotificationMessage obj)
{
if (obj.Notification == "NewView")
{
NewView view = new NewView();
view.Show();
}
}
}
However, this doesn't work because the NewViewViewModel isn't yet instantiated (so isn't registered with Messenger). Additionally, this doesn't fit with MVVM because NewViewViewModel is responsible for creating NewView.
What is the correct way to achieve a simple command which instantiates and opens a new View and ViewModel pair which are linked via ViewModelLocator and setting of DataContext="{Binding NewView, Source={StaticResource Locator}}" in NewView.xml?
Use a window service:
MVVM show new window from VM when seperated projects
You may either inject the view model to with an IWindowService implementation or use a static WindowService class:
public static class WindowService
{
public static void OpenWindow()
{
NewView view = new NewView();
view.Show();
}
}
Dependency injection is obviously preferable for being able to unit test the view model(s) and switch implementations of IWindowService at runtime.

WPF MVVM compliant way to open views

I would love to find a simple and MVVM compliant way,
to open a new view from the MainWindow.
I have already worked through some instructions and tutorials.
But somehow none really worked or it was a mixture of code behind.
I would like to open a view after pressing a button and edit an ObservableCollection in it.
I have already created DataTemplates in App.xaml and mapped the ViewModels with the respective views.
But I don't know how to cleanly open a separate window from the MainWindow (MainViewModel) via an ICommand for another ViewModel.
You should't open a window directly from the MainWindow nor the MainWindowViewModel. But the view model may use a service to open a window:
public class MainWindowViewModel
{
private readonly IWindowService _service;
public MainWindowViewModel (IWindowService service)
{
_service = service;
}
//...
public void OpenWindowExecuted()
{
_service.ShowWindow();
}
}
Service:
public interface IWindowService
{
void ShowWindow();
}
public class WindowService : IWindowService
{
public void ShowWindow();
{
Window window = new Window()
window.Show();
}
}
You could easily mock out the service in your unit tests.

RegionManager.RequestNavigate only gets me System.Object?

I need to add some features to a WPF Project a retired colleague of mine made. Tried to copy the Navigation Features but they won´t work like they should.
I want to open my own XAML File in the Main Window but all I get is System.Object.
Here I register the Views as:
public override void Initialize()
{
UnityContainer.RegisterType<RelationView>();
UnityContainer.RegisterType<RelationNavigationItemView>();
UnityContainer.RegisterTypeForNavigation<RelationView>();
RegionManager.RegisterViewWithRegion(RegionNames.NavigationRegion, typeof(RelationNavigationItemView));//this works out fine appears in the Navigation Part
}
The RelationNavigationItemView is simply a button which should open the RelationView in the MainWindow.
Which should happen here as:
private static Uri RelationViewUri = new Uri("/RelationView", UriKind.Relative);
private IRegionManager _regionManager;
private DelegateCommand _navigateCommand;
public RelationNavigationViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public ICommand NavigateCommand
{
get
{
return _navigateCommand ?? (_navigateCommand = new DelegateCommand(NavigateCommandExecute, NavigateCommandCanExecute));
}
}
private bool NavigateCommandCanExecute()
{
return true;
}
private void NavigateCommandExecute()
{
_regionManager.RequestNavigate(RegionNames.MainContentRegion, RelationViewUri); //Here should the new window appears and the ViewModel Constructor should be called but nothing happens, I only get System.Object in the MainContentRegion
}
The Project runs with Prism Version 6.3.
I hope, someone can help me.
Thanks and Best Regards, Max.
You should just navigate to ´"RelationView"`. No need for uri here, it just adds potential for errors.
Thanks Guys it works now. The Constructor was Wrong.
I expected an UnityContainer instead of a IUnityContainer.

MVVM light, send message via Messenger from ViewModel to new child window, which is not initialized yet

I've following architecture:
desktop application, .Net 4.5, C#, WPF, MVVM Light, Messenger, IoC - ViewModel locator, so ViewModels doen't know anyhing about Views.
I have main view with data grid of some elements, and I want to display details of each individual element in new/child windows after double click on data grid.
I've bind event double click on main view to main view model. From this event handler in main view model, message is sent via Messanger.
New view (new/child window) is created in main view via delegate of also double click.
New/child window is a view which locate his view model and this view model register to the specific message in his constructor.
The problem is that new/child window (new view, and view model so on) is created too late, because message is already sent when new view model register for it.
Do you know maybe some patterns for such architecture. Any ideas will be appreciated.
It would help to know exactly what you try to do.
If your problem is just to display a detailed Window when double click on a row, I would say: create only one childWindow at start, and play with its visbility when required.
If you really need a new window each time, you could create it from your viewModel with an injected service for example.
In any case, you never has to create your window from main view! Either you create one window at start, either you dynamically create it from view model.
You cannot hope to create it from view and send the message in your view model.
Edit about the injected service, you could use something like that:
public interface IWindowService
{
void Open<TWindow>(ViewModelBase viewModel)
where TWindow : Window;
}
public class WindowService : IWindowService
{
private readonly IUIDispatcher _dispatcher;
public WindowService(IUIDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void Open<TWindow>(ViewModelBase viewModel)
where TWindow : Window
{
_dispatcher.Run(() => OpenThreadSafe<TWindow>(viewModel));
}
private static void OpenThreadSafe<TWindow>(ViewModelBase viewModel) where TWindow : Window
{
var view = (TWindow) Activator.CreateInstance(typeof(TWindow), viewModel);
view.Show();
}
}
public class UIDispatcher : IUIDispatcher
{
public void Run(Action action)
{
var dispatcher = DispatcherHelper.UIDispatcher;
if (dispatcher == null)
{
action();
return;
}
DispatcherHelper.CheckBeginInvokeOnUI(action);
}
Note this DispatcherHelper come from MVVMlight, but you could erplace it easily.
Hope it helps.
The problem is that the ViewModel Locator creates the viewmodel instance only when it is needed (lazy loading).
just configure the ViewModelLocator to instantiate the viewmodel eager instead of lazy. This is done by passing the parameter "true" to the IoC Container.
Sample:
namespace Administration.ViewModel
{
public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
//Eager Loading
SimpleIoc.Default.Register<UserManagementViewModel>(true);
//Lazy Loading
SimpleIoc.Default.Register<InformationManagementViewModel>();
}
public UserManagementViewModel UserManagementViewModel
{
get
{
return ServiceLocator.Current.GetInstance<UserManagementViewModel>();
}
}
public InformationManagementViewModel InformationManagementViewModel
{
get
{
return ServiceLocator.Current.GetInstance<InformationManagementViewModel>();
}
}
public static void Cleanup()
{
SimpleIoc.Default.Unregister<UserManagementViewModel>();
SimpleIoc.Default.Unregister<InformationManagementViewModel>();
}
}
}

Categories

Resources