WP7 Uri as StaticResource? - windows-phone-7

I want to define URI in the resource files, and use them on the ApplicationBar. I done it as the first answer of the following question:
WP7 Image Uri as StaticResource
likes:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=System">
<sys:Uri x:Key="MenuButton1">/Images/button1.png</sys:Uri>
<sys:Uri x:Key="MenuButton2">/Images/button2.png</sys:Uri>
</ResourceDictionary>
But it doesn't work for me, the xaml file can't be parse.
And then I found another solution that is extending the StaticResourceExtension class, see the last answer of the following question:
Is it possible to supply a type converter for a static resource in WPF?
likes:
public class MyStaticResourceExtension : StaticResourceExtension
{
public IValueConverter Converter { get; set; }
public object ConverterParameter { get; set; }
public MyStaticResourceExtension()
{
}
public MyStaticResourceExtension(object resourceKey)
: base(resourceKey)
{
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
object value = base.ProvideValue(serviceProvider);
if (Converter != null)
{
Type targetType = typeof(object);
IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (target != null)
{
DependencyProperty dp = target.TargetProperty as DependencyProperty;
if (dp != null)
{
targetType = dp.PropertyType;
}
else
{
PropertyInfo pi = target.TargetProperty as PropertyInfo;
if (pi != null)
{
targetType = pi.PropertyType;
}
}
}
value = Converter.Convert(value, targetType, ConverterParameter, CultureInfo.CurrentCulture);
}
return value;
}
}
But I don't know whether it can be used on windows phone 7, and how to implement it, can someone give me some tips or example? or help me fix the first solution. thanks in advance.

You don't want to do this in XAML, since the ApplicationBar have no support for data-binding.
Instead, you should create the ApplicationBar with C#, which also offers you the ability of doing localization.
As for defining the URLs, I recommend you use a .NET Resource File, or define a static class with navigation URLs. The only reason for defining a URL as a resource in the first place, would be because you intend to re-use it, and as such, you're likely to also need to access it from C#, thus why a Resource File would be a optimal solution.
Here's an example of how to build a ApplicationBar in C#. It also allows you to add more features, like transparency toggling.

using the datatemplate may figure out your issue.

Related

Dynamic ViewModel navigation

