Executing UI Code from ViewModel on MVVMCross - c#

I have just started using MvvmCross, but i didn't find any info about to how i can execute UI code from a ViewModel.
On Caliburn there are coroutine so i can access the view and keep the ui code separated from the viewmodel code.
on my first case i need to open a dialow from a command inside a ViewModel, what is the correct way?
Right now i'm developing a WinRT app.
Thanks

There isn't any hard/fast rule on this within MvvmCross.
Generally, when I need to do this I use the Messenger plugin.
This answer assumes you are using the latest Alpha v3 code. For older vNext code you'll have to do some translation - see notes below.
To use this approach:
I reference Cirrious.MvvmCross.Plugins.Messenger.dll from both Core and UI projects.
Then I add a line somewhere in Setup.cs (e.g. in InitializeLastChance) to:
Cirrious.MvvmCross.Plugins.Messenger.PluginLoader.Instance.EnsureLoaded();
Then in the Core project I add a message:
public class InputIsNeededMessage : MvxMessage
{
public InputIsNeededMessage(object sender) : base(sender) {}
}
In the ViewModel I can get the Messenger by constructor injection or by:
var messenger = Mvx.Resolve<IMvxMessenger>();
and I can send messages by calling:
messenger.Publish(new InputIsNeededMessage(this));
In the View I can again get to the messenger and subscribe to messages using:
var messenger = Mvx.Resolve<IMvxMessenger>();
_token = messenger.SubscribeOnMainThread<InputIsNeededMessage>(OnInputIsNeeded);
where _token must be a member variable - if it isn't then the subscription won't persist - the subscription itself is weak by default (so you never have to unsubscribe)
and where OnInputIsNeeded is something like:
private void OnInputIsNeeded(InputIsNeededMessage message)
{
if (message.Sender != ViewModel)
return;
// do stuff here - you are already on the UI thread
}
The above sequence is what I normally do for 'proper code'
To start with using a Messenger/EventAggregator can feel uncomfortable - it certainly took me a while to get used to it - but after I did get used to it, then I now use it everywhere - the pub/sub Message decoupling is very flexible for testing and for future maintenance of code (IMO)
As alternatives to this approach above I do sometimes take shortcuts:
sometimes I fire normal C# events from the ViewModel and have the View respond to these
sometimes I have special marker properties and fire the UI code from them
Sorry for using v3 syntax - but the changeover is coming and it's what I'm now coding in...
To switch back to vNext I think you might need to:
use IMessenger instead of IMvxMessenger
use BaseMessage instead of the MvxMessage
use Subscribe instead of SubscribeOnMainThread - but then you will need to marshall the message onto the UI thread yourself.

There exists an easier way. Here is the method I use for executing any action on the main
thread:
protected void RunOnUIThread(Action action) {
var dispatcher = Mvx.Resolve<IMvxMainThreadDispatcher>();
dispatcher.RequestMainThreadAction(action);
}
Hope it helps. Cheers.

Related

How to make a listener of a service on android

