Wednesday, October 31, 2012
How to ask questions about MvvmCross?
I love answering questions about Mvx and hearing about what users want.
Take a look at all the information that's already available - http://slodge.blogspot.co.uk/p/mvvmcross-quicklist.html
So please feel free to ask questions by:
1. You can post them on StackOverflow - http://stackoverflow.com/questions/tagged/mvvmcross - please think about your question and provide as much detail as you can - I generally spend about 10 minutes to write a good answer so please also spend 10 minutes writing a good question.
For all questions, please search first - if there are any similar problems/questions then consider referencing them in your question.
For complicated questions, please consider writing a separate small test app which focusses on the problem area, rather than posting all your code - no-one has time to read all your code :)
If you find you have followup questions... then please do not update your question... and please do not ask new questions in comments - open a new question instead :)
2. You can post them on http://forums.xamarin.com - but again the more relevant detail you can provide the better - consider adding a gist for code - http://gist.github.com/
3. If you think it is a bug or a new feature then you can open a new issue on https://github.com/slodge/MvvmCross/issues/new - ideally include some sample code that I can build and run - if you have a test application please put it in a repo somewhere. If I have to make a test app myself for each and every issue then I'll be slower to answer...
4. You can come along to http://jabbr.net/#/rooms/mvvmcross but please don't ask too many questions there - it's not a great place to ask questions to look at code or to share things really - and it's not very searchable so it's hard for answers to benefit others...
Looking forwards to hearing from you all :)
Stuart
Tuesday, October 30, 2012
Testing ViewModels in MvvmCross
This is actually very simple to do. There are just a couple of things to put in place to cope with the singleton nature of MvvmCross IoC
Also, please note that if you want to test on MonoTouch then because there are dynamic code restrictions, then you cannot use Dynamic Mocks (like Moq)
*1. First in the test setup, I clear the IoC system using code like:
private IMvxServiceProviderRegistry _ioc;
[SetUp]
public void SetUp()
{
// fake set up of the IoC
MvxOpenNetCfContainer.ClearAllSingletons();
MvxOpenNetCfServiceProviderSetup.Initialize();
_ioc = MvxServiceProvider.Instance;
_ioc.RegisterServiceInstance(new MvxDebugTrace());
MvxTrace.Initialize();
}
*2. Then to test general navigation I use a couple of Mocks like:
public class MockMvxViewDispatcherProvider : IMvxViewDispatcherProvider
{
#region IMvxViewDispatcherProvider implementation
public IMvxViewDispatcher Dispatcher { get; set; }
#endregion
}
public class MockMvxViewDispatcher : IMvxViewDispatcher
{
public List CloseRequests = new List();
public List NavigateRequests = new List();
public MockMvxViewDispatcher()
{
}
#region IMvxViewDispatcher implementation
public bool RequestNavigate(MvxShowViewModelRequest request)
{
NavigateRequests.Add(request);
return true;
}
public bool RequestClose(IMvxViewModel whichViewModel)
{
CloseRequests.Add(whichViewModel);
return true;
}
public bool RequestRemoveBackStep()
{
throw new NotImplementedException();
}
#endregion
#region IMvxMainThreadDispatcher implementation
public bool RequestMainThreadAction(Action action)
{
action();
return true;
}
#endregion
}
The main thing these Mocks appear to do is to catch and store the navigation requests.
IMPORTANT NOTE: however, please do note the IMvxMainThreadDispatcher code - this service is essential to much of the operation of MvvmCross - lots of things in MvvmCross rely on this service being available because they need to get their execution across to some "UI thread" - e.g. PropertyChanged will silently fail to fire if the service is missing!
*3. To then test navigation I use tests like:
[Test]
public void ExecutingTheLoginCommandNavigatesToTheLoginViewModel()
{
var mockNavigation = new MockMvxViewDispatcher();
var mockNavigationProvider = new MockMvxViewDispatcherProvider();
mockNavigationProvider.Dispatcher = mockNavigation;
_ioc.RegisterServiceInstance(mockNavigationProvider);
var homeViewModel = new HomeViewModel();
homeViewModel.LoginCommand.Execute(null);
Assert.That(mockNavigation.NavigateRequests.Count == 1);
Assert.That(mockNavigation.NavigateRequests.First().ViewModelType == typeof(LoginViewModel));
}
[Test]
public void ExecutingTheCloseCommandClosesTheViewModel()
{
var mockNavigation = new MockMvxViewDispatcher();
var mockNavigationProvider = new MockMvxViewDispatcherProvider();
mockNavigationProvider.Dispatcher = mockNavigation;
_ioc.RegisterServiceInstance(mockNavigationProvider);
var loginViewModel = new LoginViewModel();
loginViewModel.CloseCommand.Execute(null);
Assert.That(mockNavigation.CloseRequests.Count == 1);
Assert.That(mockNavigation.CloseRequests.First() == viewModel);
}
*4. And to test ViewModel property changes I just use simple code like:
[Test]
public void ExecutingTheAddCommandIncrementsTheCounter()
{
var mockNavigation = new MockMvxViewDispatcher();
var mockNavigationProvider = new MockMvxViewDispatcherProvider();
mockNavigationProvider.Dispatcher = mockNavigation;
_ioc.RegisterServiceInstance(mockNavigationProvider);
var tipViewModel = new TipViewModel();
Assert.That(tipViewModel.Counter == 0);
var notifications = new List();
tipViewModel.PropertyChanged += (s, e) =>
{
notifications.Add(e.PropertyName);
};
tipViewModel.CloseCommand.Execute(null);
Assert.That(mockNavigation.CloseRequests.Count == 0);
Assert.That(mockNavigation.NavigateRequests.Count == 0);
Assert.That(notifications.Count == 1);
Assert.That(notifications[0] == "Counter");
Assert.That(tipViewModel.Counter == 1);
}
*5. And that's it... these tests work cross-platform - including in the lovely NUnit tool from Xamarin for MonoTouch
Possible solutions for WP8 SDK Emulator issues - WP8 Hyper-V emulator cannot see the wireless network adapter
I had a problem with windows phone 8 sdk accessing the wireless network on my host laptop.
Some solutions/questions I saw reported when trying to debug this were:
- Plugin an Ethernet cable - that worked for me!
- Problem solved! Hyper-V uses same MAC address for guest VMs (virtual machine) and Host. If the router configured to give the host always same ip address it will conflict with the emulator. Solution - on the router remove the host from known PCs and let it give you some new ip address (not fixed). After you start the emulator it will get the correct ip address from router. Router will show you two PCs (host and vm) with the same MAC, but different ip addresses.
- I encountered a problem with installing Hyper-V on a german installation of Windows 8 but have found people having the same issue with other localized versions. After setting the checkbox to install Hyper-V and clicking ok it simply did not install. I had to change my regional settings to english, install it and switch them back to german for everything to work.
Maybe the SDK simply triggered the installation correctly or the recent big Windows 8 patch resolved the problem. Although it might be that you had different problems with installing Hyper-V.
It is possible that the emulator's virtual machine is corrupted.
1. Close Visual Studio. Launch Hyper-V Manager.
2. In the Virtual Machines list, stop and then delete any virtual machines currently running
3. Try your app again. A new emulator VM instance should start.
If that doesn't fix it, click on the running VM instance in Hyper-V Manager. In the Actions column for your Emulator instance, click on Settings, and drill down into the Network adapter hardware. See if a Virtual Switch is selected for the network adapter etc.
Hi everyone, We have some steps to run the emulator:
Enable Hyper-V on Control panel.
Restart your computer.
Install Windows Phone 8 SDK.
Restart your computer, again.
Run the Emulator! Takes very very long time if you don't do the step 5.
Happy coding!
Please check your
Control Panel\All Control Panel Items\Network and Sharing Center and tell me how the Virtual switch, internet and windows phone switch configured?? May be it will leave some clue to me.
From the release notes:
The emulator can't connect to the internet through a wired or Wi-Fi network connection.
-
User impact: There is no internet access on the emulator.
-
Workaround: Disable the automatic proxy detection and try connecting again.
-
Origo Foci-Eb 2012 - an example mvvmcross app from earlier this year
It was built on MonoDroid, MonoTouch, WP7 and MvvmCross
It shows really nicely how to show the same ViewModel data in a nice Native UI style.
I couldn't find the iOS screenshots, but some Droid and WP7 goodness is below:
Android - https://play.google.com/store/apps/details?id=OrigoEB.Main
WindowsPhone http://www.windowsphoneapplist.com/en/Origo_FociEb_2012-a116571.html
The developer was
MonoTouch, MonoDroid and MvvmCross at Build Windows 2012 in Seattle #BldWin
Learn how to create an app with versions for the Windows Store, Windows Phone, and other platforms, using the new Portable Class Libraries support in Visual Studio 2012 to share code between the different versions of the app. We will see how the Model-View-ViewModel pattern (MVVM) is ideally suited to sharing code between platforms since it encourages a clean separation between the app logic, which can be shared, and the UI, which is platform-specific. We'll see how to access non-portable functionality from portable code by creating a portable abstraction with platform-specific implementations. We will see several real-world demo apps, and touch on more advanced concepts such as navigation, inversion of control, and synchronizing data across multiple clients with Windows Azure Service Bus. To maximize your benefit from this session, having some prior experience with XAML-based apps and the MVVM pattern is recommended.
I don't know what the content will be...
But if it's anything like this blog post - http://blogs.msdn.com/b/dsplaisted/archive/2012/08/27/how-to-make-portable-class-libraries-work-for-you.aspx - then it should be very useful :)
Sunday, October 28, 2012
A temporary solution for the Profile1 only bug in MonoDevelop MonoTouch PCL support
<TargetFrameworkProfile>Profile104</TargetFrameworkProfile>
<TargetFrameworkProfile Condition="'$(OS)' != 'Windows_NT'">Profile1</TargetFrameworkProfile> <TargetFrameworkProfile Condition="'$(OS)' == 'Windows_NT'">Profile104</TargetFrameworkProfile>
Saturday, October 27, 2012
Mvvm MonoTouch back up and running :)
Edit the file /Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild/Microsoft/Portable/v4.0/Microsoft.Portable.CSharp.targets, finding the PropertyGroup that sets
<TargetFrameworkIdentifier>MonoTouch</TargetFrameworkIdentifier>
And to it, adding the lines:
<CscToolExe>smcs</CscToolExe> <CscToolPath>/Developer/MonoTouch/usr/bin</CscToolPath>
Friday, October 26, 2012
Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information
To fix this error.... first find the Assembly which is causing the problem! Useful code from http://stackoverflow.com/questions/1091853/unable-to-load-one-or-more-of-the-requested-types-retrieve-the-loaderexceptions
using System.IO; using System.Reflection; try { //The code that causes the error goes here. } catch (ReflectionTypeLoadException ex) { StringBuilder sb = new StringBuilder(); foreach (Exception exSub in ex.LoaderExceptions) { sb.AppendLine(exSub.Message); if (exSub is FileNotFoundException) { FileNotFoundException exFileNotFound = exSub as FileNotFoundException; if(!string.IsNullOrEmpty(exFileNotFound.FusionLog)) { sb.AppendLine("Fusion Log:"); sb.AppendLine(exFileNotFound.FusionLog); } } sb.AppendLine(); } string errorMessage = sb.ToString(); //Display or log the error based on your application. }
MvvmCross - experiences, hindsight, limitations?
The answer is always to point them at this question on StackOverflow -
MvvmCross experiences, hindsight, limitations?
Wednesday, October 24, 2012
Going outside of mvvm sometimes - live video preview in mvvmcross/monodroid
The question was about video views and how to get native objects working inside portable code.
The answe I gave was a bit cowardly... It was to do most of the code natively (using xamarin mobile helpers) and to then bind to the view model at quite a simple level.
The poster took my advice and has now posted their code.... https://gist.github.com/3945799
There are definitely still places where more could be abstracted... And I'm still thinking about whether my original advice was correct...
Still thinking...
Tuesday, October 23, 2012
More progress on the Portable UI prototype
These files are automatically picked up using Conventions - no configuration required.
Next steps...
- tidy it up a bit (thank you Resharper!)
- add a list/listitem format,
- try it out on Touch, WP and WinRT
Sunday, October 21, 2012
About me and my company - Stuart Lodge, Cirrious Ltd
https://speakerdeck.com/u/cirrious/p/cirrious-ltd
Saturday, October 20, 2012
How the JSON Android.Dialog project works - and how WP.Dialog might work
WP.Dialog is (I think) just the 'Form' part of that - just like Android.Dialog and MonoTouch.Dialog - although later it might grow in scope to the entire project - baby steps first:)
Also to be clear... I think WP.Dialog can exist and run without any dependency on MvvmCross - I don't see why it couldn't be useful for code-behind projects, for MvvmLight, etc
The projects
There are 5 projects:
- Core.Dialog - a PCL containing:
- Descriptions - the structs which describe a UI
- Elements - the basic interfaces which UI components have to obey
- Builder - the abstract code which turns Descriptions into Elements
- Android
- Android.Dialog - an Android Library containing:
- Attributes - not currently used but provide a *very* nice way to turn C# models into UIs - see MonoTouch.Dialog for more
- Builder - inherits from Core.Dialog.Builder - provides the *very small* Android specific building part
- Elements - the default elements... the ones to start with are:
- RootElement (which is a mess because it is a RootElement and also has RadioGroup functionality built in)
- StringElement - displays a Caption and a Value
- ValueElement
- displays a Caption and an Editable Value - EntryElement
- FloatElement
- CheckboxElement
- DO NOT START with RadioElement, WebElement, HtmlElement, etc - it's confusing!
- Enums - mainly ignored... most seem to be there for MT.Dialog API compatability
- Root-Level classes - DialogListView and DialogAdapter - together these 2 things provide the 'UI Control'
- DialogSampleApp - the Android Demo project
- MainDialogActivity - is the only activity that has been updated to the new JSON
- Touch - ****nowhere near working****
- Cirrious.MvvmCross.Dialog.
Touch - my branch of MonoTouch.Dialog - Sample - the MonoTouch Sample
Within this layout... I guess WP should work in a new folder WindowsPhone and have two projects - a Dialog and a Sample :)
Naming: I'd like to put these projects in some namespace - for Mvx I used Cirrious (which is my company name) but that's mainly because of the way the project started - it was a company job! No idea what namespace to use, but I'd like to use Something.Dialog.Core rather than just Dialog.Core...
The MainDialogActivity code
For understanding Android.Dialog:
- a good place to start might be MainDialogActivity.
- This contains:
- a big block of JSON
- some code at the start of OnCreate to load the JSON
- a big block of commented out C# which is equivalent to the JSON
A quick walkthrough the code at the start of OnCreate:
DroidResources.Breaking this down:Initialise(typeof(Resource.Lay out)); var parser = new D roidElementBuilder(); var setter = new E xampleActionPropertySetter(); setter.Actions[" ShowDialogActivity"] = ( sender, args) => StartNew(); setter.Actions[" ShowDialogListViewActivity"] = (sender, args) => ClickList() ; setter.Actions[" ElementTest"] = (sender, args) => ClickElementTest(); parser. CustomPropertySetters["Action" ] = setter; var description = Newtonsoft.Json.JsonConvert. DeserializeObject<ElementDescr iption>(JsonText); Root = parser. Build(description) as RootElem ent;
DroidResources.Initialise(typeof(Resource.Lay out));
The first line initialise the DroidResources - what this does is it tells the DroidResources where to look for numeric Android ResourceIds - e.g. when you load a StringElement then the framework might look for some AXML called dialog_string_layout (or similar) - these resources are in the resources folder.
var parser = new DThis creates a builder (not a parser - sorry!).roidElementBuilder();
The Builder stores a lookup list of string names to Element Types
There is a default parameter to DroidElementBuilder which tells the Builder to reflect the Android.Dialog namespace and to look for the default set of Element Types.
Users can also register custom Element Types if they want to - so if you invent a RuneElement, then you can add it.
var setter = new ExampleActionPropertySetter(); setter.Actions[" ShowDialogActivity"] = ( sender, args) => StartNew(); setter.Actions[" ShowDialogListViewActivity"] = (sender, args) => ClickList() ; setter.Actions[" ElementTest"] = (sender, args) => ClickElementTest(); parser. CustomPropertySetters["Action" ] = setter;
This block of code sets up a custom property setter for 'Action'. This means that if ever a property is marked in the Json with a value "@Action:foobar" then this property and foobar will be passed to the custom setter.
In a 'coming soon' step I expect to add an MvxBind custom property setter...
var description =Newtonsoft.Json.JsonConvert. DeserializeObject<ElementDescr iption>(JsonText); This uses PCL JSON.Net to deserialize the ElementDescription JSON. Note that the framework is decoupled from JSON - so users could use XML, ProtoBuf, C#, etc instead!
Root = parser.Finally this line passes the description to the builder :)Build(description) as RootElem ent;
How an Android Element is built
If some JSON comes in like:
{ 'Key':'then this maps to an ElementDescription.String', ' Properties':{ ' Caption':'Click for EntryElement Test', ' Click':'@Action:ElementTest' } }
The builder uses this:
- The Key 'String' is mapped to 'StringElement' - so it uses Reflection to call the parameterless constructor of StringElement (or the constructor with default parameters)
- The builder then iterates the Properties
- uses reflection to set the Caption property on the StringElement to 'Click for EntryElement Test'
- notices the '@Action:' prefix - so passes the Click PropertyInfo and 'ElementTest' to the custom property setter
Note that property values can be strings, numerics or booleans - anything else has to go through a special handler (e.g. a string lookup or a JSON serialised object)
Note that there is no real data binding right now - but that will come with '@MvxBind;' :)
Note that later there may be some chances to add platform specific properties - e.g. something like:
'Properties':{ ' Caption':'Click for EntryElement Test', ' Click':'@Action:ElementTest', '@Droid:WarpSpeed':4, '@WindowsPhone:Pinned':false, }
How an entire Dialog is displayed
In Android and in Touch, the Dialog is displayed using a ListView
The reason for this is because it allows UI virtualisation... and also because MonoTouch doesn't really have a StackPanel!
This use of a ListView makes the UI a bit more complicated than is really needed... e.g. for small forms it would actually be a lot easier to not have any cell reuse.
For WindowsPhone, it might be easier to just use a StackPanel with fixed members - but you could use a List if you wanted to....
In Android, the basic approach is:
- the UI View (Activity) is a List (including Groupings)
- the UI View gets help from an Adapter
- the Adapter stores the list of Elements
- when it comes to time to render the UI, then the Adapter's GetView gets called for every visible 'index'
- the Adapter passes the GetView call through to the GetView on the individual Element - this is passed through to GetViewImpl
- currently the GetViewImpl passes everything through eventually to DroidResources - which loads 'axml' for the element.
- calls like UpdateDetailDisplay and UpdateCaptionDisplay are used in the Element to actually fill in values in the Element
Note that because it uses a list, then there is an opportunity for cell reuse. In Mt.Dialog this works quite well. In Android.Dialog I think it's currently broken - but I will fix it.
So for WP.Dialog
I would expect for WP:
- the same JSON will be used
- the JSON will be parsed by JSON.Net
- a WindowsPhoneBuilder will be used
- this WindowsPhoneBuilder will (by default) know about a set of WindowsPhone Elements - which it will construct using reflection
- these Elements will contain some C# and will somehow map to XAML...
- the XAML will be parented either in a StackPanel (inside a ScrollViewer) or inside a ListView
- if you use a ListView it's just a bit more complicated to route the bindings and to reuse controls (it's a standard 'ListItemSelector' type thing)
- it would be really nice if the XAML is very easily styleable - like custom controls are
- maybe just try some JSON with some StringElements - each has a Caption and Value
- then try adding an EntryElement - Caption and Value
- then try adding a CheckboxElement - Caption and Boolean Value
And then (if we're lucky) people can add platform specific styling to those UIs.
Cross Platform Views for MvvmCross... ideas...
Friday, October 19, 2012
Thursday, October 18, 2012
Starting to play with the idea of a cross platform UI framework
I've started playing with the idea of doing a cross platform UI framework - at least for those UIs that can be done by MonoTouch.Dialog type displays.
See the idea in very raw form at: https://github.com/slodge/Android.Dialog/issues/4
Is this of interest... if it is then comment here or on GitHub
Stuart
Wednesday, October 17, 2012
Creating custom views is easy to do...
---
Creating custom views is easy to do...
namespace Angevelle.App1.UI.Droid. Controls
{
public class MyText : EditText
{
public MyText(Context context, IAttributeSet attrs)
: base(context, attrs)
{
this.EditorAction += OnEditorAction;
}
private void OnEditorAction(object sender, EditorActionEventArgs editorActionEventArgs)
{
if (editorActionEventArgs. ActionId == ImeAction.Done)
{
// this code not tested - but something like this should work
var imm = (InputMethodManager)Context. GetSystemService(Context. InputMethodService);
imm.HideSoftInputFromWindow( WindowToken, 0);
}
}
}
}
Then you can use that View in your AXML just as you do Android or Mvx views:
<angevelle.app1.ui.droid
.controls.MyText
android:layout_height=....
/>
If you are finding
angevelle.app1.ui.droid. controls
too verbose, then you could shorten this using an abbreviation in setup.cs: protected override IDictionary ViewNamespaceAbbreviations
{
get
{
var abbreviations = base. ViewNamespaceAbbreviations;
abbreviations["Abv"] = "angevelle.app1.ui.droid. controls";
return abbreviations;
}
}
then you can just use:<Abv.MyText
android:layout_height=....
/>
Build a new plugin for mvvmcrosss
-----
1. Create a central shared plugin
This would be Portable Class library - sayMyCompany.MvvmCross.Plugins. Mega
Within that central shared PCL, you would put whatever portable code was available - often this might only be a few service Interface definitions - e.g.
public interface IAlphaService { ... }
andpublic interface IPageService { ... }
You'd then add the PluginManager for that plugin which would just add the boiler-plate of:public class PluginLoader
: IMvxPluginLoader
, IMvxServiceConsumer<IMvxPlugin Manager>
{
public static readonly PluginLoader Instance = new PluginLoader();
#region Implementation of IMvxPluginLoader
public void EnsureLoaded()
{
var manager = this.GetService<IMvxPluginMana ger>();
manager.EnsureLoaded<PluginLoa der>();
}
#endregion
}
2. Create the specific plugin implementations
For each platform, you would then implement the plugin - e.g. you might implementMyCompany
.MvvmCross.Plugins. Mega.WindowsPhone
and MyCompany
.MvvmCross.Plugins.Mega.Droid
Within each of these you will implement the native classes which provide the services:
public class MyAlphaService : IAlphaService { ... }
and public class MyPageService : IPageService { ... }
Finally each plugin would then provide the boilerplate plugin implementation:public class Plugin
: IMvxPlugin
, IMvxServiceProducer
{
#region Implementation of IMvxPlugin
public void Load()
{
// alpha registered as a singleton
this.RegisterServiceInstance<I AlphaService>(new MyAlphaService());
// page registered as a type
this.RegisterServiceType<IPage Service, MyPageService>();
}
#endregion
}
3. Instantiation of plugins
Each UI client will have to initialise the plugins.This is done by the end UI client adding library references to:
- the shared core plugin
- the appropriate plugin implementation
3.1 WinRT, WindowsPhone and MonoTouch
Then, for WinRT, WindowsPhone and MonoTouch clients, you also need to provide a Loader accessor in setup.cs - like:Note that Convention is used here - so it's important that MyCompany.MvvmCross.protected override void AddPluginsLoaders(Cirrious.Mvv
mCross.Platform.MvxLoaderPlugi nRegistry loaders) { loaders.AddConventionalPlugin<
.MvvmCross.Plugins.Me
MyCompany ga.WindowsPhone.Plugin>(); base.AddPluginsLoaders(loaders ); }
3.2 MonoDroid
For MonoDroid clients, you don't need to add this setup step - because MonoDroid has less Assembly.Load restrictions than the other platforms - and ao can load the plugins from file. But for this to work, it's important that the assembly names match - if the PluginLoader isAlphaPage.MvvmCross.Plugins. Mega.PluginLoader
then the conventions will try to load the plugin from MyCompany
.MvvmCross.Plugins. Mega.Droid.dll
4. Use of plugin services
After this setup, then applications should finally be able to access the plugins by:- adding a reference the Shared core portable library
- at some time calling
MyCompany
.MvvmCross.Plugins.Mega.PluginLoader. Instance.EnsureLoaded() - then accessing the individual services using
this.GetService
or() this.GetService
( )
5. Pure portable plugins
Some plugins can be 'pure portable'In this case they don't need any specialization for each platform, and no step 3 is required.
For an example of this, see the Json implementation - https://github.com/slodge/
How to bind an Android ImageView to an image loaded from Monodroid Assets
From StackOverflow
Quick answer:
- if your Android image file is stored in
assets/images/i1.png
- then make sure it is marked as an
AndroidAsset
- then your path needs to be
images/i1.png
Longer answer:
Ideally your ViewModel should be platform independent and not know about View concerns.
So your ViewModel might perhaps expose a property like:
private GameState _state;
public GameState State
{
get { return _state; }
set { _state = value; RaisePropertyChanged(() => State); }
}
where GameState is an enumeration like:
public enum GameState
{
Stopped,
Running,
Paused,
GameOver
}
you might then have images representing these states in an assets structure like:
/assets/gamestates/stopped.png
/assets/gamestates/running.png
/assets/gamestates/paused.png
/assets/gamestates/gameover.png
where each of those files is marked with BuildAction of AndroidAsset.
To then display the correct image in the UI, you would need a value converter like:
public class GameStateConverter
: MvxBaseValueConverter
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return string.Format("gamestates/{0}.png", ((GameState)value).ToString().ToLower());
}
}
mapped in using a Converters wrapper like:
public class Converters
{
public readonly GameStateConverter GameState = new GameStateConverter();
}
which is configured in setup.cs using:
protected override IEnumerable<Type> ValueConverterHolders
{
get { return new[] { typeof(Converters) }; }
}
With this in place, then your axml binding statement would be:
{'AssetImagePath':{'Path':'State', 'Converter':'GameState'}}
For an alternative approach using resources instead of assets, see MvxButtonIconBinding
in Іssue with binding to GridLayout to Android
Tuesday, October 16, 2012
Building mvvmcross projects in visual studio 2012
My basic setup for this has been the same one described in: http://slodge.blogspot.co.uk/2012/09/mvvmcross-vnext-portable-class.html
- I've installed VS, the Portable Class Library VS2010 extensions, VS2012, MonoDroid and VSMonoTouch
- I've then altered the registered Portable Library platforms just a little in order for Droid and Touch to both work under the magical Profile 104
However, working this way, I do admit I've experienced several small problems, and I thought I might list them here in case they help others:
- VSMonoTouch doesn't yet work in VS2012 - so there's no iOS support in VS2012 yet. There are some people who have got this working over on GitHub, but I've held off implementing anything in case Xamarin pull some magic out of the hat during this week's MonkeySpace conference.
- MonoDevelop refuses to open any solution that Visual Studio 2012 has opened - this is due to a Version number - 12 instead of 11 - at the start of the .sln file - it takes seconds to fix in NotePad++, but it is annoying
- There are some issues building MonoDroid portable projects in VS2012 sometimes - sometimes it takes 2 builds rather than 1 - no idea what this is yet - it feels like its somehow not quite hooking up the dependencies correctly between PCL and MonoDroid. I've not seen this problem at all in VS2010.
- There are some issues sometimes on putting breakpoints in the PCL code - again I've not identified what this is completely yet - and I have a feeling it may be a more general MonoDroid bug, and nothing to do with VS2012.
- I have seen some TargetFrameworkAttribute errors in VSMonoTouch projects - see http://slodge.blogspot.co.uk/2012/09/the-type-or-namespace-name.html for my hacky solution.
However.... overall, that's it - I'm up and running and Resharper is working too :)
Trying to build up the list of mvvmcross in the wild....
For the mvx readme on GitHub, I'm trying to build up a list of known users of MvvmCross.
Does anyone have any examples they would like included?So far...
Public projects that have used this framework include:
- Kinect Star Wars - http://www.youtube.com/watch?v=MXPE2iTvlWg
- Aviva Drive - http://www.aviva.co.uk/drive/
- Various Conference apps - SQLBitsX, DDDSW, LondonAzure, ....
- The CrossBox DropBox client - https://github.com/runegri/CrossBox
- Have you used the app? Please send me your links and I'll add them here
- The Blooor shopping list app - https://github.com/Zoldeper/Blooor
and listed under International inspiration are:
- http://www.slideshare.net/Runegri/kryssplatform-mobilutvikling
- http://www.slideshare.net/dan_ardelean/mvvmcross-da-windows-phone-a-windows-8-passando-per-android-e-ios
- http://www.e-naxos.com/Blog/post/Strategie-de-developpement-Cross-Platform-Partie-2.aspx
- http://blogs.msdn.com/b/dsplaisted/archive/2012/08/27/how-to-make-portable-class-libraries-work-for-you.aspx
Any more links... please post them as comments - once the spam filter lets you past then I'll include them as items.
Thanks :)
Monday, October 15, 2012
vNext is now the default branch on GitHub
This means the portable library code is now the default view.
I do anticipate that this may cause some problems, especially while the MonoDevelop/Monotouch tooling is still a little behind the curve. If anyone needs the original version, then the old non-portable version is stil there and is still labelled master - https://github.com/slodge/MvvmCross/tree/master
However, I hope that most of you will be able to join me in developing portable code :)
The future is portable - and I'm really glad to be switching over to vNext - it's much cleaner and even more powerful than the first generation of MvvmCross.
Collection binding in vNext - now switched to include IEnumerable
The reason for this decision was simple - performance.
Within Android, the ListView Adapter class relies on random access to the collection and it needs to use values like Count. This is why IList was selected for binding - because IList provides the [position] operator and it provides the Count property, whereas IEnumerable can only provide random element access and element counting through step-by-step enumeration - which, obviously, is slow
However.... despite this, it appears that Silverlight and Wpf databinding allows users to use IEnumerable collections - and I *guess* it does this in a less than optimal way, but that this doesn't matter for small collection sizes...
So... Mvx Droid is now following the same route - the binding will use IList when it's available, but will drop down to step-by-step enumeration when IList is not available. This means that if you want to, then your Android code can now bind to IEnumerable. However, just beware that this is never going to be super efficient!
For a look at the changes in details, see https://github.com/slodge/MvvmCross/commit/2b2be9878b0c84d12fdf6ba5b9e7d022b4ce6e42
Piggybank for Hadoop on Azure
I looked around and could only find this http://www.bimonkey.com/2012/08/no-piggybank-for-pig-on-hadoop-on-azure/
Fortunately, building one didn't seem too bad.... basically you just have to:
- have JDK 7 installed
- download ant from Apache
- set up some path variables (ANT_HOME and JAVA_HOME)
- download the Pig source
- open a cmd prompt, cd to the pig directory, then type `ant`
- cd to the piggybank directory and type `ant`
- download the Jodatime source
- cd to the Jodatime directory and type `ant`
Sunday, October 14, 2012
Changes to IoC in vNext
In all previous code, the simple IoC system worked using generic interfaces and generic extension methods.
So, for example, to import a service like IMyService, then the user would write code like:
public class TwitterViewModel : MvxViewModel , IMvxServiceConsumer<ITwitterSearchProvider> { private ITwitterSearchProvider TwitterSearchProvider { get { return this.GetService<ITwitterSearchProvider>(); } } }This has some duplication of the generic target - and it can make class declarations quite long winded... To make the code 'cleaner', in vNext, I've removed the generic part from the interface - so now code like this will work:
public class TwitterViewModel : MvxViewModel , IMvxServiceConsumer { private ITwitterSearchProvider TwitterSearchProvider { get { return this.GetService<ITwitterSearchProvider>(); } } }
Some Project Templates for vNext
If you download these then they should allow you to get new vNext projects up and running a bit more quickly.
Basically, these templates are created using the Visual Studio 'Export' menu item, and these templates are based on the code in: https://github.com/slodge/MvvmCross/tree/vnext/Templates
To use them:
- unzip the wrapper file to get to each individual item
- copy them to C:\Users\Stuart\Documents\Visual Studio 11\My Exported Templates
- or to C:\Users\Stuart\Documents\Visual Studio 2010\My Exported Templates
- that should (I hope) automatically import the templates into visual studio
- so when you do "new project" then type mvvmCross in the top right
- the options like MyApplication.Core should then automatically appear in the new project options:
There will be problems in the projects you create - especially there will be references which don't link together perfectly... but these should be small problems to resolve by hand - so it should be possible to get new projects up and running really quickly!
//
I think it's almost time to ship vNext ...
Friday, October 12, 2012
A sqlite example (vNext portable)
My initial attempt was to try to remove the #if statements from sqlite-net by using inheritance - see https://gist.github.com/3857333
However.... Craig (ConceptDev) pointed out to me that heading this way would mean that it would be harder to keep up to date with changes, fixes, etc in sqlite-net
So instead of inheriting out of sqlite-net, I adapted sqlite-net so it used an interface:
public interface ISQLiteConnection : IDisposable
{
string DatabasePath { get; }
bool TimeExecution { get; set; }
bool Trace { get; set; }
int CreateTable<T>();
ISQLiteCommand CreateCommand(string cmdText, params object[] ps);
int Execute(string query, params object[] args);
List<T> Query<T>(string query, params object[] args) where T : new();
IEnumerable<T> DeferredQuery<T>(string query, params object[] args) where T : new();
List<object> Query(ITableMapping map, string query, params object[] args);
IEnumerable<object> DeferredQuery(ITableMapping map, string query, params object[] args);
ITableQuery<T> Table<T>() where T : new();
T Get<T>(object pk) where T : new();
bool IsInTransaction { get; }
void BeginTransaction();
void Rollback();
void Commit();
void RunInTransaction(Action action);
int InsertAll(System.Collections.IEnumerable objects);
int Insert(object obj);
int Insert(object obj, Type objType);
int Insert(object obj, string extra);
int Insert(object obj, string extra, Type objType);
int Update(object obj);
int Update(object obj, Type objType);
int Delete<T>(T obj);
void Close();
}
This then made the changes to Sqlite-net really simple - just maybe 4 or 5 classes to add inheritance to, and 4 or 5 methods to add `where T : new()` constraints too.
-
The result is this portable plugin: vnext/Cirrious/Plugins/Sqlite
With a MonoDroid implementation in vnext/Cirrious/Plugins/Sqlite/Cirrious.MvvmCross.Plugins.Sqlite.Droid/SQLiteNet.cs
Note that I've only done the Droid implementation of this plugin so far, but I think all of the rest - WP7, MonoTouch, and WinRT (and beyond) should be straight-forward - and that the same SQLiteNet.cs file (#if's and all) will be link-shared between those plugins.
-
As a first example of use I created a 'simple' style project
- SimpleDroidSql.Core
- SimpleDroidSql
This simple example isn't a good architecture (all the logic is in the ViewModel), but it does make it easy(ish) to see the SQLite connection at work - e.g. you can see how it is created in the ViewModel :
public ListViewModel()
{
Cirrious.MvvmCross.Plugins.Sqlite.PluginLoader.Instance.EnsureLoaded();
var factory = this.GetService<ISQLiteConnectionFactory>();
var connection = factory.Create("SimpleList");
connection.CreateTable<ListItem>();
_items = new DatabaseBackedObservableCollection<ListItem, int>(connection, listItem => -listItem.Id);
}
And you can see how it is queried in my DatabaseBackedObservableCollection<T> :
public void Add(T item)
{
_connection.Insert(item);
RaiseCollectionChanged();
}
public int Count { get { return _connection.Table<T>().Count(); }}
public bool Remove(T item)
{
var result = _connection.Delete(item);
return true;
}
public T this[int index]
{
get { return _connection.Table<T>().OrderBy(_sortOrder).Skip(index).FirstOrDefault(); }
set { throw new NotImplementedException(); }
}
Note - DatabaseBackedObservableCollection<T> is definitely not optimal code -but it works well for a demo :)
And the MonoDroid specific code.... it is, of course, just XML with bindings:
[Activity(Label = "SimpleDroidSql", MainLauncher = true, Icon = "@drawable/icon")]
public sealed class MainActivity : MvxSimpleBindingActivity<ListViewModel>
{
public MainActivity()
{
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
if (ViewModel == null)
ViewModel = new ListViewModel();
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
}
}
Loading an xml list binding of:
And list item templates that include:
Really glad this conversation happened - adding a proper SQLite layer has been on the TODO list for MvvmCross for a long time.
I'll update this further with the other platforms at some point soon - and I may also add Vici plugins at some point too - I've used their sqlite wrapper before - it worked really well - http://viciproject.com/wiki/projects/coolstorage/home
Tuesday, October 09, 2012
An attempt at making SQLite-net more portable
Sunday, October 07, 2012
Portable Class Library discussion in MonoTouch/MonoDroid
Friday, October 05, 2012
Error 13 /platform:anycpu32bitpreferred is not a valid setting for option /target:library or /target:module
Open the project file in notepad and remove <Prefer32Bit>true</Prefer32Bit> then reload it (you can also right click on the project in solution explorer, choose unload project, right click on the project again, choose edit someproject.csproj, after making the edit, save, and right click and reload.
Full image: http://i.imgur.com/XJHpD.png
Obviously there is still a need for:
And I do intend to add a WinRT.Dialog and a WindowsPhone.Dialog too...
If anyone's interested, then post here or on https://github.com/slodge/Android.Dialog/issues/4