I am trying to find a way to be able to set from the View to what ViewModel I have to navigate. This is to be able to change the navigation flow without changing the core project.
I thought the easier way would be creating an interface, setting the target ViewModel there and injecting the interface into the ViewModel to then perform the navigation.
public interface IModelMapping
{
MvxViewModel ViewModelToNavigate();
}
public class MyViewModel : MvxViewModel
{
readonly IMvxNavigationService navigationService;
readonly IModelMapping modelMapping;
public MyViewModel(IMvxNavigationService navigationService, IModelMapping modelMapping)
{
this.navigationService = navigationService;
this.modelMapping = modelMapping;
}
public IMvxAsyncCommand GoContent
{
get
{
IMvxViewModel vm = modelMapping.ViewModelToNavigate();
IMvxAsyncCommand navigateCommand = new MvxAsyncCommand(() => navigationService.Navigate<vm>());
return navigteCommand;
}
}
}
The problem with this code is I am getting an error setting the navigationService.Navigate(). The error is 'vm is a variable but it is used like a type'
What about using the URI navigation together with the facade? See also https://www.mvvmcross.com/documentation/fundamentals/navigation#uri-navigation
Say you are building a task app and depending on the type of task you want to show a different view. This is where NavigationFacades come in handy (there is only so much regular expressions can do for you).
mvx://task/?id=00 <– this task is done, show read-only view (ViewModelA)
mvx://task/?id=01 <– this task isn’t, go straight to edit view (ViewModelB)
[assembly: MvxRouting(typeof(SimpleNavigationFacade), #"mvx://task/\?id=(?<id>[A-Z0-9]{32})$")]
namespace *.NavigationFacades
{
public class SimpleNavigationFacade
: IMvxNavigationFacade
{
public Task<MvxViewModelRequest> BuildViewModelRequest(string url,
IDictionary<string, string> currentParameters, MvxRequestedBy requestedBy)
{
// you can load data from a database etc.
// try not to do a lot of work here, as the user is waiting for the UI to do something ;)
var viewModelType = currentParameters["id"] == Guid.Empty.ToString("N") ? typeof(ViewModelA) : typeof(ViewModelB);
return Task.FromResult(new MvxViewModelRequest(viewModelType, new MvxBundle(), null, requestedBy));
}
}
}

How to change password masking character in Xamarin forms - Entry

I've currently faced a rather simple issue which eventually put me to a dead end. I am building an application that uses Xamarin Forms and want to change a masking character when user enters password from a bullet to an asterisk.
For entering password I'm using Entry control in Portable lib project in my content page (in VS2017 professional):
<Entry x:Name="Entry_Password" Placeholder="Password" IsPassword="True" />
I know that I probably should create a custom Renderer in Android project for this one, but would really appreciate how to do it for this specific purpose.
Am sure the converter answer will work , but as a personal preference i dont like it. this looks like a renderer job to me .
and here is how i would do it(example only in android because i dont have ios, but its fairly simple to implement it there)
Usage Xamarin forms
<controls:PasswordBox Placeholder="Password"/>
The Renderer (Android)
[assembly: ExportRenderer(typeof(PasswordBox), typeof(PasswordBoxRenderer))]
namespace PasswordAsterisk.Droid.Renderers
{
public class PasswordBoxRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.InputType = Android.Text.InputTypes.TextVariationPassword |
Android.Text.InputTypes.ClassText;
Control.TransformationMethod = new HiddenPasswordTransformationMethod();
}
}
}
internal class HiddenPasswordTransformationMethod : Android.Text.Method.PasswordTransformationMethod
{
public override Java.Lang.ICharSequence GetTransformationFormatted(Java.Lang.ICharSequence source, Android.Views.View view)
{
return new PasswordCharSequence(source);
}
}
internal class PasswordCharSequence : Java.Lang.Object, Java.Lang.ICharSequence
{
private Java.Lang.ICharSequence _source;
public PasswordCharSequence(Java.Lang.ICharSequence source)
{
_source = source;
}
public char CharAt(int index)
{
return '*';
}
public int Length()
{
return _source.Length();
}
public Java.Lang.ICharSequence SubSequenceFormatted(int start, int end)
{
return _source.SubSequenceFormatted(start, end);
}
public IEnumerator<char> GetEnumerator()
{
return _source.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _source.GetEnumerator();
}
}
}
full source code example in GitHub
An easyier way to do this would be to use a Converter to swap every letter in an asterisk and than when you request the value it is plain.
This is an interesting post that could help you with your problem: https://forums.xamarin.com/discussion/52354/is-there-a-way-to-partially-mask-an-entry-field-in-xamarin
It's imported to use oneway and not twoway!
Good luck

How to use different custom renderer on different versions of Android in Xamarin Forms?

