MVVMCross programmatically change start ViewModel - mvvmcross

The portable class library defines the start view model. This scenario generally sounds great but I was considering this. You have written a iOS universal application or Android that needs to change its start screen / view model. If application is a phone, the default view model is login but if it is tablet, you want a different view model as the start. Is there an override or a way to take control of this?

See the Wiki section - https://github.com/MvvmCross/MvvmCross/wiki/Customising-using-App-and-Setup#custom-imvxappstart - this has an example of programmatic switching:
If more advanced startup logic is needed, then a custom app start can be used - e.g.
public class CustomAppStart
: MvxNavigatingObject
, IMvxAppStart
{
public void Start(object hint = null)
{
var auth = Mvx.Resolve<IAuth>();
if (auth.Check())
{
ShowViewModel<HomeViewModel>();
}
else
{
ShowViewModel<LoginViewModel>();
}
}
}
This can then be registered in App using:
RegisterAppStart(new CustomAppStart());

In your App class you could register an AppStart that is a splash screen:
RegisterAppStart<SplashScreenViewModel>()
In that splash screen you could receive a service that verifies if it's a tablet or a phone. You would need to create a plugin to make this verification. (There are other stackoverflow questions showing how to verify this / How to detect device is Android phone or Android tablet? )
public SplashScreenViewModel(ITabletVerificationService tabletVerificationService)
Then you would simply change screen according to this service
if(tabletVerificationService.IsTablet())
{
ShowViewModel<TabletViewModel>
}
else
{
ShowViewModel<LoginViewModel>
}
Hope it helps =)

Here's my implementation of this scenario, if it could help:
PCL:
public enum PlateformType
{
Android,
iPhone,
WindowsPhone,
WindowsStore
}
public interface IPlateformInfos
{
PlateformType GetPlateformType();
}
public class CustomAppStart
: MvxNavigatingObject
, IMvxAppStart
{
public void Start(object hint = null)
{
var plateformInfos = Mvx.Resolve<IPlateformInfos>();
var plateformType = plateformInfos.GetPlateformType();
switch (plateformType)
{
default:
ShowViewModel<MenuViewModel>();
break;
case PlateformType.WindowsPhone:
case PlateformType.WindowsStore:
ShowViewModel<FirstViewModel>();
break;
}
}
}
PCL App.cs:
RegisterAppStart(new CustomAppStart());
UI (ex: WindowsPhone):
public class PlateformInfos : IPlateformInfos
{
public PlateformType GetPlateformType()
{
return PlateformType.WindowsPhone;
}
}
UI Setup.cs:
protected override void InitializeFirstChance()
{
Mvx.RegisterSingleton<IPlateformInfos>(new PlateformInfos());
base.InitializeFirstChance();
}
Pretty simple way.

Related

Hardware Back button is not working in (Webview ) windows phone 8

I am having trouble getting the hardware back button to do what I would like it to do for the Windows Phone 8. The app is strictly just webview, so as of now when a back (hardware) button is clicked it closes the app but i want to back just previous page. I put the the URL in constructor like below
namespace Masala
{
public partial class Entertainment : PhoneApplicationPage
{
public Entertainment()
{
InitializeComponent();
var targetUri = new Uri("http://mobile-masala.com");
WebBrowser.Navigate(targetUri);
}
}
}
Add following code in your page.xam.cs to handle back button press...
protected override void OnBackKeyPress(CancelEventArgs e)
{
if(WebBrowser.CanGoBack)// your code... check the web view that you can go back or it is the main page.
{
WebBrowser.GoBack();
e.Cancel = true;
}
}

GWT Responsive Design solution

