I am trying to create a dynamic view, where I get the data from the backend and create views for it on my Xamarin App.
In the XAML view I have a simple stack layout
<StackLayout x:Name="Container">
</StackLayout>
and I am creating views as soon as the date is retrieved as so
Label label = new Label();
label.Text= Text;
label.LineHeight = 1.1;
Container.Children.Add(CreateLabel(label));
The problem is the view doesn't expand to fit all the elements added
calculating the height and setting it as the HeightRequest for stack layout didn't work
any idea or suggestion would be nice.
I made a demo for you by writing the MainPage.xaml.cs file.
public partial class MainPage : ContentPage
{
String Text1 = "This is a text. This is a text.This is a text.This is a text.";
Double LineHeight1 = 1.78;
public MainPage()
{
InitializeComponent();
var layout = new StackLayout { };
var label = new Label { Text = Text1, TextColor = Color.Black, FontSize = 20, LineHeight = LineHeight1, BackgroundColor = Color.Red, LineBreakMode = LineBreakMode.WordWrap };
layout.Children.Add(label);
this.Content = layout;
}
}
You can see that I create a StackLayout and a label and I bind the layout to the content. It works well and you can try it.
Related
I have a toggle button and list which contains Label in it.
Toggle(Switch) and List View are declared in Xaml file where list's Data-cell is generated programatically in cs file.
I need to hide/show this label in the list based on the toggle switch
Xaml code:
<Switch IsToggled="{Binding IsToggled, Mode=TwoWay}" Grid.Row = "0" Grid.Column = "1" HorizontalOptions = "Start" Margin = "10,8,8,0"></Switch>
<ListView x:Name="lvItemSigns" HasUnevenRows="True" SeparatorVisibility="Default" SeparatorColor="Gray">
cs file code:
lvItemSigns.ItemTemplate = new DataTemplate(typeof(DataCell));
lvItemSigns.ItemsSource = VM.ItemSignsList;
class DataCell : ViewCell
{
Label label;
public DataCell()
{
// has grid
var label = new Label();
label.TextColor = Color.Black;
label.Margin = 4;
label.Text = "test";
grid.Children.Add(label, 2, 1);
label.SetBinding(Label.IsVisibleProperty, new Binding("BindingContext.IsToggled", BindingMode.TwoWay, new BooleanConverter(), null, null, "cs-file_name"));
grid.Children.Add(stackLayout, 0, 3);
grid.Margin = new Thickness(8,0,0,0);
View = grid;
}
}
In ViewModel:
public bool _IsToggled;
public bool IsToggled
{
get
{
return _IsToggled;
}
set
{
_IsToggled= value;
OnPropertyChanged("_IsToggled");
}
}
public ItemSignsTabViewModel()
{
ItemSignsList = new ObservableCollection<TicketItem>(daItemSign.GetItemSigns(Ticket.MobileID));
}
I'm binding the visible property to Label but still I can see the label all the time (when toggle switch is on or off).
I know I'm doing something wrong. Any help?
Your DataContext for the Switch's binding is different from you DataCell's DataContext.
Both views are not targeting the same objects.
You need to post the code of your viewmodels for both the page, and the DataCell in order to get help.
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.
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/
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");
I am looking for a way to bind a whole Chart in my xaml. Not only one Series, but the whole Chart. This is due to my need to add multiple Series dynamically to the Chart.
XAML:
<chart:Chart DataContext="{Binding Path=FocusEnergyChart, UpdateSourceTrigger=PropertyChanged}"/>
C#:
public void DrawChart()
{
myChart = new Chart();
LinearAxis xAxis = new LinearAxis();
xAxis.Orientation = AxisOrientation.X;
xAxis.Title = "Energy";
LinearAxis yAxis = new LinearAxis();
yAxis.Orientation = AxisOrientation.Y;
yAxis.Title = "Focus";
myChart.Axes.Add(xAxis);
myChart.Axes.Add(yAxis);
myChart.Title = "Focus Energy - Chart";
foreach( string aKey in myGraphData.Keys)
{
BubbleSeries aSeries = new BubbleSeries();
aSeries.Title = aKey;
aSeries.ItemsSource = myGraphData[aKey];
aSeries.DependentValuePath = "Focus";
aSeries.IndependentValuePath = "Energy";
aSeries.SizeValuePath = "Size";
aSeries.SetResourceReference(Series.BackgroundProperty, "Background");
aSeries.SetResourceReference(BubbleSeries.LegendItemStyleProperty, "CustomLegendItemStyle");
aSeries.SetResourceReference(BubbleSeries.DataPointStyleProperty, "BubbleToolTipTemplate");
myChart.Series.Add(aSeries);
}
base.OnPropertyChanged("FocusEnergyChart");
}
public Chart FocusEnergyChart
{
get { return myChart; }
}
When i try to run this code it just shows me an empty ChartArea.
I hope someone can help me!
Thanks!
All you do here is add another chart as the DataContext of your chart declared from XAML.
You can use a ContentControl and bind it's content to your chart created from code-behind:
<ContentControl Content="{Binding Path=FocusEnergyChart}" />