Xamarin Forms - Change View's location in a Grid - xamarin

I have a grid on my page with a few items.
I want to change the location/span of these items in C#.
On Xaml I can do this:
<Grid>
<Label Grid.Row="1" Grid.RowSpan="2"/>
</Grid>
I could do grd.Children.Remove and then grd.Children.Add in the new position, but is there another way?

public MyPage()
{
var grid = new Grid();
var lbl1 = new Label { Text= "lbl1" };
var lbl2 = new Label { Text = "lbl2" };
grid.Children.Add(lbl1);
grid.Children.Add(lbl2);
Grid.SetRow(lbl1, 1);
Grid.SetRow(lbl2, 0);
this.Content = grid;
}
However I would recommend not to do it dynamically but once in the constructor. More info in the official doc.

Related

Xamarin Android emulator using grid inside scrollview, only first page of grid is drawn

I am developing a Xamarin Forms app in Visual Studio 2019 using the standard Android emulator. The XAML contains a ScrollView that contains a Grid. The grid merely has two columns. I have a handler for the OnStart event that connects to a database, gets a response containing 64 objects, adds two labels to the grid for each object, and populates the labels. The ScrollView's background color is set to yellow. When I debug the app using the emulator, the initial screen is drawn correctly. But when I scroll down, the grid is not filled in. The background is still yellow, showing that the scrollview is the correct size (or at least, big enough to hold more labels). What am I doing wrong?
When I put a breakpoint at the bottom of the second for loop, after adding the labels, I see that I have all of the label objects I expect, and they have the text properties set as I expect.
Here's the XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CapsBases.MainPage">
<ScrollView BackgroundColor="Yellow"
VerticalOptions="FillAndExpand">
<Grid Margin="10"
x:Name="BasesGrid">
<!-- two columns: base ID and status -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</ScrollView>
</ContentPage>
The event handler calls a function named ShowBases() in the MainPage.xaml.cs file. Here it is:
public async void ShowBases()
{
string url = "http://10.0.2.2:5000/caps/bases";
//HttpClient client = new HttpClient();
//string info = await client.GetStringAsync(url);
//// await DisplayAlert("Coil Count", message, "Close");
//// The base ID and string will be returned in a single string with a space separating them.
//string[] pieces = info.Split(' ');
//BaseID.Text = pieces[0];
//BaseStatus.Text = pieces[1];
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
string data = await response.Content.ReadAsStringAsync();
//IEnumerable<Base> baseList = JsonConvert.DeserializeObject<IEnumerable<Base>>(data);
List<Base> baseList = JsonConvert.DeserializeObject<List<Base>>(data).OrderBy(b =>b.BaseName).ToList();
//BaseID.Text = theBase.BaseName;
//BaseStatus.Text = theBase.Status;
string message = $"Retrieved {baseList.Count()} bases.";
await DisplayAlert("Result", message, "Close");
Grid theGrid = BasesGrid;
var rowDefinitions = theGrid.RowDefinitions;
for (int i = 0; i < baseList.Count(); i++)
{
RowDefinition rowDef = new RowDefinition { Height = 20 };
rowDefinitions.Add(rowDef);
}
await DisplayAlert("Row count", $"The grid has {BasesGrid.RowDefinitions.Count()} rows.", "Close");
// We have the grid with all the rows we need. Now we have to create a label for each grid cell.
try
{
for (int i = 0; i < baseList.Count(); i++)
{
BasesGrid.Children.Add
(
new Label
{
Text = baseList[i].BaseName,
HorizontalOptions = LayoutOptions.Start
},
0, i
);
BasesGrid.Children.Add
(
new Label
{
Text = baseList[i].Status,
HorizontalOptions = LayoutOptions.Start
},
1, i
);
}
}
catch (Exception ex)
{
await DisplayAlert("Error", $"Failed to add row data: {ex.Message}", "Close");
}
}
else
{
await DisplayAlert("Get Coils failure",
$"Failed to retrieve coils; status code: {response.StatusCode}",
"Close");
}
}
}
}
Surround the Grid in a StackLayout of vertical orientation. The Grid is not expanding inside the ScrollView.

how to add wrap Layout in scroll view dynamically