i am working on GWT to make web application but now i need to make my web applications in Responsive design but GWT not support Responsive Design please help me.
GWT supports responsive design just like any other widget toolkit (OK, that's not exactly true, there are probably widget toolkits that do a better job): do your layout with HTMLPanel, FlowPanel, SimplePanel and responsive CSS, or go the active layout route with layout panels and doing calculations in your code (or in a custom layout panel).
You can make your layout responsive using CSS media queries.
For example, to make dialog boxes occupy 90% of the available horizontal space on devices that have screen size up to 640px, one can wrap the style inside #media block like this:
#media all and (max-width: 640px) {
.gwt-DialogBox {
width: 90%;
}
}
Unfortunately (as of today) GWT compiler does not support media CSS, so the code above will fail if you use it in conjunction with CssResource.
One of the approaches to this problem is to split your CSS resources into two files.
All default (desktop) CSS styles would go to the first file (e.g. main.css), and all your mobile overrides would go to the second file (e.g. mobile.css).
Note that style names that you want to override for mobile need to be tagged as #external in the main.css to avoid name obfuscation by gwt compiler.
main.css:
#external .mainNorthPanel;
.mainNorthPanel {
position: fixed;
top: 0px;
}
mobile.css:
#media all and (max-width: 640px) {
.mainNorthPanel {
position: absolute;
top: -3em;
}
}
In your application ClientBundle, use main.css in conjunction with your CssResource interface, and define the mobile file as an external resource:
public interface MyBundle extends ClientBundle {
public interface MainStyles extends CssResource {
String mainNorthPanel();
}
#Source("css/main.css")
MainStyles css();
#Source("css/mobile.css")
TextResource mobile();
}
And finally inject your external CSS resource somewhere in the module initialization:
String mobileCss = myBundle.mobile().getText();
StyleInjector.injectAtEnd(mobileCss)
For the full working example, take a look at this JavaWorld post that just came out recently:
http://www.javaworld.com/article/2842875/java-web-development/responsive-web-design-with-google-web-toolkit.html
It covers some basic concepts such css-based responsive views, dialogs, and menus.
And there is a little proof of concept on github:
https://github.com/cuppafame/gwt-responsive
In addition to what Thomas said you can look into gwt-bootstrap. They have a custom DataGrid widget that can be shown or hidden based on breakpoints (tablets, phones, etc).
If you actually want to hide and show columns based on available size you extend the DataGrid and do something along this lines:
ResponsiveDataGrid extends DataGrid<myDTO> {
private final Column<myDTO,String> column1;
private final Column<myDTO,String> column2;
private Boolean isCompact;
public ResponsiveDataGrid(int pageSize, Resources resources,ActionCell.Delegate<myDTO> actionDelegate) {
super(pageSize, resources,new EntityProxyKeyProvider<myDTO>());
initColumns();
}
private void initColumns() {
// init your columns
}
private void updateColumns() {
int columnCount = getColumnCount();
for (int i =columnCount-1;i>=0;i--) {
removeColumn(i);
}
removeUnusedColGroups();
if (isCompact) {
// show columns for compact size
}
else {
// show all columns
}
}
#Override
protected int getRealColumnCount() {
return getColumnCount();
}
// WORKAROUND for some sizing issues in DataGrid
private void removeUnusedColGroups() {
int columnCount = getColumnCount();
NodeList<Element> colGroups = getElement().getElementsByTagName("colgroup");
for (int i = 0; i < colGroups.getLength(); i++) {
Element colGroupEle = colGroups.getItem(i);
NodeList<Element> colList = colGroupEle.getElementsByTagName("col");
for (int j = colList.getLength()-1;j>=0; j--) {
colGroupEle.removeChild(colList.getItem(j));
}
}
}
#Override
public void onResize() {
super.onResize();
if (!isAttached()) {
return;
}
// or whatever breakpoint you want to support
boolean isNewCompact = (getOffsetWidth() < 800);
if (isCompact == null || isNewCompact != isCompact) {
isCompact = isNewCompact;
updateColumns();
}
}
}
/*The best way to do responsive web with is to use Timer class and Window class in GWT as Gwt does not responsive web at the moment. I have been searching on the web for about a week now and it was a waist of my time, even Google does not know how to do that. I came out with a very straight forward solution by using Window class and Timer class and it works like a magic.*/
public class View extends VerticalPanel{
private FlexTable flexTable=new FlexTable();
private Button[]buyAndSellButtons = new Button[2];
private TextBox[] textField=new TextBox[2];
private Label alert=new Label();
private LinkedList <String> stock=new LinkedList<>();
public View(){
createComponents();
}
public VerticalPanel createComponents() {
// Assume that the host HTML has elements defined whose
// IDs are "slot1", "slot2". In a real app, you probably would not want
// to hard-code IDs. Instead, you could, for example, search for all
// elements with a particular CSS class and replace them with widgets.
//
HorizontalPanel[] horizontalPanel = new HorizontalPanel[4];
for (int x = 0; x < horizontalPanel.length; x++) {
horizontalPanel[x] = new HorizontalPanel();
}
alert.setStyleName("alert");
add(alert);
flexTable.setText(0, 0, "BUY Orders");
flexTable.getCellFormatter().setStyleName(0, 0, "orderMatcherListHeader");
flexTable.setText(0, 1, "SELL Orders");
flexTable.getCellFormatter().setStyleName(0, 1, "orderMatcherListHeader");
flexTable.setStyleName("flexTable");
flexTable.setWidth("33em");
flexTable.setCellSpacing(5);
flexTable.setCellPadding(3);
add(flexTable);
Label[] labels = new Label[2];
labels[0] = new Label("Volume");
labels[1] = new Label("Price");
for (Label label : labels) {
label.setStyleName("label");
horizontalPanel[1].add(label);
horizontalPanel[1].setStyleName("labelPosition");
}
textField[0] = new TextBox();
textField[0].setTitle("Volume");
textField[1] = new TextBox();
textField[1].setTitle("Price");
for (TextBox textBox : textField) {
textBox.setStyleName("textField");
textBox.setFocus(true);
horizontalPanel[2].add(textBox);
}
buyAndSellButtons[0] = new Button("BUY");
buyAndSellButtons[1] = new Button("SELL");
for (Button button : buyAndSellButtons) {
horizontalPanel[3].add(button);
button.setStyleName("buttons");
horizontalPanel[3].setStyleName("buttonPosition");
}
VerticalPanel[] mainPanel = new VerticalPanel[1];
mainPanel[0] = new VerticalPanel();
for (HorizontalPanel aHorizontalPanel : horizontalPanel) {
mainPanel[0].add(aHorizontalPanel);
mainPanel[0].setStyleName("mainPanel_1");
setStyleName("mainPanel");
add(mainPanel[0]);
Window.addResizeHandler(new ResizeHandler() {
#Override
public void onResize(ResizeEvent event) {
alert.setText("" + Window.getClientWidth());
}
});
}
Timer timer=new Timer() {
int x;
#Override
public void run() {
alert.setText(Window.getClientWidth()+"Attach" + x++);
String[] gadget=new String[10];
gadget[0]=("354"); //android portrait
gadget[1]=("625");
gadget[2]=("314");
gadget[3]=("474");
gadget[4]=("369");
gadget[5]=("562");
gadget[6]=("617");// android landscape
gadget[7]=("48");
gadget[8]=("730");
alert.setText("" + Window.getClientWidth()+x++);
if(Window.getClientWidth()<=425) {
flexTable.getCellFormatter().setStyleName(0, 0, "orderMatcherListHeader_1");
flexTable.getCellFormatter().setStyleName(0, 1, "orderMatcherListHeader_1");
mainPanel[0].setStyleName("phonePortrait_1");
setStyleName("phonePortrait");
flexTable.setStyleName("flexTable_1");
if(Window.getClientWidth()==414){
flexTable.setWidth("26.2em");
}{
flexTable.setWidth("24.2em");
}
flexTable.setCellSpacing(5);
flexTable.setCellPadding(3);
}
else if((Window.getClientWidth()>425)&&(Window.getClientWidth()<=812)) {
alert.setText("" + Window.getClientWidth());
flexTable.getCellFormatter().setStyleName(0, 0, "orderMatcherListHeader_1");
flexTable.getCellFormatter().setStyleName(0, 1, "orderMatcherListHeader_1");
mainPanel[0].setStyleName("phoneLandScape_1");
setStyleName("phoneLandScape");
flexTable.setStyleName("flexTable_1");
flexTable.setWidth("24.2em");
flexTable.setCellSpacing(5);
flexTable.setCellPadding(3);
}else {
return;
}
}
};
timer.scheduleRepeating(500);
return this;
}

Using MvvmCross from content providers and activities

I am trying to use MvvmCross v3 in one of my applications which consists of activities, content providers and broadcast receivers. However, I am not quite succeeding.
The application consists of a Core PCL which contains logic, models and viewmodels and a Droid application which contains all MonoDroid-specific stuff.
In Core I have an App:MvxApplication class and in Droid I have a Setup:MvxSetup class which creates an App-instance and initialises stuff.
I can use the IOC parts with content providers, broadcast receivers and non-Mvx-activities without problems. When I now want to add an MvxActivity it falls apart.
When the Mvx Activity launches I get an exception "Cirrious.CrossCore.Exceptions.MvxException: MvxTrace already initialized".
Obviously I am initialising things in the wrong order / wrong place. But, I need a pointer in the right direction.
My App Class
public class App
: MvxApplication
{
public override void Initialize()
{
base.Initialize();
InitialisePlugins();
InitaliseServices();
InitialiseStartNavigation();
}
private void InitaliseServices()
{
CreatableTypes().EndingWith("Service").AsInterfaces().RegisterAsLazySingleton();
}
private void InitialiseStartNavigation()
{
}
private void InitialisePlugins()
{
// initialise any plugins where are required at app startup
// e.g. Cirrious.MvvmCross.Plugins.Visibility.PluginLoader.Instance.EnsureLoaded();
}
}
And my setup class
public class Setup
: MvxAndroidSetup
{
public Setup(Context applicationContext)
: base(applicationContext)
{
}
protected override IMvxApplication CreateApp()
{
return new App();
}
protected override IMvxNavigationSerializer CreateNavigationSerializer()
{
return new MvxJsonNavigationSerializer();
}
public override void LoadPlugins(Cirrious.CrossCore.Plugins.IMvxPluginManager pluginManager)
{
pluginManager.EnsurePluginLoaded<Cirrious.MvvmCross.Plugins.Json.PluginLoader>();
base.LoadPlugins(pluginManager);
}
public void RegisterServices()
{
// I register a bunch of singletons here
}
// The following is called from my content provider's OnCreate()
// Which is the first code that is run
public static void DoSetup(Context applicationContext)
{
var setup = new Setup(applicationContext);
setup.Initialize();
setup.RegisterServices();
}
My Content provider's OnCreate():
public override bool OnCreate()
{
Log.Debug(Tag, "OnCreate");
_context = Context;
Setup.DoSetup(_context);
return true;
}
My MvxActivity:
[Activity(Label = "#string/ApplicationName", MainLauncher = true)]
[IntentFilter(new[] { "Settings" })]
public class SettingsView
: MvxActivity
{
public new SettingsViewModel ViewModel
{
get { return (SettingsViewModel) base.ViewModel; }
set { base.ViewModel = value; }
}
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.Page_SettingsView);
}
}
Short answer (I'm in an airport on mobile)
all the mvx android views will check the setup singleton has been created - https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Droid/Platform/MvxAndroidSetupSingleton.cs (vnext tree - but similar on v3)
so if you are creating a setup, but not setting this singleton, then you will get a second setup created when you first show a view
i suspect you can just get your setup created via the singleton class, but if this isn't flexible enough for your needs, then please log an issue on github
would also love to see some blogging about this - I've not used custom content providers much (at all!)

Update UI thread from portable class library

I have an MVVM Cross application running on Windows Phone 8 which I recently ported across to using Portable Class Libraries.
The view models are within the portable class library and one of them exposes a property which enables and disables a PerformanceProgressBar from the Silverlight for WP toolkit through data binding.
When the user presses a button a RelayCommand kicks off a background process which sets the property to true which should enable the progress bar and does the background processing.
Before I ported it to a PCL I was able to invoke the change from the UI thread to ensure the progress bar got enabled, but the Dispatcher object isn't available in a PCL. How can I work around this?
Thanks
Dan
All the MvvmCross platforms require that UI-actions get marshalled back on to the UI Thread/Apartment - but each platform does this differently....
To work around this, MvvmCross provides a cross-platform way to do this - using an IMvxViewDispatcherProvider injected object.
For example, on WindowsPhone IMvxViewDispatcherProvider is provided ultimately by MvxMainThreadDispatcher in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxMainThreadDispatcher.cs
This implements the InvokeOnMainThread using:
private bool InvokeOrBeginInvoke(Action action)
{
if (_uiDispatcher.CheckAccess())
action();
else
_uiDispatcher.BeginInvoke(action);
return true;
}
For code in ViewModels:
your ViewModel inherits from MvxViewModel
the MvxViewModel inherits from an MvxApplicationObject
the MvxApplicationObject inherits from an MvxNotifyPropertyChanged
the MvxNotifyPropertyChanged object inherits from an MvxMainThreadDispatchingObject
MvxMainThreadDispatchingObject is https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxMainThreadDispatchingObject.cs
public abstract class MvxMainThreadDispatchingObject
: IMvxServiceConsumer<IMvxViewDispatcherProvider>
{
protected IMvxViewDispatcher ViewDispatcher
{
get { return this.GetService().Dispatcher; }
}
protected void InvokeOnMainThread(Action action)
{
if (ViewDispatcher != null)
ViewDispatcher.RequestMainThreadAction(action);
}
}
So... your ViewModel can just call InvokeOnMainThread(() => DoStuff());
One further point to note is that MvvmCross automatically does UI thread conversions for property updates which are signalled in a MvxViewModel (or indeed in any MvxNotifyPropertyChanged object) through the RaisePropertyChanged() methods - see:
protected void RaisePropertyChanged(string whichProperty)
{
// check for subscription before going multithreaded
if (PropertyChanged == null)
return;
InvokeOnMainThread(
() =>
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(whichProperty));
});
}
in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNotifyPropertyChanged.cs
This automatic marshalling of RaisePropertyChanged() calls works well for most situations, but can be a bit inefficient if you Raise a lot of changed properties from a background thread - it can lead to a lot of thread context switching. It's not something you need to be aware of in most of your code - but if you ever do find it is a problem, then it can help to change code like:
MyProperty1 = newValue1;
MyProperty2 = newValue2;
// ...
MyProperty10 = newValue10;
to:
InvokeOnMainThread(() => {
MyProperty1 = newValue1;
MyProperty2 = newValue2;
// ...
MyProperty10 = newValue10;
});
If you ever use ObservableCollection, then please note that MvvmCross does not do any thread marshalling for the INotifyPropertyChanged or INotifyCollectionChanged events fired by these classes - so it's up to you as a developer to marshall these changes.
The reason: ObservableCollection exists in the MS and Mono code bases - so there is no easy way that MvvmCross can change these existing implementations.
If you don't have access to the Dispatcher, you can just pass a delegate of the BeginInvoke method to your class:
public class YourViewModel
{
public YourViewModel(Action<Action> beginInvoke)
{
this.BeginInvoke = beginInvoke;
}
protected Action<Action> BeginInvoke { get; private set; }
private void SomeMethod()
{
this.BeginInvoke(() => DoSomething());
}
}
Then to instanciate it (from a class that has access to the dispatcher):
var dispatcherDelegate = action => Dispatcher.BeginInvoke(action);
var viewModel = new YourViewModel(dispatcherDelegate);
Or you can also create a wrapper around your dispatcher.
First, define a IDispatcher interface in your portable class library:
public interface IDispatcher
{
void BeginInvoke(Action action);
}
Then, in the project who has access to the dispatcher, implement the interface:
public class DispatcherWrapper : IDispatcher
{
public DispatcherWrapper(Dispatcher dispatcher)
{
this.Dispatcher = dispatcher;
}
protected Dispatcher Dispatcher { get; private set; }
public void BeginInvoke(Action action)
{
this.Dispatcher.BeginInvoke(action);
}
}
Then you can just pass this object as a IDispatcher instance to your portable class library.
Another option that could be easier is to store a reference to SynchronizationContext.Current in your class's constructor. Then, later on, you can use _context.Post(() => ...) to invoke on the context -- which is the UI thread in WPF/WinRT/SL.
class MyViewModel
{
private readonly SynchronizationContext _context;
public MyViewModel()
{
_context = SynchronizationContext.Current.
}
private void MyCallbackOnAnotherThread()
{
_context.Post(() => UpdateTheUi());
}
}

Hiding default properties for a custom visual web part

Is there a way of hiding Common properties of Web Parts? The Layout or appearance section for example.
I have created a new visual web part and I wan't to make it very easy to edit for the administrators and they don't need the standard layout / appearance settings when they go to 'edit web part'
Any ideas how to hide the base properties from the edit panel? Been searching all over but can't see anything in the documentation.
Here's one way to achieve this. In your EditorPart, mark the container of the other EditorParts as not Visible:
class EditorPartTest : EditorPart
{
protected override void CreateChildControls()
{
Parent.Controls[1].Visible = false;
Parent.Controls[2].Visible = false;
base.CreateChildControls();
}
public override bool ApplyChanges()
{
return true;
}
public override void SyncChanges()
{
}
}
And use it from your web part like this:
public class VisualWebPart1 : WebPart
{
public override EditorPartCollection CreateEditorParts()
{
ArrayList partsArray = new ArrayList();
EditorPartTest editor = new EditorPartTest();
editor.ID = this.ID + "_editorPart";
partsArray.Add(editor);
return new EditorPartCollection(partsArray);
}
}
Then you should get a result like this:
http://joelblogs.co.uk/?attachment_id=10785
Hope this helps!
joel
joelblogs.co.uk
SharePoint Architect Blog