I have this code to check if a service is active, but I would like to know if there is any way for an EditText to show the status of the service, without making this query per second, or in a separate thread, or linking it in some way? that it is possible to detect if the service stopped
private bool MiServicioEstaCorriendo(Class #class, Context contexto)
{
ActivityManager manager = (ActivityManager)contexto.GetSystemService(Context.ActivityService);
foreach (ActivityManager.RunningServiceInfo service in manager.GetRunningServices(Integer.MaxValue))
{
if (#class.Name.Equals(service.Service.ClassName))
{
Log.Info(typeof(BroadcastGps).Name, "MiServcicioEstaCorriendo: true");
return true;
}
}
Log.Info(typeof(BroadcastGps).Name, "MiServcicioEstaCorriendo: false");
return false;
}
You are basically in need of a way to pass events/messages among classes within your application. So this question probably goes down to Android & C# implementation of such a pattern. Xamarin.Forms has a MessagingCenter class, but since you are using Xamarin.Native, you would have to create something yourself
There's nothing actually already baked in to Android or C#, but so you can implement one of the most common ways to let a class spread an event/message using the "Listener" (term used in Android) or "Delegate" (term used in C#) technique.
There are frameworks too like PubNub that you can use as Nuget packages that simplify everything for you.
Some more resources to understand the concept: Wikipedia, IBM.
And Some Android resources: Handlers, AsyncTasks, Parcelables.
Don't forget that your event to update your EditText may not be fired on the Main UIThread so you won't be able to see the changes unless you force that update line to be Run on UI Thread.

WPF - Can I add a click event to multiple windows?

I'm stumbling my way through my first WPF desktop application using C# and am trying to stick to good programming practice by not repeating code. I've come a little unstuck when trying to add an event handler to buttons in different windows.
I have two windows (named 'MainWindow' and 'ViewContent') which both contain buttons to exit the application.
The buttons are both identical in XAML, and are created in separate windows:
<Button Click="Exit_Application" />
The event handler for a button click will then run:
public void Exit_Application(object sender, RoutedEventArgs e)
{
// Exit the application
System.Windows.Application.Current.Shutdown();
}
This works when I include the 'Exit_Applicaiton' method in the code-behind for both windows, but I was hoping to only have to include this method once and be able to use it globally. I've searched around and can't seem to find any information on using click event handlers globally, Is this possible?
Any help would be greatly appreciated.
There are a few ways to handle this scenario (listed below), however I would recommend looking into the MVVM pattern to help clarify how to structure your application.
1. Shared method within App
Create a public method (example below) within the App class (typically App.xaml.cs in the project root). The App class is accessible from anywhere within your application so could be used to share exit logic that can be triggered from multiple <Window\>.
public void Shutdown()
{
// Insert any code that needs to run before shutdown
System.Windows.Application.Current.Shutdown();
}
From within each <Window\> you could call App.Shutdown() to exit the application.
2. Decide code sharing is not needed for this case
If the only line of code that needs to run when a user exits your application is System.Windows.Application.Current.Shutdown(); then there is no need to "share" this code. There is no logic within this code therefore calling this method from both <Window\> could be just fine.
The fact that you're using click events on buttons and asking the question means you don't understand commands in wpf. Commands in particular, binding and resources are the big plusses of using WPF. If you're not using these then that's ok for a trivial application but commercial teams use MVVM and even a hobby app of any substance will benefit from adopting this.
There is, however, a learning curve and if you're only ever writing one app then learning MVVM might not be worthwhile.
Either way, you can use a command by binding the command property of your buttons to a class implements icommand.
Usually, a command will be doing something or other with data and you'd be working with a viewmodel so a simple command would be in a property of a viewmodel like:
https://social.technet.microsoft.com/wiki/contents/articles/32164.wpf-mvvm-step-by-step-2.aspx
In this case your command doesn't need any data and is just working with the app. Which you can do from any piece of code.
You can therefore use a static class implements icommand. That could be just directly in the class or by using a library already does this for you - like MVVM light.
From this thread:
WPF Commands, How to declare Application level commands?
Here's a simple implementation:
class MyCommand : ICommand
{
// Singleton for the simple cases, may be replaced with your own factory
public static ICommand Instance { get; } = new MyCommand();
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
System.Windows.Application.Current.Shutdown();
}
}
you can declare in MainWindow (or another class) static ICommand ExitAppCommand and use it
class:
public static ICommand ExitAppCommand { get; } = new ActionCommand(() => System.Windows.Application.Current.Shutdown());
XAML:
<Button Command="{x:Static youClassNamespace:youClass.ExitAppCommand}">

mvvmlight messenger strange behaviour

I have a strange behavior in my project. I use MvvmLight messenger to notify different parts of my UI to update.
public EntryViewModel(MenuViewModel menuVM, Entry item)
{
this._menuVM = menuVM;
OpenDetailsCommand = new RelayCommand(OpenDetailsInMainWindow);
BackCommand = new RelayCommand(Back);
this._entry = item;
Refresh();
Messenger.Default.Register<CardUpdateMessage>(this, this._entry.Id, msg => Refresh(); );
}
and send with
Messenger.Default.Send(new CardUpdateMessage(id), id);
when I see Messenger content after registration it contains about 400 registered actions of CardUpdateMessage, but when I call send none of them fires.
By the way, similar code with single registered object per Message type work as I expect. What is the cause of this problem?
Update: I have made some research with debugger and found that in file https://mvvmlight.codeplex.com/SourceControl/latest#GalaSoft.MvvmLight/GalaSoft.MvvmLight (PCL)/Messaging/Messenger.cs method SendToList is fired and in its inner loop WeakAction is fired, but Refresh method is not run. Does it something I haven't suspected with WeakAction?
Solution: I have found the case of this issue. It's NOT ALLOWED to use anonimous function in Messenger.Register due to unexpected behavior.
just Messenger.Default.Register(this, this._entry.Id, Refresh); and
private void Refresh(CardUpdateMessage msg) ...
External reference: https://mvvmlight.codeplex.com/workitem/7640
This is the answer https://mvvmlight.codeplex.com/workitem/7640 and this
Strange behavior with actions, local variables and garbage collection in MVVM light Messenger
Solution in short words - do no use lambdas in Messenger.Default.Register, because the can behave not as you expected.

Where to initialize PCL instanced in a Xamarin.iOS app?

I'm working on a Xamarin application, which I will at first have working on iOS, but plan to later expand to Android and other mobile platforms.
As such, I'm trying to keep as much common code in PCLs as possible.
My question: what is the best practise - in Xamarin.iOS for now - to initialize any dependent PCL code?
For now I have it in the RootViewController inside ViewDidLoad()
public override void ViewDidLoad()
{
base.ViewDidLoad();
_engine = new MyEngine();
View = new MainView(_engine);
}
Is this the right spot? I'd considered putting it in the ctor for the RootViewController, but there's a fair bit going on in the initialization code, which thus ran against "don't put heavy duty init code into a constructor".
Things that happen are:
Load app settings
If app is run for first time ever, load basic defaults
Initialise other PCL libraries, such as a TextToSpeech module, a state engine (hence the name of the class above), etc
Prepare a data grid based on XML or JSON input
Alternately, I though it should possibly go into the AppDelegate section, but that didn't sound right.
I'm still fairly new to mobile app dev in general and Xamarin in specific, though I've done C# native code for Windows for years. I just want to make sure I follow best practises, but there doesn't seem to be a "thou shalt" in this case.
Edit: I've extracted the solution based on #wishmaster's suggestions.
For iOS the Appdelegate method is the best place for initialization code. The appdelegate also provides multiple delegate methods to give you feedback on application lifecyle events such as the method "DidFinishLauchingWithOptions"
. if you have a lot of data to download or long running tasks that your app depends on I would suggest you take a look backgrounding for iOS.
A technique I have also used is for my first viewcontroller on IOS (or activity on Android) to display a splash screen and a loading indicator while i run some code to refresh the cache.
Using #wishmaster's pointers, this solution works like a charm:
In AppDelegate.cs
// in the global section put any data you may make available elsewhere
private var _engine;
public Engine => _engine;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
/*
* Do whatever init needs to happen here, if you need to make this
* available elsewhere, ensure you have properties or accessors,
* as above.
*/
_engine = new MyEngine();
return true;
}
Then in RootViewController.cs using a similar approach to these examples in Obc-C or Swift you can access the information through a property pointing at the AppDelegate.
var myappdelegate = UIApplication.SharedApplication.Delegate as AppDelegate;
var engine = myappdelegate.Engine;
View = new MainView(engine);
The result resulted in a snappier start up of the application, because the initialisation now happens during the splash screen and no longer between splash screen and appearance of the UI.

