visual studio xamarin forms mvvm - c#

I'm starting a new project, and id like to use MVVM - I really like this pattern, and I have been using it in all my windows phone 8.1 apps. But moving to xamarin is a jungle! I usually use mvvm light, and I have a nice basic implementation I use every time a create a new project - but I can't find a really good sample that shows exactly what I need.
What I want to do is make a xamarin shared (or portable) project, that shares the views across all platforms. I want to write create the view using code-behind - so no xaml.
Does anyone have experience with this and can point me to a good sample?
I'm also wondering if I need to use a thirtyparty framework afterall, since navigating seems pretty easy.

There are many samples on to be found. My favorite site for Xamarin.Forms samples is Xamarin Forms in Anger.
Let's take a look at the Jobbberr sample:
using System;
using Xamarin.Forms;
namespace InAnger.Jobbberr
{
public class SettingsPage : ContentPage
{
public SettingsPage ()
{
Style = AppStyle.SettingsPageStyle;
var pageTitle = new Frame () {
Style = AppStyle.PageTitleLabelFrameStyle,
Padding = new Thickness(0,Device.OnPlatform(15,0,0),0,10),
Content = new Label {
Style = AppStyle.PageTitleLabelStyle,
Text = "Settings",
}
};
var signoutButton = new Button () {
VerticalOptions = LayoutOptions.EndAndExpand,
HorizontalOptions = LayoutOptions.Center,
Text = "Sign Out",
TextColor = AppStyle.DarkLabelColor,
};
Content = new StackLayout {
VerticalOptions = LayoutOptions.FillAndExpand,
Padding = new Thickness (20),
Children = {
pageTitle,
new BoxView() {
HeightRequest = 1,
BackgroundColor = AppStyle.DarkLabelColor,
},
new SettingsUserView(),
new SyncView (),
new SettingsSwitchView ("GPS"),
new SettingsSwitchView ("Jobs Alert"),
signoutButton,
new StatusBarView()
}
};
}
}
}
What do you see here?
The new class SettingsPage derives from ContentPage. The controls pageTitle and signoutButton are created in its constructor. In the end you see how a StackLayout is being created, filled with the controls and set as content of the page. That's how to create a Page in code.
How to apply MVVM?
Set BindingContext = ViewModel in the first row of the constructor (create a new view model or locate it by via a ViewModelLocator or anything).
Let's say for example you want to bind the Text and Command property of signoutButton to the view model's properties SignOutButtonText and SignoutCommand. You would change the creation of the button to this:
var signoutButton = new Button () {
VerticalOptions = LayoutOptions.EndAndExpand,
HorizontalOptions = LayoutOptions.Center,
TextColor = AppStyle.DarkLabelColor,
};
signoutButton.SetBinding(Button.TextProperty, "SignOutButtonText");
signoutButton.SetBinding(Button.CommandProperty, "SignoutCommand");

Related

Device.OS in Xaml in Xamarin.Forms