I have Xamarin Forms solution and in Xamarin Droid project I have custom renderer for class CustomCameraScanView that extends ContentView. This CustomCameraScanView should use Camera (old API) on Androids before 5.0 (Lollipop) and Camera2 (new API) from 5.0 and afterwards. How can I create two renderers: CustomCameraScanViewRenderer_Droid4 and CustomCameraScanViewRenderer_Droid5 that will be used on different versions of OS?
My CustomCameraScanViewRenderer_Droid4 looks like this:
[assembly: ExportRenderer(typeof(CustomCameraScanView), typeof(CustomCameraScanViewRenderer_Droid4))]
namespace Genea.Droid.Renderers
{
public class CustomCameraScanViewRenderer_Droid4 : ViewRenderer,
ISurfaceTextureListener,
ISurfaceHolderCallback,
Android.Hardware.Camera.IPreviewCallback,
Android.Hardware.Camera.IPictureCallback,
Android.Hardware.Camera.IShutterCallback
{
}
}
Unfortunately, registering a custom-renderer at runtime is not possible at this point in Xamarin-Forms. More details can be found on this forum link. But what you can do is resolve the controls at run-time using OnPlatform and build-version number.
I would of course recommend the conditional-compilation approach first as suggested by #luccas-clezar; but if that is not an option, then you can try resolving your control (and hence the renderer) at run-time using following steps.
Steps:
Create an simple contract to resolve current API value - in forms project
public interface IBuildVersion { int Number { get; } }
Implement it for Android platform
public class AndroidBuildVersion : IBuildVersion
{
public int Number { get { return ((int)Android.OS.Build.VERSION.SdkInt); } }
}
Register on DependencyService
[assembly: Xamarin.Forms.Dependency (typeof (AndroidBuildVersion))]
Subclass your CustomCameraScanView into two derived types - in forms project
public class CustomCameraScanView_Droid4 : CustomCameraScanView { }
public class CustomCameraScanView_Droid5 : CustomCameraScanView { }
Setup your renderers in Android project
[assembly: ExportRenderer(typeof(CustomCameraScanView_Droid4), typeof(CustomCameraScanViewRenderer_Droid4))]
and,
[assembly: ExportRenderer(typeof(CustomCameraScanView_Droid5), typeof(CustomCameraScanViewRenderer_Droid5))]
Create custom-control to resolve at run-time - using OnPlatform - in forms project
public class CameraScanContentView : Xamarin.Forms.ContentView
{
public CameraScanContentView()
{
this.Content = Device.OnPlatform(
iOS: new CustomCameraScanView(),
Android: DependencyService.Get<IBuildVersion>().Number < 21
? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
: ((CustomCameraScanView)new CustomCameraScanView_Droid5()),
WinPhone: new CustomCameraScanView()
);
}
}
And, XAML usage will look like this
<local:CameraScanContentView />
Update 05/24
I don't believe Xamarin-Forms supports 'Property Value' inheritance as WPF does - so it is kind of tricky to propagate the values from parent to child control.
One option is to cascade these values back to CustomCameraScanView from CameraScanContentView by defining bindable-properties (recommended):
public class CameraScanContentView : Xamarin.Forms.ContentView
{
public CameraScanContentView()
{
CustomCameraScanView scannerCtrl = null;
switch (Device.RuntimePlatform)
{
case Device.Android:
scannerCtrl = DependencyService.Get<IBuildVersion>().Number < 21
? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
: ((CustomCameraScanView)new CustomCameraScanView_Droid5());
break;
default:
scannerCtrl = new CustomCameraScanView();
break;
}
scannerCtrl.SetBinding(CustomCameraScanView.IsScanningProperty, new Binding(nameof(IsScanning), source: this));
scannerCtrl.SetBinding(CustomCameraScanView.IsTakingImageProperty, new Binding(nameof(IsTakingImage), source: this));
scannerCtrl.SetBinding(CustomCameraScanView.IsFlashlightOnProperty, new Binding(nameof(IsFlashlightOn), source: this));
Content = scannerCtrl;
}
public static readonly BindableProperty IsScanningProperty = BindableProperty.Create("IsScanning", typeof(bool), typeof(CameraScanContentView), false);
public static readonly BindableProperty IsTakingImageProperty = BindableProperty.Create("IsTakingImage", typeof(bool), typeof(CameraScanContentView), false);
public static readonly BindableProperty IsFlashlightOnProperty = BindableProperty.Create("IsFlashlightOn", typeof(bool), typeof(CameraScanContentView), false);
public bool IsScanning
{
get { return (bool)GetValue(IsScanningProperty); }
set { SetValue(IsScanningProperty, value); }
}
public bool IsTakingImage
{
get { return (bool)GetValue(IsTakingImageProperty); }
set { SetValue(IsTakingImageProperty, value); }
}
public bool IsFlashlightOn
{
get { return (bool)GetValue(IsFlashlightOnProperty); }
set { SetValue(IsFlashlightOnProperty, value); }
}
}
XAML usage will then look like this
<local:CameraScanContentView IsScanning="{Binding IsScanning}" IsFlashlightOn="{Binding IsFlashlightOn}" IsTakingImage="{Binding IsTakingImage}" />
Or, you can manually define your binding-expressions as below (not recommended as it makes the assumption that the property-names on view-model will not change):
public class CameraScanContentView : Xamarin.Forms.ContentView
{
public CameraScanContentView()
{
CustomCameraScanView scannerCtrl = null;
switch (Device.RuntimePlatform)
{
case Device.Android:
scannerCtrl = DependencyService.Get<IBuildVersion>().Number < 21
? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
: ((CustomCameraScanView)new CustomCameraScanView_Droid5());
break;
default:
scannerCtrl = new CustomCameraScanView();
break;
}
scannerCtrl.SetBinding(CustomCameraScanView.IsScanningProperty, new Binding("IsScanning", source: this.BindingContext));
scannerCtrl.SetBinding(CustomCameraScanView.IsTakingImageProperty, new Binding("IsTakingImage", source: this.BindingContext));
scannerCtrl.SetBinding(CustomCameraScanView.IsFlashlightOnProperty, new Binding("IsFlashlightOn", source: this.BindingContext));
Content = scannerCtrl;
}
}
Note: My first instinct was to use an implicit style targeting CustomCameraScanView to bind the values - but somehow couldn't get it to work.
There's no need to have two renderers I think. Something like this should work:
if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop)
{
// Access old API
}
else
{
// Access new API
}
Another method of doing the same thing is by adding compiler directives. Like so:
#if __ANDROID_21__
// New API (>=21)
#else
// Old API (<21)
#endif
This will compile only the specific code of that Android API. I'm not sure if this works with PCL projects and the only thing that I could find that said something about it is this line from Dealing with Multiple Platforms guide: "Conditional compilation works best with Shared Asset Projects, where the same source file is being referenced in multiple projects that have different symbols defined.". Anyway, I think you could give it a try.
Hope it helps! :)
You will probably have to put some code like the code below inside the renderers so their methods don't get called unless a certain platform requirement is met:
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
// Lollipop specific stuff
}
There is no mechanism in place to actually point to a different renderer on different OS versions.
You can put the following code in your main activity right after Forms.Init() (if you are using forms)
if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
Xamarin.Forms.Internals.Registrar.Registered.Register(typeof(Xamarin.Forms.Picker), typeof(PickerRendererEx));
}
else
{
Xamarin.Forms.Internals.Registrar.Registered.Register(typeof(Xamarin.Forms.Picker), typeof(PickerRendererExOld));
}