i want to add wrap layout elements in scroll view dynamically using java script.
but when i try to add scroll view child it says, it is not a function.
i want to know is it possible to achieve this or not.
one more thing is that i need to add layout by id i.e wrapId in below code.
<Page xmlns="http://www.nativescript.org/tns.xsd" navigatingTo="onNavigatingTo">
<Page.actionBar>
<ActionBar title="Wrap Layout" />
</Page.actionBar>
<ScrollView>
<StackLayout id="wrapId">
</StackLayout>
</ScrollView>
</Page>
this is my xml and below is the js
const WrapLayout = require("tns-core-modules/ui/layouts/wrap-layout").WrapLayout;
const StackLayout = require("tns-core-modules/ui/layouts/stack-layout").StackLayout;
var ScrollView = require('ui/scroll-view').ScrollView;
const Button = require("tns-core-modules/ui/button/").Button;
exports.onNavigatingTo = function (args) {
const page = args.object;
var wrapId = page.getViewById("wrapId");
const myWrap = new WrapLayout();
const myScroll = new ScrollView();
myScroll.orientation = "vertical";
for (let i = 0; i < 30; i++) {
var button = `button${i}`;
button = new Button();
button.backgroundColor = "#0099CC";
button.text = `${i}`;
button.width = 150;
button.height = 100;
button.margin = 4;
myWrap.addChild(button);
}
// myScroll.addChild(myWrap);
page.content = myWrap;
};
ScrollView is just like Page, inherited from ContentView which supports holding only one child element. So it should be,
myScroll.content = myWrap;

How to add a visual prefix to an entry in Xamarin Forms?

Say I want to add a number prefix based on a country, for a phone entry? Like the one on the image:
How can I achieve that?
I would do something like this
<StackLayout Orientation="Horizontal" BackgroundColor="Gray">
<Label Text="+995 |" BackgroundColor="Transparent" />
<Editor Text="699999999" BackgroundColor="Transparent"></Editor>
</StackLayout>
A Horizontal stacklayout with a label for the prefix and an editor for the entry.
As you can see yourself i am using the same approach for my app in order to display the arrow down icon next to the picker.
var datectrl = new NoBorderPicker()
{
VerticalOptions = LayoutOptions.Center,
FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)) * FontSizes.EditFormControlFactor,
HeightRequest = 40,
BackgroundColor = Color.White,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
var icon = new IconView()
{
Source = "ic_keyboard_arrow_right_black_24dp",
Foreground = Palette._019,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.End,
Margin = new Thickness(0, 0, 5, 0)
};
var stack = new StackLayout()
{
Orientation = StackOrientation.Horizontal,
Children =
{
datectrl,
icon
}
};
The NoBorderPicker is a custom renderer in order to remove the border for the picker control
[assembly: ExportRenderer(typeof(NoBorderPicker), typeof(CustomPicker))]
namespace ThesisSFA.Droid.Renderers
{
public class CustomPicker : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var customBG = new GradientDrawable();
customBG.SetColor(Android.Graphics.Color.Transparent);
customBG.SetCornerRadius(3);
Control.SetBackground(customBG);
var custdatepicker = (NoBorderPicker) this.Element;
this.Control.TextSize = (float)custdatepicker.FontSize;
}
}
}
}
You can just use masking behavior.
<Entry.Behaviors>
<behavior:MaskedBehavior Mask="(995) XX-XXX-XXXX" />
</Entry.Behaviors>
enter code here
and to add behavior just use the following link.
https://xamarinhelp.com/masked-entry-in-xamarin-forms/

Make a NativeScript ListView Transparent on iOS

