I just released TinyPubSub.Forms 1.1 that takes advantage of the change I got into Xamarin.Forms Core Navigation.
Nuget package for Forms can be found at https://www.nuget.org/packages/tinypubsub.forms/.
The change is that we now can get info from the NavigationPage what pages that are popped when we call PopToRoot. We needed this information to deregister pages in TinyPubSub.
A blog about .NET development and related technologies. Nothin' fancy! A lot of Xamarin and .NET Core.
Wednesday, November 9, 2016
Tuesday, October 11, 2016
PropertyChanged.Fody
Short story
When using MVVM as the pattern of choice for your app, make sure to use
PropertyChanged.Fody
to make your life a little easier. - Install the nuget-package
PropertyChanged.Fody
- If using Xamarin studio, edit the Weavers.xml file in the root and add <PropertyChanged>. This is done automatically in Visual Studio.
- Create a base class for ViewModels and decorate it with the
[ImplementPropertyChanged]
attribute - All your properties will be raising the PropertyChanged event on INotifyPropertyChanged.
Long story
MVVM heavily relies on ViewModels that implement INotifyPropertyChanged. This is the way that the View will be aware of changes in the ViewModel and what triggers UI-updates when you change a ViewModel property.
Before PropertyChanged.Fody
The usual way to tackle this is to implement the INotifyPropertyChanged your self. INotifyPropertyChanged only defines one event called PropertyChanged. This event is what the view hooks up to in order to listen to the ViewModel. No magic at all going on here.
So what we do is that we implement that interface and add a method to raise it in a simple way.
using System.ComponentModel; // The definition lives here
public class MyViewModel : INotifyPropertyChanged
{
// The only thing INotifyPropertyChanged defines
public event PropertyChangedEventHandler PropertyChanged;
// Helper method to raise the event
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// And a property with a backing field
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
That is alot of code for a single property. What if we could get rid of most of that?
After PropertyChanged.Fody
Enter PropertyChanged.Fody!
To install, do this:
- Install the nuget-package
PropertyChanged.Fody
- If using Xamarin studio, edit the Weavers.xml file in the root and add <PropertyChanged>. This is done automatically in Visual Studio.
After installing the nuget package, rewrite the code above to look like this.
[ImplementPropertyChanged]
public class MyViewModel
{
public string Name {get; set; }
}
Can we make it better
Yes, create a base class for your ViewModels and decorate that one with the
ImplementPropertyChanged
attribute. Then you can forget about it.How does it work
Fody is an IL-weaver. It modifies the IL code generated by the compiler and implements the interface for you.
Resources
Make sure to check out the official documentation at https://github.com/Fody/PropertyChanged
Tuesday, July 26, 2016
Thoughts on making TinyPubSub a little less tiny
Thoughts on making TinyPubSub a little less tiny
TinyPubSub is a very simple Publish/Subscribe library created mainly for passing events between views in an Xamarin Forms application that uses MVVM. You can read about it at https://github.com/johankson/tinypubsub.What I'm thinking about doing is extending it with two features
- Passing of data
- A stack based recipient model
Passing of data
TinyPubSub only allows for publishing events from one source to many recipients. It was originally create for notifying other views to reload or refresh their data. At first this was pretty much all it was intended to do. But now I can't help myself and I would really like to publish data as well.This is the original way to subscribe and publish an event.
In the first view model
TinyPubSub.Subscribe("ducks-loaded",
() => { RebindGui(); });
TinyPubSub.Publish("ducks-loaded");
TinyPubSub.Subscribe("duck-color-updated",
(c) => { RecolorDuck( c ) } );
TinyPubSub.Publish("duck-color-updated", c);
An example
Let's say you're buildning an app for configuring a car. The first page is to choose the model. On this page there is a button to choose your color. The original page simply registers for thecolor-chosen
event and waits happily for that to happen. We then create a generic choose color page that knows nothing about what page that really needs that color. When the color finally is choosen the page fires a color-chosen
event and the first page will receive it.All is fine until you get another subpage that also wants a color choosen. You can solve that in a number of ways. The first being to register different events for different colors choosers and pass an argument to when we create the color picker page. This is messy and could easily get out of hand.
My proposed solution is to create a function where you can state that only the latest registered listener will handle the event.
A stack based recipient model
Enter the stack based recipient model.The mechanism behind this is simple. The latest registered recipients of a specific event is the only one that will receive an event.
Since all events for a page is deregistered automatically in TinyPubSub it will be simple to reuse the color-picker page multiple times.
To revisit the car example, just before clicking the button for coloring your car door you register to the
color-chosen
event with the `SubscribeExclusive(...)
method.TinyPubSub.SubscribeExclusive("color-chosen",
(c) => { RecolorCarDoor( c ) } );
await Navigation.PushAsync(Resolver.Resolve());
color-chosen
event. Only the page before will get the event. And when the page goes out of scope, the subscription for the event will be removed and the page before will get the event instead.This also means that the ColorPickerPage could check at runtime to see if there are any recipients at all and throw an Exception if there is none.
Summary
This is still not implemented. I thought I just write it down first and get some comments on it.Tuesday, May 10, 2016
A very small pub/sub solution for Xamarin Forms
I've created a small project called TinyPubSub that only does one thing at the moment. It's made especially for use with MVVM and Xamarin Forms.
DISCLAIMER: This is a very early version of the library.
The "update-ducks" string is just a arbitrary name and you can select what ever you want. Note that I don't pass any data (yet), but that might be the next step in destroying this library by bloating it.
Short version:
Long version:
I'm a big fan of vanilla MVVM. That means that I don't like to add other frameworks on top of what's already possible to achieve using only Xamarin Forms.
A very common scenario is that I have a main page that are supposed to display some kind of data, let's say a list of ducks. I then navigate down a couple of pages in the app and find a page where I can add a duck. This should then update the first page. I could do this update in the OnAppearing event of the page but that breaks two nice rules of mine:
- The page should not start to load data when it is resurfaced. It should have already done that.
- The view is starting to handle logic. We don't want that.
So I created a small (tiny one might call it) library that solves this in the most simple way I can think of. It also handles dereferencing in a nice way. As long as you don't use Navigation.PopToRoot(); for the time being.
The features being:
- Simple usage
- Automatic un-subscription
The code
This is the structure of the project in the sample supplied with the source code (available at github).
Initialization
To initialize TinyPubSubs automatic dereference magic, just add this code to each NavigationPage you create. I'm looking at creating a forms library that adds an Init-method instead. But for now, do this.
public App ()
{
// The root page of your application
var navPage = new NavigationPage(new MainView());
navPage.Popped += (object sender, NavigationEventArgs e) => TinyPubSub.Unsubscribe(e.Page.BindingContext);
MainPage = navPage;
}
{
// The root page of your application
var navPage = new NavigationPage(new MainView());
navPage.Popped += (object sender, NavigationEventArgs e) => TinyPubSub.Unsubscribe(e.Page.BindingContext);
MainPage = navPage;
}
Usage in the ViewModels
In the constructor of the ViewModels, add subscriptions like this
public MainViewModel ()
{
TinyPubSub.Subscribe (this, "update-ducks", () =>
{
// Get data and update the GUI
});
}
{
TinyPubSub.Subscribe (this, "update-ducks", () =>
{
// Get data and update the GUI
});
}
Publish events
In another ViewModel we then decide to add a duck.
public ICommand AddDuck
{
get {
return new Command (async () => {
// Do logic and add stuff
// Publish an event
TinyPubSub.Publish ("update-ducks");
await Navigation.PopAsync();
});
}
}
{
get {
return new Command (async () => {
// Do logic and add stuff
// Publish an event
TinyPubSub.Publish ("update-ducks");
await Navigation.PopAsync();
});
}
}
This will fire the actions (synchronous at the moment) and then pop this view. The cool part is that when we pop the view, the subscriptions will be unsubscribed (remember the code in the beginning of the post) and the memory will be cleaned up.
Summary
This is a simple way to solve a common problem. There is a built in Messaging Center in Xamarin Forms that I personally find a bit messy to use.
Future features might be async actions and passing of simple data.
Available on nuget at https://www.nuget.org/packages/tinypubsub and GitHub at https://github.com/johankson/TinyPubSub
Tuesday, May 3, 2016
Enabling multitouch using CocosSharp
It's been a long time since my last blog post due to personal and professional reasons. Anyhow, now I'm planning to get back in the saddle and start blogging on a regular basis again. Also, this happens to be blog post number 100. Yay!
I've started a little secret project of my own that required two things:
So I checked out the available frameworks out there for Xamarin (especially for Xamarin Forms) and I decided to give CocosSharp a run for its money. I've done some small CocosSharp projects before and it fits my needs for the prototyping of this app.
I'm using the Forms version of CocosSharp since I'm a big Xamarin Forms fan.
One of the first things I noticed was that the multitouch simply didn't work as I expected. No matter what properties I set there was no multitouch going on. After some google-fu I found out that you have to set the MultipleTouchEnabled to true on the CCGameView instance. Well, the CCGameView is platform specific and there is no exposure of this property in the platform agnostic CocosSharpView that you use in the forms project.
That didn't work. In fact, the method is never called. (Yes, I registered the renderer! :) ).
Short version
To enable multitouch in CocosSharp (Forms version) you must create a custom renderer to set the MultipleTouchEnabled on the CCGameView (platform specific code) and then you must inherit from the CocosSharpView in order to make the registration of the custom renderer work. Code in the bottom of the post.
Long version
I've started a little secret project of my own that required two things:
- A simple framework for drawing stuff
- A simple input scheme for multitouch
So I checked out the available frameworks out there for Xamarin (especially for Xamarin Forms) and I decided to give CocosSharp a run for its money. I've done some small CocosSharp projects before and it fits my needs for the prototyping of this app.
I'm using the Forms version of CocosSharp since I'm a big Xamarin Forms fan.
The issue
One of the first things I noticed was that the multitouch simply didn't work as I expected. No matter what properties I set there was no multitouch going on. After some google-fu I found out that you have to set the MultipleTouchEnabled to true on the CCGameView instance. Well, the CCGameView is platform specific and there is no exposure of this property in the platform agnostic CocosSharpView that you use in the forms project.
Custom renderer to the rescue
Well, that's a simple fix I figured. Simply create a custom renderer and set the property directly.
protected override void OnElementChanged (ElementChangedEventArgs<CocosSharpView> e)
{
base.OnElementChanged (e);
if (Control != null) {
Control.MultipleTouchEnabled = true;
}
}
{
base.OnElementChanged (e);
if (Control != null) {
Control.MultipleTouchEnabled = true;
}
}
Create a custom control (the work around)
So the simple work around for this was to create a custom control.
public class MyCocosSharpView : CocosSharpView
{
}
{
}
And then use MyCocosSharpView instead of CocosSharpView. I'm not sure why it behaves this way, but its got to have something to do with the registration of the custom renderer. Hopefully I'll get some time to drill down in the source code and find out why.
What I would like
The MultpleTouchEnabled property should be visible from the CocosSharpView class. That is at least what I'll suggest to the CocosSharp team.
The code
These are the interesting parts of the code.
Subscribe to:
Posts (Atom)