How to implement a custom presenter in a Windows UWP (Xamarin, MvvmCross)

I have the following code in my Android app, it basically uses one page (using a NavigationDrawer) and swaps fragments in/out of the central view. This allows the navigation to occur on one page instead of many pages:
Setup.cs:
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
var customPresenter = new MvxFragmentsPresenter();
Mvx.RegisterSingleton<IMvxFragmentsPresenter>(customPresenter);
return customPresenter;
}
ShellPage.cs
public class ShellPage : MvxCachingFragmentCompatActivity<ShellPageViewModel>, IMvxFragmentHost
{
.
.
.
public bool Show(MvxViewModelRequest request, Bundle bundle)
{
if (request.ViewModelType == typeof(MenuContentViewModel))
{
ShowFragment(request.ViewModelType.Name, Resource.Id.navigation_frame, bundle);
return true;
}
else
{
ShowFragment(request.ViewModelType.Name, Resource.Id.content_frame, bundle, true);
return true;
}
}
public bool Close(IMvxViewModel viewModel)
{
CloseFragment(viewModel.GetType().Name, Resource.Id.content_frame);
return true;
}
.
.
.
}
How can I achieve the same behavior in a Windows UWP app? Or rather, is there ANY example that exists for a Windows MvvmCross app which implements a CustomPresenter? That may at least give me a start as to how to implement it.
Thanks!
UPDATE:
I'm finally starting to figure out how to go about this with a customer presenter:
public class CustomPresenter : IMvxWindowsViewPresenter
{
IMvxWindowsFrame _rootFrame;
public CustomPresenter(IMvxWindowsFrame rootFrame)
{
_rootFrame = rootFrame;
}
public void AddPresentationHintHandler<THint>(Func<THint, bool> action) where THint : MvxPresentationHint
{
throw new NotImplementedException();
}
public void ChangePresentation(MvxPresentationHint hint)
{
throw new NotImplementedException();
}
public void Show(MvxViewModelRequest request)
{
if (request.ViewModelType == typeof(ShellPageViewModel))
{
//_rootFrame?.Navigate(typeof(ShellPage), null); // throws an exception
((Frame)_rootFrame.UnderlyingControl).Content = new ShellPage();
}
}
}
When I try to do a navigation to the ShellPage, it fails. So when I set the Content to the ShellPage it works, but the ShellPage's ViewModel is not initialized automatically when I do it that way. I'm guessing ViewModels are initialized in MvvmCross using OnNavigatedTo ???
I ran into the same issue, and built a custom presenter for UWP. It loans a couple of ideas from an Android sample I found somewhere, which uses fragments. The idea is as follows.
I have a container view which can contain multiple sub-views with their own ViewModels. So I want to be able to present multiple views within the container.
Note: I'm using MvvmCross 4.0.0-beta3
Presenter
using System;
using Cirrious.CrossCore;
using Cirrious.CrossCore.Exceptions;
using Cirrious.MvvmCross.ViewModels;
using Cirrious.MvvmCross.Views;
using Cirrious.MvvmCross.WindowsUWP.Views;
using xxxxx.WinUniversal.Extensions;
namespace xxxxx.WinUniversal.Presenters
{
public class MvxWindowsMultiRegionViewPresenter
: MvxWindowsViewPresenter
{
private readonly IMvxWindowsFrame _rootFrame;
public MvxWindowsMultiRegionViewPresenter(IMvxWindowsFrame rootFrame)
: base(rootFrame)
{
_rootFrame = rootFrame;
}
public override async void Show(MvxViewModelRequest request)
{
var host = _rootFrame.Content as IMvxMultiRegionHost;
var view = CreateView(request);
if (host != null && view.HasRegionAttribute())
{
host.Show(view as MvxWindowsPage);
}
else
{
base.Show(request);
}
}
private static IMvxWindowsView CreateView(MvxViewModelRequest request)
{
var viewFinder = Mvx.Resolve<IMvxViewsContainer>();
var viewType = viewFinder.GetViewType(request.ViewModelType);
if (viewType == null)
throw new MvxException("View Type not found for " + request.ViewModelType);
// Create instance of view
var viewObject = Activator.CreateInstance(viewType);
if (viewObject == null)
throw new MvxException("View not loaded for " + viewType);
var view = viewObject as IMvxWindowsView;
if (view == null)
throw new MvxException("Loaded View is not a IMvxWindowsView " + viewType);
view.ViewModel = LoadViewModel(request);
return view;
}
private static IMvxViewModel LoadViewModel(MvxViewModelRequest request)
{
// Load the viewModel
var viewModelLoader = Mvx.Resolve<IMvxViewModelLoader>();
return viewModelLoader.LoadViewModel(request, null);
}
}
}
IMvxMultiRegionHost
using Cirrious.MvvmCross.ViewModels;
using Cirrious.MvvmCross.WindowsUWP.Views;
namespace xxxxx.WinUniversal.Presenters
{
public interface IMvxMultiRegionHost
{
void Show(MvxWindowsPage view);
void CloseViewModel(IMvxViewModel viewModel);
void CloseAll();
}
}
RegionAttribute
using System;
namespace xxxxx.WinUniversal.Presenters
{
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegionAttribute
: Attribute
{
public RegionAttribute(string regionName)
{
Name = regionName;
}
public string Name { get; private set; }
}
}
These are the three foundational classes you need. Next you'll need to implement the IMvxMultiRegionHost in a MvxWindowsPage derived class.
This is the one I'm using:
HomeView.xaml.cs
using System;
using System.Diagnostics;
using System.Linq;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using Cirrious.MvvmCross.ViewModels;
using Cirrious.MvvmCross.WindowsUWP.Views;
using xxxxx.Shared.Controls;
using xxxxx.WinUniversal.Extensions;
using xxxxx.WinUniversal.Presenters;
using xxxxx.Core.ViewModels;
namespace xxxxx.WinUniversal.Views
{
public partial class HomeView
: MvxWindowsPage
, IMvxMultiRegionHost
{
public HomeView()
{
InitializeComponent();
}
// ...
public void Show(MvxWindowsPage view)
{
if (!view.HasRegionAttribute())
throw new InvalidOperationException(
"View was expected to have a RegionAttribute, but none was specified.");
var regionName = view.GetRegionName();
RootSplitView.Content = view;
}
public void CloseViewModel(IMvxViewModel viewModel)
{
throw new NotImplementedException();
}
public void CloseAll()
{
throw new NotImplementedException();
}
}
}
The last piece to make this work is the way the actual xaml in the view is set-up. You'll notice that I'm using a SplitView control, and that I'm replacing the Content property with the new View that's coming in in the ShowView method on the HomeView class.
HomeView.xaml
<SplitView x:Name="RootSplitView"
DisplayMode="CompactInline"
IsPaneOpen="false"
CompactPaneLength="48"
OpenPaneLength="200">
<SplitView.Pane>
// Some ListView with menu items.
</SplitView.Pane>
<SplitView.Content>
// Initial content..
</SplitView.Content>
</SplitView>
EDIT:
Extension Methods
I forgot to post the two extension methods to determine if the view declares a [Region] attribute.
public static class RegionAttributeExtentionMethods
{
public static bool HasRegionAttribute(this IMvxWindowsView view)
{
var attributes = view
.GetType()
.GetCustomAttributes(typeof(RegionAttribute), true);
return attributes.Any();
}
public static string GetRegionName(this IMvxWindowsView view)
{
var attributes = view
.GetType()
.GetCustomAttributes(typeof(RegionAttribute), true);
if (!attributes.Any())
throw new InvalidOperationException("The IMvxView has no region attribute.");
return ((RegionAttribute)attributes.First()).Name;
}
}
Hope this helps.
As the link to the blog of #Stephanvs is no longer active I was able to pull the content off the Web Archive, i'll post it here for who ever is looking for it:
Implementing a Multi Region Presenter for Windows 10 UWP and MvvmCross
18 October 2015 on MvvmCross, Xamarin, UWP, Windows 10, Presenter > Universal Windows Platform
I'm upgrading a Windows Store app to the new Windows 10 Universal
Windows Platform. MvvmCross has added support for UWP in v4.0-beta2.
A new control in the UWP is the SplitView control. Basically it
functions as a container view which consist of two sub views, shown
side-by-side. Mostly it's used to implement the (in)famous hamburger
menu.
By default MvvmCross doesn't know how to deal with the SplitView, and
just replaces the entire screen contents with a new View when
navigating between ViewModels. If however we want to lay-out our views
differently and show multiple views within one window, we need a
different solution. Luckily we can plug-in a custom presenter, which
will take care of handling the lay-out per platform.
Registering the MultiRegionPresenter
In the Setup.cs file in your UWP project, you can override the
CreateViewPresenter method with the following implementation.
protected override IMvxWindowsViewPresenter CreateViewPresenter(IMvxWindowsFrame rootFrame)
{
return new MvxWindowsMultiRegionViewPresenter(rootFrame);
}
Using Regions
We can define a region by declaring a
element. At this point it has to be a Frame type because then we can
also show a nice transition animation when switching views.
<mvx:MvxWindowsPage ...>
<Grid>
<!-- ... -->
<SplitView>
<SplitView.Pane>
<!-- Menu Content as ListView or something similar -->
</SplitView.Pane>
<SplitView.Content>
<Frame x:Name="MainContent" />
</SplitView.Content>
</SplitView>
</Grid>
</mvx:MvxWindowsPage>
Now we want to be able when a ShowViewModel(...) occurs to swap out
the current view presented in the MainContent frame.
Showing Views in a Region
In the code-behind for a View we can now declare a MvxRegionAttribute,
defining in which region we want this View to be rendered. This name
has to match a Frame element in the view.
[MvxRegion("MainContent")]
public partial class PersonView
{
// ...
}
It's also possible to declare multiple regions within the same view.
This would allow you to split up your UI in more re-usable pieces.
Animating the Transition between Content Views
If you want a nice animation when transitioning between views in the
Frame, you can add the following snippet to the Frame declaration.
<Frame x:Name="MainContent">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition>
<NavigationThemeTransition.DefaultNavigationTransitionInfo>
<EntranceNavigationTransitionInfo />
</NavigationThemeTransition.DefaultNavigationTransitionInfo>
</NavigationThemeTransition>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
The contents will now be nicely animated when navigating.
Hope this helps, Stephanvs