How to write (Device.OS == TargetPlatform.Android) in xaml,
In My class file i created like this in c#, but i don't know how to write this in xaml,
if (Device.OS == TargetPlatform.Android)
{
var stack = new StackLayout()
{
HorizontalOptions = LayoutOptions.Center,
};
var label = new Label()
{
Content = "This design is for Android"
};
stack.Children.Add(label);
};
if (Device.OS == TargetPlatform.iOS)
{
var grid = new Grid()
{
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
var label = new Label()
{
Content = "This design is for IOS"
};
grid.Children.Add(label);
}
Please help me how to write this two different design in android and IOS in xaml.
As far as I know, this is not possible in XAML, at least not like this. Two options come to mind:
Create two pages in XAML, one for Android and one for iOS and push the right page depending on the platform, basically with the if from your code.
Or, implement something like this in one page:
<StackLayout>
<StackLayout.IsVisible>
<OnPlatform x:TypeArguments="x:Boolean">
<OnPlatform.iOS>false</OnPlatform.iOS>
<OnPlatform.Android>true</OnPlatform.Android>
</OnPlatform>
</StackLayout.IsVisible>
</Stacklayout>
And for the grid the other way around. Note: the latter might negatively impact your layout cycle
PS. Device.OS is deprecated, you should use Device.RuntimePlatform now.

What is the best way to add buttons in Xamarin Forms?

So I'm new to Xamarin Forms and I've found two ways of adding buttons:
1.Declaring the button in the .xaml file
<!-- <Button Text="Click Me!"
Clicked="OnButtonClicked" VerticalOptions="CenterAndExpand" />-->
and the .xaml.cs file
public void OnButtonClicked(object sender, EventArgs args)
{
count++;
label.Text =
String.Format("{0} click{1}!", count, count == 1 ? "" : "s");
declaring the button only in the .xaml.cs file
using System;
using Xamarin.Forms;
namespace FormsGallery
{
class ButtonDemoPage : ContentPage
{
Label label;
int clickTotal = 0;
public ButtonDemoPage()
{
Label header = new Label
{
Text = "Button",
Font = Font.BoldSystemFontOfSize(50),
HorizontalOptions = LayoutOptions.Center
};
Button button = new Button
{
Text = "Click Me!",
Font = Font.SystemFontOfSize(NamedSize.Large),
BorderWidth = 1,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
button.Clicked += OnButtonClicked;
label = new Label
{
Text = "0 button clicks",
Font = Font.SystemFontOfSize(NamedSize.Large),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
// Accomodate iPhone status bar.
this.Padding = new Thickness(10, Device.OnPlatform(20, 0, 0), 10, 5);
// Build the page.
this.Content = new StackLayout
{
Children =
{
header,
button,
label
}
};
}
void OnButtonClicked(object sender, EventArgs e)
{
clickTotal += 1;
label.Text = String.Format("{0} button click{1}",
clickTotal, clickTotal == 1 ? "" : "s");
}
}
}
but the thing is: I want to know which way is better for adding a button and to not have any future code problems.
Thank you!
Actually they are same. It depends on one's choice.
I prefer XAML over Code because
XAML is cleaner and easy to understand.
XAML seems to be able to better respect the "separation of concerns" between UI and controller logic.
It has intellisense in Visual Studio
You can find your answer here in details
https://developer.xamarin.com/guides/xamarin-forms/creating-mobile-apps-xamarin-forms/summaries/chapter07/
They are functionally equivalent. Building your UI in XAML generally allows for a cleaner separation of concerns in your design, but one approach is not "better" than the other.
They are same. After building your UI with XAML, it's converted to their equivalent with C#, doing the same thing as writing with C# the view.
Code your UI as you like. For me the better approach is XAML as its more clean and easy to understand.
I agree with the above comments that using XAML or C# depends on your preferences. Additionally I would recommend to study bindings and MVVM quite quickly because they make the UI code much cleaner. In the case of buttons you can use commands to directly refer to ViewModel instead of having Click listener in your UI code.
Here is a place where you can get started with data bindings and MVVM: https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/

DataGrid binding crashes UWP app on Xamarin

I am creating an application with Xamarin using the shared definition, and my application should run on Android and as an UWP app. This App needs to show a DataGrid with bindable values and for this I am using the Xamarin.Forms.DataGrid. I had followed the sample showed in DataGrid's repository, and it works very well on Android, but I am having an issue when I try to run as a UWP app. The issue is that, when I run as a UWP app with a populated List and try to binding this list on the DataGrid, the app crashes, showing this Exception:
"System.Runtime.InteropServices.COMException: Error HRESULT E_FAIL has been returned from a call to a COM component.
at Windows.UI.Xaml.UIElement.Measure(Size availableSize)
at Xamarin.Forms.Platform.UWP.VisualElementRenderer`2.MeasureOverride(Size availableSize)
at Windows.UI.Xaml.UIElement.Measure(Size availableSize)
at Xamarin.Forms.Platform.UWP.VisualElementRenderer`2.MeasureOverride(Size availableSize)
at Windows.UI.Xaml.UIElement.Measure(Size availableSize)
at Xamarin.Forms.Plat"
As I had said this exception only occur on UWP, and only happens when this List is populate. The list is create in this way:
private List<TableValue> _tableValues;
public List<TableValue> TableValues
{
get { return _tableValues; }
set
{
TableValues= value;
OnPropertyChanged(nameof(TableValues));
}
}
private List<TableValue> CreateTableValues()
{
return new List<TableValue>{
new TableValue{Val1="", Val2="", Val3="", Val4="", Val5="", Val6="", Val7=""}
};
}
public async Task PopulateItems()
{
_tableValues = CreateTableValues();
UpdateProperty();
}
This list is create inside of the MVVM class of the View.
The DataGrid element is create in the View in that way:
private ScrollView CreateTable()
{
table = new DataGrid();
table.Columns.Clear();
table.Columns.AddRange(CreateColumns());
table.SelectionEnabled = true;
table.BackgroundColor = Color.White;
table.SetBinding(DataGrid.ItemsSourceProperty, new Binding("TableValues"));
table.HeaderBackground = Color.FromHex("#D4D0C8");
table.HeaderFontSize = 18;
table.HeaderTextColor = Color.FromHex("#08098F");
StackLayout tableStack = new StackLayout
{
BackgroundColor = Color.White,
HeightRequest = 850,
VerticalOptions = LayoutOptions.FillAndExpand
};
tableStack.Children.Add(table);
var scroll = new ScrollView
{
BackgroundColor = Color.White,
Margin = new Thickness(5, 5, 5, 5),
Content = tableStack,
Orientation = ScrollOrientation.Horizontal,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
return scroll;
}
I searched to find a possible solution for this problem, but I was not able to find any solution, since the questions using this DataGrid in Xamarin are few common.
In Xamarin.Forms.UWP nesting a ListView inside of a ScrollView is not supported. Thats the reason why you're crashing. See more on bugzilla.

Binding a HTML control into a stacklayout using xamarin forms

Being a newbie to Xamrin I am struggling to adding some HTML to a StackLayout via Xamarin Forms. I have tried quite a few things and had a Google around.
Firstly I can't work out which bindable object I am supposed to be using. As I cannot find a straight answer on Google/Xamarin I am going to assume this is not as easy I was hoping.
var nameEntry = new Label ();
nameEntry.SetBinding (Label.TextProperty, "Club.ClubName");
var webView = new WebView ();
webView.SetBinding ( ??? , "Club.Description");
var content = new StackLayout {
Children = {
nameEntry,
???
}
};
I am not sure if this is possible within Xamarin forms itself. Can anyone help?
I should point out my data for the form is being retrieved asynchronously on a remote json endpoint
protected override void OnAppearing ()
{
base.OnAppearing ();
if (ViewModel == null || ViewModel.IsLoading)
return;
ViewModel.LoadItemsCommand.Execute (Club.ClubId);
}
My remote json api contains, Description contatins a HTML snippet which I would like to use.
{
ClubName: "Stourbridge",
Description: "<p>This club meets every TWO weeks on a <b>Friday</b>.</p>"
...
}
Try the following example that will show how to do the bindings.
Note that you have to use a HtmlWebViewSource to achieve this, and bind the WebView.Source to this.
Clicking the button will change the view model and update the WebView appropriately to the newly changed text.
StackLayout objStackLayout = new StackLayout();
MyView objMyView = new MyView();
objMyView.MyHtml = "<html><head></head><body><h1>Title</h1><p>Some body text</p></body></html>";
HtmlWebViewSource objHtmlWebViewSource = new HtmlWebViewSource();
objHtmlWebViewSource.SetBinding(HtmlWebViewSource.HtmlProperty, "MyHtml");
objHtmlWebViewSource.BindingContext = objMyView;
WebView objWebview = new WebView();
objWebview.HorizontalOptions = LayoutOptions.FillAndExpand;
objWebview.VerticalOptions = LayoutOptions.FillAndExpand;
objWebview.Source = objHtmlWebViewSource;
Button objMyButton2 = new Button();
objMyButton2.Text="Change Html";
objMyButton2.Clicked+=((o2,e2)=>
{
objMyView.MyHtml = "<html><head></head><body><h1>Title</h1><p>Some body text that has changed.</p></body></html>";
});
objStackLayout.Children.Add(objMyButton2);
objStackLayout.Children.Add(objWebview);
The view model is just a simple one with a bindable property as below:-
public class MyView
: Xamarin.Forms.View
{
public static readonly BindableProperty MyHtmlProperty = BindableProperty.Create<MyView, string>(p => p.MyHtml, default(string));
public string MyHtml
{
get { return (string)GetValue(MyHtmlProperty); }
set { SetValue(MyHtmlProperty, value); }
}
}
Before clicking the button gives:-
After clicking the button, adjusts the view model, and automatically updates the control via the binding giving:-

What approach should I take when implementing a horizontal GridView in Xamarin.Forms?

I need to implement the horizontal (magazine style) list. The apps that do this quite good (in my opinion) are Flipboard and Zite. I wondered if this is possible to implement into a Xamarin.Forms application with existing resources.
In Xamarin.Forms, you have an excellent View that is the ListView. This ListView has an ItemSource and an ItemTemplate property where you can bind your ViewModel to the ItemSource and you can bind your TextCell class to your ItemTemplate.
I'm searching for the exact same thing except that you can modify the ItemTemplate to a custom class I make myself. The reason I need this is that I need a more complex layout than TextCelland the ListView only scrolls vertically.
I like the MVVM pattern very much and I need something that exactly fits into this pattern. Now, I looked into some implementations:
https://github.com/XLabs/Xamarin-Forms-Labs
http://forums.xamarin.com/discussion/18627/gridview-with-itemssource
Option 1
In the Xamarin.Forms.Labs, there is a GridView, but this view doesn't expand to its parent in my implementation although I am setting the following:
var grid = GridView {
ItemWidth = 50,
ItemHeight = 50,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
My ItemSource is tied to my ViewModel (which I am 100% sure of it is providing items. I know that because if I swap this GridView for a ListView, there are items.):
grid.ItemSource = ViewModel.Items;
And my ItemTemplate:
var cell = new DataTemplate(typeof(TextCell));
cell.SetBinding(TextCell.TextProperty, "Title");
cell.SetBinding(TextCell.TextProperty, "Description");
gridView.ItemTemplate = cell;
Now, I know there are some problems with the GridView and that the implementation is only for iOS right now according to this.
Option 2
In the second post they mention a WrapLayout. Although it shows some items being added via its Children property, it doesn't show any implementation with MVVM. Besides that, the implementation is nowhere near finished.
I can take this project as a base and expand it to my needs. But I feel there has to be a lot of work done for this to work in my scenario.
Does anybody know any other resources that better fit my needs than these two? For which option should I go if there aren't any resources available (I know there must be something available since Zite and Flipboard already done it)?
I dont know flipboard or zite but you try could something like this.
var grid = new Grid()
{
VerticalOptions = LayoutOptions.FillAndExpand,
ColumnDefinitions = new ColumnDefinitionCollection()
{
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) }
},
RowDefinitions = new RowDefinitionCollection()
{
new RowDefinition(){ Height = new GridLength(1,GridUnitType.Star) },
new RowDefinition(){ Height = new GridLength(1,GridUnitType.Star) },
new RowDefinition(){ Height = new GridLength(1,GridUnitType.Star) }
}
};
var scrollview = new ScrollView() { Orientation = ScrollOrientation.Horizontal };
scrollview.Content = grid;

Categories

Resources