Race condition with asynchronous service initialization

I'm working in C# WPF with a proprietary framework (essentially a blend of Caliburn Micro and Castle Windsor) and I've got two singleton modules that have a race condition:
DeviceService - A service that manages a connection to a physical device emitting data. The service is "Startable" and hence is automatically constructed and initialized asynchronously.
ConnectionIndicatorViewModel - A client ViewModel that chiefly concerns itself with communicating to the user the status of the connection managed by DeviceService. Changes state mainly based on events fired by DeviceService.
My problem lies at application startup. In the constructor for the ViewModel, I set the default state to "Pending" because I assume that the Service has not finished initializing. Then the ViewModel simply handles the "Initialized" event fired by the Service. It's in this handler that I asses the actual connection state via a property on the Service and update the ViewModel.
Now, all of this works just fine because it is extremely unlikely that the race condition poke its head in. However, in the unlikely case that the Service finishes its initialization before the ViewModel is constructed, it will never handle that "Initialized" event and will just stay in its "Pending" state.
I've considered changing the Service interface to return awaitable types for properties, so that any module trying to access properties will have to wait for initialization to finish, but I'm not sure that this is the best approach. I'm also wary of having part of the client kick off the Service because then who should initialize it if several modules use it?
Is there some conventional way of dealing with this sort of asynchronous initialization that I am missing?
You mention using events to do the communication between the service and the ViewModel, you could use Reactive Extensions (Rx) instead of using events and this has the ability to remove the race condition you describe above.
Put simply this turns the service from a pull-model into a push-model, it will push out data\events via a stream and allows you to compose LINQ queries over the stream. If you're not familiar with Rx there's plenty of good information out.
In this scenario using Rx I would have the service expose a property of IObservable<T>;, where T is your type (I guess some kind of State enum), the backing field for this property is the important part, this would be a ReplaySubject<T> with a size of one. What this means is anytime someone 'subscribes' to the property they will receive the last value published to the subject. This therefore means there isn't a race condition between publishing and subscribing to the stream.
This is probably a little easier to understand in code:
public enum State
{
Initializing,
Initialized,
}
public interface IMyService
{
IObservable<State> Status { get; }
}
public class MyService : IMyService
{
private ReplaySubject<State> _state;
public MyService()
{
_state = new ReplaySubject<State>(1);
_state.OnNext(State.Initializing);
// Do initialisation stuff
_state.OnNext(State.Initialized);
}
public IObservable<State> Status { get { return _state; } }
}
The example only accounts for initializing the service on the current thread (ie synchronously), this means it would block the calling thread and I guess this would be the Dispatcher thread if this is a XAML based app.
If you require the initialization to be done asynchronously you would look to using either Observable.Create<T> or Observable.Start<T> to start the work on a background thread so that it doesn't block the dispatcher (UI) thread.
To consume this service you would do something like this is your ViewModel:
public class MyViewModel
{
private State _state;
public MyViewModel(IMyService myService)
{
myService.Status.ObserveOn(DispatcherScheduler.Current)
.Subscribe(x =>
{
_state = x;
});
}
public bool IsReady { get { return _state == State.Initialized; } }
}
Now there isn't a race condition between the Service and the ViewModel.
There can be a lot to learn about Reactive Extensions but it is a very good way to handle asynchronous calls when you're implementing an MVVM application.

Categories