I’m trying to get a NativeScript <ListView> to be transparent on iOS and I’m failing. I found an old thread on the topic at https://groups.google.com/forum/#!topic/nativescript/-MIWcQo-l6k, but when I try the solution it doesn’t work for me. Here’s my complete code:
/* app.css */
Page { background-color: black; }
<!-- main-page.xml -->
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="loaded">
<ListView id="list-view" items="{{ items }}" itemLoading="itemLoading">
<ListView.itemTemplate>
<Label text="{{ name }}" />
</ListView.itemTemplate>
</ListView>
</Page>
// main-page.js
var ios = require("utils/utils");
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var page;
var items = new ObservableArray([]);
var pageData = new Observable();
exports.loaded = function(args) {
page = args.object;
page.bindingContext = pageData;
// Toss a few numbers in the list for testing
items.push({ name: "1" });
items.push({ name: "2" });
items.push({ name: "3" });
pageData.set("items", items);
};
exports.itemLoading = function(args) {
var cell = args.ios;
if (cell) {
// Use ios.getter for iOS 9/10 API compatibility
cell.backgroundColor = ios.getter(UIColor.clearColor);
}
}
Any help would be appreciated. Thanks!
Don't forget to set the listview to transparent, seems to have a backgroundcolor itself
ListView{
background-color: transparent;
}
Currently with NativeScript 2.4 the following works
var cell = args.ios;
if (cell) {
cell.selectionStyle = UITableViewCellSelectionStyleNone
}
And if you want to change the selection highlight color here is a simple approach, I have not tested performance but it works okay on an iPhone 6.
import { Color } from 'color';
cell.selectedBackgroundView = UIView.alloc().initWithFrame(CGRectMake(0, 0, 0, 0));
let blue = new Color('#3489db');
cell.selectedBackgroundView.backgroundColor = blue.ios
Not sure if there are better ways to do this, but this is what worked for me with NativeScript 2.4 on iOS to both A) make the ListView background transparent, and B) change the color when an item is tapped:
let lvItemLoading = (args) => {
let cell = args.ios;
if (cell) {
// Make the iOS listview background transparent
cell.backgroundColor = ios.getter(cell, UIColor.clearColor);
// Create new background view for selected state
let bgSelectedView = UIView.alloc().init();
bgSelectedView.backgroundColor = new Color("#777777").ios;
bgSelectedView.layer.masksToBounds = true;
cell.selectedBackgroundView = bgSelectedView;
}
};

Windows Phone Custom Live Tiles not working as Expected

I created a Windows Phone application, In that i need to create the custom tile and update it from program
I created a User control,
<TextBlock x:Name="Count" Foreground="White" FontFamily="Segoe WP Bold" FontSize="80" Text="{Binding Count}" HorizontalAlignment="Right" Margin="0,0,10,0"/>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0,0,0,0" Grid.Row="1" Text="Tile Demo" Foreground="White" FontFamily="Segoe WP Semibold" FontSize="35" />
from my MainPage.xaml.cs file i am binding the count then i am converting the User control into a .jpg file and storing in the ISO Store. Like below
public void CreateOrUpdateTile(int count)
{
CustomNotificationTile frontTile = new CustomNotificationTile();
TileData tileData = new TileData() { Count = count };
frontTile.DataContext = tileData;
//frontTile.Count.Text = count.ToString();
frontTile.Measure(new Size(173, 173));
frontTile.Arrange(new Rect(0, 0, 173, 173));
var bmp = new WriteableBitmap(173, 173);
bmp.Render(frontTile, null);
bmp.Invalidate();
var isf = IsolatedStorageFile.GetUserStoreForApplication();
var filename = "/Shared/ShellContent/Tile.jpg";
if (!isf.DirectoryExists("/Shared/ShellContent"))
{
isf.CreateDirectory("/Shared/ShellContent");
}
using (var stream = isf.OpenFile(filename, System.IO.FileMode.OpenOrCreate))
{
bmp.SaveJpeg(stream, 173, 173, 0, 100);
}
ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("TileID=2"));
//test if Tile was created
if (TileToFind == null)
{
StandardTileData NewTileData = new StandardTileData
{
BackgroundImage = new Uri("isostore:" + filename, UriKind.Absolute),
BackBackgroundImage = new Uri("Application_TileImage_173x173.png", UriKind.Relative)
};
ShellTile.Create(new Uri("/MainPage.xaml?TileID=2", UriKind.Relative), NewTileData);
}
#region Update the Tile Not Working as expected
else
{
StandardTileData NewTileData = new StandardTileData
{
BackgroundImage = new Uri("isostore:" + filename, UriKind.Absolute)
};
TileToFind.Update(NewTileData);
}
#endregion
}
Problem:
My problem is first i am calling from constructor to create the tile with some dummy data, Its Working as expected
But when i try to update the Tile from other methods its not working, those methods i am calling from page_load event
Those methods will fetch data from a WCF service, i am updating the Tile from the completed event of the WCF service method like below
Service.getProductsCountAsync();
Service.getProductsCountCompleted += (o,e) => {
int count = e.Result;
Dispatcher.BeginInvoke(() =>
{
CreateOrUpdateTile(count);
});
};
When the controller hit the above code, I only seeing the number with black background, Tile count is updating but the background color and logo are changing, I don't know why its happening but need to solve as early as possible.
I think the problem might be updating the UI from the background thread, but i don't know how to overcome that
Following are the images which will taken before method calls and after method calls
Before
After
Its working
We have to Bind the Background color, Logo also dynamically like count even though they are static
After that it is working as expected

Resources