mvvmlight - what's the "proper way" of picking up url parameters for a view model

I'm just switching a project across to mvvmlight and trying to do things "the right way"
I've got a simple app with a listbox
When an item is selected in the listbox, then I've hooked up a RelayCommand
This RelayCommand causes a call on an INavigationService (http://geekswithblogs.net/lbugnion/archive/2011/01/06/navigation-in-a-wp7-application-with-mvvm-light.aspx) which navigates to a url like "/DetailPage.xaml?DetailId=12"
The DetailPage.xaml is then loaded and ... this is where I'm a bit unsure...
how should the DetailPage get hooked up to a DetailView with DetailId of 12?
should I do this in Xaml somehow using a property on the ViewLocator?
should I do this in the NavigatedTo method?
Please feel free to point me to a full sample - sure this has been done a (hundred) thousand times before, but all the blogs and tutorials seem to be skipping this last trivial detail (focussing instead on the messaging and on the ioc on on the navigationservice)
Thanks!
The only place you can retrieve the URL parameter is in the view. So since your view is likely depending on it, you should fetch it in the OnNavigatedTo method.
Then, you should pass it along to your viewmodel, either using messaging (to expensive if you ask me), or by referring to your datacontext (which is the viewmodel I presume), and execeuting a method on that.
private AddTilePageViewModel ViewModel
{
get
{
return DataContext as AddTilePageViewModel;
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var postalCode = NavigationContext.TryGetKey("PostalCode");
var country = NavigationContext.TryGetStringKey("Country");
if (postalCode.HasValue && string.IsNullOrEmpty(country) == false)
{
ViewModel.LoadCity(postalCode.Value, country);
}
base.OnNavigatedTo(e);
}
I'm using some special extensions for the NavigationContext to make it easier.
namespace System.Windows.Navigation
{
public static class NavigationExtensions
{
public static int? TryGetKey(this NavigationContext source, string key)
{
if (source.QueryString.ContainsKey(key))
{
string value = source.QueryString[key];
int result = 0;
if (int.TryParse(value, out result))
{
return result;
}
}
return null;
}
public static string TryGetStringKey(this NavigationContext source, string key)
{
if (source.QueryString.ContainsKey(key))
{
return source.QueryString[key];
}
return null;
}
}
}
Create a new WindowsPhoneDataBound application, it has an example of how to handle navigation between views. Basically you handle the navigation part in your view, then set the view's DataContext accord to the query string. I think it plays nicely with the MVVM pattern since your ViewModels don't have to know anything about navigation (which IMO should be handled at the UI level).

Resources