Xamarin Forms - Thread Efficiency - xamarin

I am developing a Xamarin (PCL) cross platform app that i am currently testing on my Android Physical devices and Emulators. The app runs perfectly on the high-end phones, but "crashes unexpectedly" on the Samsung S4 and such low-end phones. It crashes only after i perform multiple activities and tasks.
I am assuming that has something to do with the task-thread-capacity of these phones. If i am right in that regard, how am i supposed to make my app such that it works smoothly and error free on all phones?
Edit - The error says "The app has closed unexpectedly". This error doesn't appear on a specific line because it has nothing to do with the code. It breaks only on certain "older" phones when many activities are performed. Example of activities include, Add data to database, updating/deleting them, moving from one activity to another, showing calendars and pie-charts from user entered data.
Edit 2 -Some of the Code that deals with images:
Xaml:
<ScrollView HorizontalOptions="Fill" Orientation="Horizontal">
<StackLayout Orientation="Vertical" BackgroundColor="GhostWhite" >
<StackLayout Orientation="Horizontal" BackgroundColor="GhostWhite" >
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="dairy" Image="{Binding Dairy_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="alcohol" Image="{Binding Alcohol_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="eggs" Image="{Binding Egg_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="fastfood" Image="{Binding Fastfood_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="fish" Image="{Binding Fish_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="fruit" Image="{Binding Fruit_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="grain" Image="{Binding Grain_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="legume" Image="{Binding Legume_Image}"/>
</StackLayout>
<StackLayout Orientation="Horizontal" BackgroundColor="GhostWhite" >
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="meat" Image="{Binding Meat_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="munchies" Image="{Binding Munchies_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="nuts" Image="{Binding Nut_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="potato" Image="{Binding Potato_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="soda" Image="{Binding Soda_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="sweets" Image="{Binding Sweet_Image}"/>
<Button HeightRequest="50" BackgroundColor="GhostWhite" WidthRequest="50" Command="{Binding Button_Clicked_Food}" CommandParameter="vegetables" Image="{Binding Vegetable_Image}"/>
</StackLayout>
</StackLayout>
.CS:
public UserMealINC_vm(User_Profiles up, DateTime day)
{
try
{
Day = day;
User_pro = up;
Bool_Food_Type = false;
Food_Name = "";
Type = "";
Food_Weight = "0";
Selected_Food = new List<string>();
//All meal item are first initialized with the non-coloured images
Dairy_Image = "drawable/dairy.png";
Alcohol_Image = "drawable/alcohol.png";
Egg_Image = "drawable/eggs.png";
Fastfood_Image = "drawable/fastfood.png";
Fish_Image = "drawable/fish.png";
Fruit_Image = "drawable/fruit.png";
Grain_Image = "drawable/grain.png";
Legume_Image = "drawable/legume.png";
Meat_Image = "drawable/meat.png";
Munchies_Image = "drawable/munchies.png";
Nut_Image = "drawable/nuts.png";
Potato_Image = "drawable/potato.png";
Soda_Image = "drawable/soda.png";
Sweet_Image = "drawable/sweets.png";
Vegetable_Image = "drawable/vegetables.png";
this.Button_Clicked_Food = new Command<string>((key) =>
{
//Change the item selected from color to non-color, or vice-versa
if (Selected_Food.Contains(key))
{
if (key == "dairy")
{
Dairy_Image = "drawable/dairy.png";
}
else if (key == "alcohol")
{
Alcohol_Image = "drawable/alcohol.png";
}
else if (key == "eggs")
{
Egg_Image = "drawable/eggs.png";
}
else if (key == "fastfood")
{
Fastfood_Image = "drawable/fastfood.png";
}
else if (key == "fish")
{
Fish_Image = "drawable/fish.png";
}
else if (key == "fruit")
{
Fruit_Image = "drawable/fruit.png";
}
else if (key == "grain")
{
Grain_Image = "drawable/grain.png";
}
else if (key == "legume")
{
Legume_Image = "drawable/legume.png";
}
else if (key == "meat")
{
Meat_Image = "drawable/meat.png";
}
else if (key == "munchies")
{
Munchies_Image = "drawable/munchies.png";
}
else if (key == "nuts")
{
Nut_Image = "drawable/nuts.png";
}
else if (key == "potato")
{
Potato_Image = "drawable/potato.png";
}
else if (key == "soda")
{
Soda_Image = "drawable/soda.png";
}
else if (key == "sweets")
{
Sweet_Image = "drawable/sweets.png";
}
else if (key == "vegetables")
{
Vegetable_Image = "drawable/vegetables.png";
}
else
{
//Key out of bounds???
}
Selected_Food.Remove(key);
}
else
{
if (key == "dairy")
{
Dairy_Image = "drawable/dairy_color.png";
}
else if (key == "alcohol")
{
Alcohol_Image = "drawable/alcohol_color.png";
}
else if (key == "eggs")
{
Egg_Image = "drawable/eggs_color.png";
}
else if (key == "fastfood")
{
Fastfood_Image = "drawable/fastfood_color.png";
}
else if (key == "fish")
{
Fish_Image = "drawable/fish_color.png";
}
else if (key == "fruit")
{
Fruit_Image = "drawable/fruit_color.png";
}
else if (key == "grain")
{
Grain_Image = "drawable/grain_color.png";
}
else if (key == "legume")
{
Legume_Image = "drawable/legume_color.png";
}
else if (key == "meat")
{
Meat_Image = "drawable/meat_color.png";
}
else if (key == "munchies")
{
Munchies_Image = "drawable/munchies_color.png";
}
else if (key == "nuts")
{
Nut_Image = "drawable/nuts_color.png";
}
else if (key == "potato")
{
Potato_Image = "drawable/potato_color.png";
}
else if (key == "soda")
{
Soda_Image = "drawable/soda_color.png";
}
else if (key == "sweets")
{
Sweet_Image = "drawable/sweets_color.png";
}
else if (key == "vegetables")
{
Vegetable_Image = "drawable/vegetables_color.png";
}
else
{
//Key out of bounds???
}
Selected_Food.Add(key);
}
});
}
catch (Exception ex)
{
App.Current.MainPage.DisplayAlert("UserMealINC_vm 1!", ex.Message, "OK");
}
}

It turns out that the device memory was getting overflowed by all the multiple images i had in my App. (As suggested by #hvaughan3)
This link has the answer to it.
You basically just have to add these two lines in you Android Manifest (Under Application) -
android:hardwareAccelerated="false"
android:largeHeap="true"

Related

Xamarin CarouselView throws OutOfRangeException when ItemsSource changes and Positon is not 0

I have a Xamarin Forms App with a Carousel View and my plan is to filter the result by the Priorities shown in a Bottom Tap Bar.
When the View is on the first card, everything works fine, but if you hit one of the filters from a different card, then the first one, a System.ArgumentOutOfRangeException exception got fired.
I tried already a lot of things to set the position of the Carousel View to 0, but in vain.
using the CarouselView_PositionChanged event => not working
using the TabHost_SelectedTabIndexChanged event => not working
setting the property of the CarouselView by the selectedIndex changed from the Tab View from the ViewModel => not working
turn it into a CollectionView and everything is working => just looks ugly 🤮
Here the page
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:viewModels="clr-namespace:AmsXamarin.ViewModels"
xmlns:fontAwesome="clr-namespace:FontAwesome"
xmlns:cells="clr-namespace:AmsXamarin.Cells"
xmlns:tabs="http://sharpnado.com"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
x:Class="AmsXamarin.Views.SnagListX.SnagListPage"
x:Name="mySnagListPage">
<ContentPage.BindingContext>
<viewModels:SnagListViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<xct:TabSelectionChangedEventArgs x:Key="TabSelectionChangedEventArgs" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem Command="{Binding ShowMyJobsCommand}"
Order="Primary"
Priority="0"
Text="{Binding MyJobsTitle,Mode=TwoWay}">
</ToolbarItem>
<ToolbarItem Command="{Binding AddFaultCommand}"
Order="Primary"
Priority="0">
<ToolbarItem.IconImageSource>
<FontImageSource FontFamily="FAS"
Glyph="{x:Static fontAwesome:FontAwesomeIcons.Plus}"
Color="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Primary}}"
Size="Large" />
</ToolbarItem.IconImageSource>
</ToolbarItem>
<ToolbarItem Command="{Binding AcceptCommand}"
Order="Primary"
Priority="0">
<ToolbarItem.IconImageSource>
<FontImageSource FontFamily="FAS"
Glyph="{x:Static fontAwesome:FontAwesomeIcons.UserCheck}"
Color="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Primary}}"
Size="Large" />
</ToolbarItem.IconImageSource>
</ToolbarItem>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<Label Style="{StaticResource LabelLarge}"
Text="Snag List"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<StackLayout>
<IndicatorView x:Name="snagListIndicator"
Margin="0,10,0,0"
IndicatorColor="LightGray"
SelectedIndicatorColor="LightGray"
IndicatorSize="6" />
<RefreshView Command="{Binding RefreshCommand}"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
Style="{StaticResource BaseRefreshView}">
<CarouselView x:Name="snagListCV"
Margin="10"
IndicatorView="snagListIndicator"
ItemsLayout="HorizontalList"
ItemsSource="{Binding SnagListPriorities.SnagListApps}"
CurrentItem="{Binding SnagListItem}"
Position="{Binding PositionIdx,Mode=OneWay}"
PositionChanged="CarouselView_PositionChanged"
Loop="False"
IsEnabled="{Binding IsNotBusy}">
<CarouselView.EmptyView>
<StackLayout Padding="12">
<Label Style="{StaticResource LabelMedium}"
HorizontalOptions="Center"
Text="{Binding EmptyMessage,Mode=TwoWay}" />
</StackLayout>
</CarouselView.EmptyView>
<CarouselView.ItemTemplate>
<DataTemplate>
<cells:SnagListCardX />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</RefreshView>
</StackLayout>
<tabs:TabHostView x:Name="TabHost"
Margin="13,0,13,10"
BackgroundColor="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Fourth}}"
CornerRadius="30"
IsSegmented="True"
Orientation="Horizontal"
TabType="Fixed"
SelectedIndex="{Binding SelectedIndex,Mode=TwoWay}"
Shades="{StaticResource LightBottomShadow}">
<tabs:TabHostView.Behaviors>
<xct:EventToCommandBehavior EventName="SelectedTabIndexChanged"
Command="{Binding SelectedCommand}"
EventArgsConverter="{StaticResource TabSelectionChangedEventArgs}" />
</tabs:TabHostView.Behaviors>
<tabs:TabHostView.Tabs>
<tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
Label="All">
<tabs:BottomTabItem.Badge>
<tabs:BadgeView Style="{StaticResource BadgeViewBase}"
BackgroundColor="{StaticResource All}"
TextColor="White"
Text="{Binding SnagListPriorities.All,Mode=TwoWay}" />
</tabs:BottomTabItem.Badge>
</tabs:BottomTabItem>
<tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
Label="High"
StyleClass="">
<tabs:BottomTabItem.Badge>
<tabs:BadgeView Style="{StaticResource BadgeViewBase}"
BackgroundColor="{StaticResource High}"
TextColor="White"
Text="{Binding SnagListPriorities.High,Mode=OneWay}" />
</tabs:BottomTabItem.Badge>
</tabs:BottomTabItem>
<tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
Label="Medium">
<tabs:BottomTabItem.Badge>
<tabs:BadgeView Style="{StaticResource BadgeViewBase}"
BackgroundColor="{StaticResource Medium}"
TextColor="Black"
Text="{Binding SnagListPriorities.Medium,Mode=TwoWay}" />
</tabs:BottomTabItem.Badge>
</tabs:BottomTabItem>
<tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
Label="Low">
<tabs:BottomTabItem.Badge>
<tabs:BadgeView Style="{StaticResource BadgeViewBase}"
BackgroundColor="{StaticResource Low}"
TextColor="Black"
Text="{Binding SnagListPriorities.Low,Mode=TwoWay}" />
</tabs:BottomTabItem.Badge>
</tabs:BottomTabItem>
</tabs:TabHostView.Tabs>
</tabs:TabHostView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
And the view model
using AmsXamarin.Helpers;
using AmsXamarin.Models;
using AmsXamarin.Services;
using MvvmHelpers;
using MvvmHelpers.Commands;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Command = MvvmHelpers.Commands.Command;
namespace AmsXamarin.ViewModels
{
public class SnagListViewModel : BaseViewModel
{
readonly ISnagListService snagListService;
List<SnagListAppX> SnagListAppXs;
SnagListAppX snagListItem;
public SnagListAppX SnagListItem
{
get { return snagListItem; }
set
{
snagListItem = value;
OnPropertyChanged();
}
}
SnagListPriorities snagListPriorities;
public SnagListPriorities SnagListPriorities
{
get { return snagListPriorities; }
set
{
snagListPriorities = value;
OnPropertyChanged();
}
}
public AsyncCommand AddFaultCommand { get; }
public AsyncCommand AcceptCommand { get; }
public Command RefreshCommand { get; }
public Command SelectedCommand { get; }
public Command ShowMyJobsCommand { get; }
string emptyMessage;
public string EmptyMessage
{
get { return emptyMessage; }
set
{
emptyMessage = value;
OnPropertyChanged();
}
}
int positionIdx;
public int PositionIdx
{
get { return positionIdx; }
set
{
positionIdx = value;
OnPropertyChanged();
}
}
int selectedIndex;
public int SelectedIndex
{
get => selectedIndex;
set => SetProperty(ref selectedIndex, value);
}
string myJobsTitle = "My Jobs";
int staffId;
public string MyJobsTitle
{
get { return myJobsTitle; }
set
{
myJobsTitle = value;
OnPropertyChanged();
}
}
bool myJobsEnabled = true;
bool updateProperty = false;
public bool AcceptToolBar { get; set; }
public SnagListViewModel()
{
SnagListItem = new SnagListAppX();
SnagListPriorities = new SnagListPriorities()
{
SnagListApps = new ObservableRangeCollection<SnagListAppX>()
};
SnagListAppXs = new List<SnagListAppX>();
AddFaultCommand = new AsyncCommand(ShowAddSnagListItem);
AcceptCommand = new AsyncCommand(ShowModalAccept);
SelectedCommand = new Command(Selected);
RefreshCommand = new Command(Refresh);
staffId = 0;
ShowMyJobsCommand = new Command(ShowModalMyJobs);
snagListService = DependencyService.Get<ISnagListService>();
Device.BeginInvokeOnMainThread(async () =>
{
await GetSnagListItems();
});
}
async Task GetSnagListItems()
{
try
{
IsBusy = true;
EmptyMessage = "Loading...";
SnagListPriorities slp = await snagListService.GetSnagLists(false, true);
SnagListPriorities.SnagListApps.Clear();
SnagListPriorities = slp;
SnagListAppXs.Clear();
SnagListAppXs.AddRange(slp.SnagListApps);
EmptyMessage = SnagListAppXs.Count == 0 ? "Good Job! \r\n\r\nCurrently nothing to fix" : "";
IsBusy = false;
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "Ok");
}
}
void Selected()
{
//PositionIdx = 0;
//OnPropertyChanged(nameof(PositionIdx));
//FilterSnagList();
Refresh();
}
void FilterSnagList()
{
var allJobs = SnagListAppXs;
if (staffId != 0) allJobs = allJobs.Where(x => x.StaffId == staffId).ToList();
if (updateProperty) OnPropertyChanged(nameof(SnagListPriorities));
if (selectedIndex > 0) allJobs = allJobs.Where(sli => sli.Priority == selectedIndex).ToList();
SnagListPriorities.SnagListApps.Clear();
//SnagListPriorities.SnagListApps = new ObservableRangeCollection<SnagListAppX>(allJobs);
SnagListPriorities.SnagListApps.AddRange(allJobs);
//OnPropertyChanged(nameof(SnagListPriorities.SnagListApps));
updateProperty = false;
}
void ShowModalMyJobs()
{
staffId = myJobsEnabled ? int.Parse(Settings.StaffIdSetting) : 0;
MyJobsTitle = myJobsEnabled ? "All Jobs" : "My Jobs";
AcceptToolBar = !myJobsEnabled;
myJobsEnabled = !myJobsEnabled;
SelectedIndex = 0;
updateProperty = true;
}
void Refresh()
{
IsBusy = true;
var allJobs = SnagListAppXs.Where(s => s.StaffId == 115);
SnagListPriorities.SnagListApps.Clear();
SnagListPriorities.SnagListApps.AddRange(allJobs);
IsBusy = false;
}
}
}
looks a bit messy, but wanted to show, that I tried already a lot of things.
Last try was a simple RefreshView.
It works as long as the itemsSource is not changing. Once it changes and the first card is not shown, it crashes.
Any ideas? Many thanks

Get a list of images of BindableLayout in Xamarin

I have a question here, however the problem is not solved perfectly. I posted another question for more clarity.
I'm trying to upload an image through the API. As in the code below, I have an image selector button, the list shows the selected images. And 1 button to post the image.
I have a list of pictures:
<Grid x:Name="pickimg" Grid.Row="0" Grid.Column="1" HorizontalOptions="End" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Image Margin="0">
<Image.Source>
<FontImageSource Color="#ddd" Size="22" FontFamily="MaterIcon" Glyph="{x:Static local:FontIconsClass.Camera}"/>
</Image.Source>
</Image>
</StackLayout>
<Grid.GestureRecognizers>
<TapGestureRecognizer Tapped="pickimg_Tapped" />
</Grid.GestureRecognizers>
</Grid>
<StackLayout x:Name="listImg" Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Frame HasShadow="False" Padding="0" IsClippedToBounds="True" CornerRadius="4">
<Image HeightRequest="70" WidthRequest="70" Aspect="AspectFill" Source="{Binding .}"/>
</Frame>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<Button x:Name="bt_addfeed" Clicked="bt_addfeed_Clicked" CornerRadius="7" FontSize="13" Text="Post" HorizontalOptions="Fill"/>
.xaml.cs
List<ImageSource> imgList = new List<ImageSource>();
async void pickimg_Tapped(System.Object sender, EventArgs e)
{
var pickResult = await MediaGallery.PickAsync(5, MediaFileType.Image);
if(pickResult?.Files == null)
{
return;
}
else
{
//var imgList = new List<ImageSource>();
foreach (var img in pickResult?.Files)
{
var stream = await img.OpenReadAsync();
imgList.Add(ImageSource.FromStream(() => stream));
}
BindableLayout.SetItemsSource(listImg, imgList);
}
}
private async void bt_addfeed_Clicked(object sender, EventArgs e)
{
var getResult = imgList;
if (getResult == null)
{
return;
}
else
{
foreach(var img in getResult)
{
var content = new MultipartFormDataContent();
content.Add(new StreamContent(await img.OpenReadAsync()), "file", img.FileName);
var httpClient = new HttpClient();
var responses = await httpClient.PostAsync("xxxx/api/UploadFileFeeds", content);
}
}
}
How img.FileName? and img.OpenReadAsync()?
Please help, thanks
create two lists
List<ImageSource> imgList = new List<ImageSource>();
List<FileResult> fileList = new List<FileResult>();
then populate both of them
foreach (var img in pickResult?.Files)
{
fileList.Add(img);
var stream = await img.OpenReadAsync();
imgList.Add(ImageSource.FromStream(() => stream));
}
BindableLayout.SetItemsSource(listImg, imgList);
then when you need to transfer the files, use fileList
foreach(var img in fileList)
{
var content = new MultipartFormDataContent();
content.Add(new StreamContent(await img.OpenReadAsync()), "file", img.FileName);
var httpClient = new HttpClient();
var responses = await httpClient.PostAsync("https://v1api.venuskorea.com.vn/api/UploadFileFeeds", content);
}

How can I put only English numbers in keyborard Xamarin.forms

My app has entry , when clicked it shows Numeric keyboard , the problem is if I put arabic numbers it doesn't calculate but close the app
is it possible to put only english number or how can I support arabic numbers ,
this is XAML file
<ContentPage.Content>
<AbsoluteLayout >
<!-- Text Box 1 -->
<StackLayout AbsoluteLayout.LayoutBounds="0.8,0.01" AbsoluteLayout.LayoutFlags="PositionProportional" >
<Label Text="" FontSize="Medium" FontAttributes="Bold" TextColor="Black" x:Name="lblname2" HorizontalOptions="Center" />
<Entry x:Name="Entnum2" WidthRequest="100" HeightRequest="40" BackgroundColor="White" Keyboard="Numeric" MaxLength="3" HorizontalTextAlignment="Center"
Focused="Entnum2_Focused" TextColor="Black" FontSize="Medium" PropertyChanged="Entnum2_PropertyChanged" />
</StackLayout>
<!-- Text Box 1 -->
<StackLayout AbsoluteLayout.LayoutBounds="0.2,0.01" AbsoluteLayout.LayoutFlags="PositionProportional">
<Label Text="" FontSize="Medium" FontAttributes="Bold" TextColor="Black" x:Name="lblname1" HorizontalOptions="Center" />
<Entry x:Name="Entnum1" WidthRequest="100" HeightRequest="40" BackgroundColor="White" Keyboard="Numeric" MaxLength="3" HorizontalTextAlignment="Center"
Focused="Entnum1_Focused" TextColor="Black" FontSize="Medium" />
</StackLayout>
<!-- view Editors -->
<Frame BackgroundColor="White" AbsoluteLayout.LayoutBounds="0.5,0.94,0.95,0.6" CornerRadius="15" AbsoluteLayout.LayoutFlags="All">
<ScrollView x:Name="scrollView" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--<Editor Text="0" FontAttributes="Bold" TextColor="Black" FontSize="Medium" WidthRequest="100" x:Name="num1" Grid.Column="0" HorizontalOptions="Center" IsReadOnly="True" />-->
<Label Text="" FontAttributes="Bold" TextColor="Black" FontSize="25" WidthRequest="100" x:Name="num1" Grid.Column="0" HorizontalOptions="Center" />
<Image Source="linev.png" Grid.Column="1" Opacity="0.3"/>
<Label Text="" FontAttributes="Bold" TextColor="Black" FontSize="25" WidthRequest="100" x:Name="num2" Grid.Column="2" HorizontalOptions="Center" />
</Grid>
</ScrollView>
</Frame>
<!-- view Buttons -->
<StackLayout Orientation="Horizontal" AbsoluteLayout.LayoutBounds="0.5,0.14,0.95,0.09" AbsoluteLayout.LayoutFlags="All" >
<Button TextColor="#1C84D3" Text="تراجع" x:Name="btnBack" Clicked="btnBack_Clicked" HorizontalOptions="CenterAndExpand" BackgroundColor="White" CornerRadius="15" HeightRequest="70"
WidthRequest="70" FontSize="20" />
<Button TextColor="#1C84D3" Text="سجل" Clicked="btnRegister_Clicked" HorizontalOptions="CenterAndExpand" BackgroundColor="White" FontSize="20" CornerRadius="15" HeightRequest="70"
WidthRequest="70" />
</StackLayout>
<controls:AdControlView AbsoluteLayout.LayoutBounds="0.5,0.26,0.95,0.14" AbsoluteLayout.LayoutFlags="All"
AdUnitId="{Static local:Constants.AdUnitIdTest}"/>
</AbsoluteLayout>
</ContentPage.Content>
This is the XAML.cs
int SUM1 = 0;
// SUM2 لتخزين النتيجة الثانية
int SUM2 = 0;
// DisplayPromptAsync تخزين حالة الاشعار
string action;
// لتبديل بين entrys
int tap = 1;
// عدد الاعبين
int playercount = 1;
int count = 0;
bool scroll = false;
public Blootrecord(bool newplay)
{
InitializeComponent();
if (newplay)
{
DisplayPrompt(lblname1, "اسم فريقهم");
DisplayPrompt(lblname2, "اسم فريقنا?");
}
else
{
// اذا مالنت الثيمة ب False هذا يعني انه يريد الرجوع لاخر لعية
// هذه اسطر لجلب اخر قيم تم تخزينها
lblname1.Text = Preferences.Get("lblname1", "");
lblname2.Text = Preferences.Get("lblname2", "");
num1.Text = Preferences.Get("num1", "");
num2.Text = Preferences.Get("num2", "");
SUM1 = Convert.ToInt32(Preferences.Get("SUM1", "0"));
SUM2 = Convert.ToInt32(Preferences.Get("SUM2", "0"));
count = Convert.ToInt32(Preferences.Get("count", "0"));
}
scrollView.HeightRequest = num1.HeightRequest;
}
/// <summary>
/// هذه دالة لعررض الاشعار
/// </summary>
/// <param name="label"></param>
/// /// <param name="label2"></param>
/// <param name="str"></param>
async void DisplayPrompt(Label label, string str)
{
var s = await DisplayPromptAsync("Alert", str);
if (string.IsNullOrEmpty(s))
label.Text = "فريق" + playercount++;
else
label.Text = s;
}
/// <summary>
/// زر سجل
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
///
private async void btnRegister_Clicked(object sender, EventArgs e)
{
try
{
scrollView.HeightRequest = num1.HeightRequest;
scroll = false;
// اضافة سط في Editors مع القيمه المدخله
num1.Text += "\n" + Entnum1.Text;
num2.Text += "\n" + Entnum2.Text;
//اذا كان الentry فارغ يبدل القيمه ب صفر
if (string.IsNullOrEmpty(Entnum1.Text))
{
num1.Text += "0";
}
if (string.IsNullOrEmpty(Entnum2.Text))
{
num2.Text += "0";
}
//تحويل القيمه الي عدد صحيح وجمعها ع اخر قميه
SUM1 += int.Parse(num1.Text.Substring(num1.Text.LastIndexOf("\n") + 1));
SUM2 += int.Parse(num2.Text.Substring(num2.Text.LastIndexOf("\n") + 1));
// اذا كانت القيمه اقل من 152 يتم اضافة سطر ثم خط ثم قيمه الجمع في كل Editor
if (SUM1 < 152 && SUM2 < 152)
{
num1.Text += "\n" + "------";
num2.Text += "\n" + "------";
num1.Text += "\n" + SUM1;
num2.Text += "\n" + SUM2;
}
else
{
// يتم عرض اكير قيمه مع اكبر فائز
if (SUM1 > SUM2)
{
action = await DisplayActionSheet(" هاردلك الفوز لهم " + SUM1 + " ", "اغلاق", "لعبة جديدة");
}
else if (SUM1 < SUM2)
{
action = await DisplayActionSheet(" مبروك الفوز لنا" + SUM2 + "", "اغلاق", "لعبة جديدة");
}
else
{
action = await DisplayActionSheet("تعادل", "اغلاق", "لعبة جديدة");
}
// اذا قمت بأختيار لعبة جديدة
if (action == "لعبة جديدة")
{
// يحذف جميع القيم ولاكن يبقي اسم العبين
num1.Text = num2.Text = "0";
Entnum1.Text = Entnum2.Text = null;
SUM1 = SUM2 = 0;
await scrollView.ScrollToAsync(num1, ScrollToPosition.Start, true);
count = 0;
scroll = true;
}
}
Entnum1.Text = Entnum2.Text = null;
// store data
// تخزين البيانات في كل مره
Preferences.Set("lblname1", lblname1.Text);
Preferences.Set("lblname2", lblname2.Text);
Preferences.Set("num1", num1.Text);
Preferences.Set("num2", num2.Text);
Preferences.Set("SUM1", SUM1.ToString());
Preferences.Set("SUM2", SUM2.ToString());
count++;
if (count >= 5 && count <= 7 && !scroll)
{
await scrollView.ScrollToAsync(num1, ScrollToPosition.Center, true);
}
else if (count > 7 && !scroll)
{
await scrollView.ScrollToAsync(num1, ScrollToPosition.End, true);
}
}
catch (Exception ex)
{
// في حالة وجود خطأ غير متوقع
await DisplayAlert("Opps!", ex.Message, "Ok");
await Navigation.PopAsync();
}
}
void btnBack_Clicked(System.Object sender, System.EventArgs e)
{
try
{
if (num1.Text != "0" && num2.Text != "0")
{
// يتم اذالة ثلاث اسطر وطرح قيمة السطر الثالث من المجموع الكلي ثم ازالة السطر الثالث
// editor number one
num1.Text = num1.Text.Remove(num1.Text.LastIndexOf("\n"));
num1.Text = num1.Text.Remove(num1.Text.LastIndexOf("\n"));
SUM1 -= int.Parse(num1.Text.Substring(num1.Text.LastIndexOf("\n") + 1));
num1.Text = num1.Text.Remove(num1.Text.LastIndexOf("\n"));
// editor number two
num2.Text = num2.Text.Remove(num2.Text.LastIndexOf("\n"));
num2.Text = num2.Text.Remove(num2.Text.LastIndexOf("\n"));
SUM2 -= int.Parse(num2.Text.Substring(num2.Text.LastIndexOf("\n") + 1));
num2.Text = num2.Text.Remove(num2.Text.LastIndexOf("\n"));
}
}
catch (Exception ex)
{
DisplayAlert("Opps!", ex.Message, "Ok");
}
}
private void Entnum1_Focused(object sender, FocusEventArgs e)
{
tap = 1;
}
private void Entnum2_Focused(object sender, FocusEventArgs e)
{
tap = 2;
}
private void Entnum2_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// في حالة اختيار Closr
if (action == "اغلاق")
{
// حزف جميع القيم المخزنه
Preferences.Clear();
// الرجوع الي الصفحة الاولة
Navigation.PopAsync();
}
}
}
}
This is an example of error , it calculates only English number
once I put Arabic Number it colses the app
Thank you
Arabic numbers are treated as char not numbers by the compiler if you want to use arabic number you have to manually map them with a case statement for example or a dictionary. if you parse them as an int an exception will be thrown.
problem fixed by this way
public int ArabicNumber (string unicode )
{
var str = unicode.Replace('\u0660', '0')
.Replace('0','0')
.Replace('\u0661', '1')
.Replace('\u0662', '2')
.Replace('\u0663', '3')
.Replace('\u0664', '4')
.Replace('\u0665', '5')
.Replace('\u0666', '6')
.Replace('\u0667', '7')
.Replace('\u0668', '8')
.Replace('\u0669', '9');
return int.Parse(str);
}

How to pass the bound property with command to modify it

i have a page with multiple labels that each have a different property bound to it and when tapped open up a prompt to modify their value. I can't figure out how to pass that property with the command so i can modify it and use this same command for all labels.
In ContentPage:
<Label x:Name="lblLevel" Text="{Binding Level}" FontSize="Large">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding InputPopup}"
CommandParameter="{Binding Source={x:Reference lblLevel}, Path=Text}" />
</Label.GestureRecognizers>
</Label>
Command:
public ICommand InputPopup => new Command(
async () => {
PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Name,
OkText = "Confirm",
Title = "New value",
CancelText = "Cancel",
MaxLength = 1,
});
if (pResult.Ok && !string.IsNullOrWhiteSpace(pResult.Text))
{
//Todo: PropertyX (Level) = pResult.Text
}
}
);
Thank you
just bind the CommandParameter to the same property as the Label
Command="{Binding InputPopup}"
CommandParameter="{Binding Level}" />
So after trying a couple different things that i couldn't get to work i ended up using a switch, it's not pretty but atleast it works.
Command (in FreshMVVM ViewModel):
public ICommand EditValuePopupCommand => new Command<string>(
async (param) =>
{
PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Name,
OkText = "Confirm",
Title = $"Edit {param}",
CancelText = "Cancel",
MaxLength = 2,
});
if (pResult.Ok && !string.IsNullOrWhiteSpace(pResult.Text))
{
switch (param)
{
case "Level": Level = int.Parse(pResult.Text); break;
case "Strength": Strength = "Str: " + pResult.Text; break;
case "Dexterity": Dexterity = "Dex: " + pResult.Text; break;
case "Constitution": Constitution = "Con: " + pResult.Text; break;
case "Wisdom": Wisdom = "Wis: " + pResult.Text; break;
case "Intelligence": Intelligence = "Int: " + pResult.Text; break;
case "Charisma": Charisma = "Cha: " + pResult.Text; break;
case "AttackModifier": AttackModifier = "Attack: " + pResult.Text; break;
case "SpellAttackModifier": SpellAttackModifier = "Spell Attack: " + pResult.Text; break;
case "SecondaryAttackModifier": SecondaryAttackModifier = "Second Attack: " + pResult.Text; break;
case "SaveDC": SaveDC = "Second Attack: " + pResult.Text; break;
default:
Console.WriteLine("Default case");
break;
}
}
}
);
XAML:
<StackLayout Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
<Frame Style="{StaticResource DefaultFrameStyle}">
<Label x:Name="lblStrength" Text="{Binding Strength}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding EditValuePopupCommand}"
CommandParameter="Strength" />
</Label.GestureRecognizers>
</Label>
</Frame>
<Frame Style="{StaticResource DefaultFrameStyle}">
<Label x:Name="lblDexterity" Text="{Binding Dexterity}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding EditValuePopupCommand}"
CommandParameter="Dexterity" />
</Label.GestureRecognizers>
</Label>
</Frame>

Removing Item from observable collection causes textbox to focus

I have a textbox that is on the same screen as a listbox. When I remove an item from the listbox, which is bound to an observable collection, the textbox gains focus. Is there a way to stop this from happening?
I am using MVVM but am open to putting some code in the code behind if it fixes this problem.
EDIT:
CodeBehind View:
namespace Offload.WinPhone.Views
{
using System.Windows.Controls;
using Microsoft.Phone.Controls;
public partial class MainPageView : PhoneApplicationPage
{
public MainPageView()
{
InitializeComponent();
}
private void QuickNoteBodyEditor_TextChanged(object sender, TextChangedEventArgs e)
{
var senderAsTextbox = (TextBox)sender;
if (senderAsTextbox.Text.Length == 0)
this.Focus();
}
}
}
View:
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="OFFLOAD" FontFamily="Segoe WP Bold" Grid.Row="0"/>
<ListBox x:Name="QuickNotes" Grid.Row="1" TabIndex="1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,5,0,5" Orientation="Vertical">
<TextBlock Style="{StaticResource PhoneTextExtraLargeStyle}" TextWrapping="Wrap" Text="{Binding Body}"/>
<TextBlock Style="{StaticResource PhoneTextAccentStyle}" Text="{Binding Timestamp, StringFormat='{}{0:dd MMM HH:mm}'}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox x:Name="QuickNoteBodyEditor" AcceptsReturn="True" Grid.Row="2" InputScope="Chat" TextChanged="QuickNoteBodyEditor_TextChanged" IsTabStop="True" />
</Grid>
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBar.Buttons>
<cal:AppBarButton IconUri="/AppFramework/Resources/Icons/Add.png" Text="Add" Message="AddQuickNote" />
<cal:AppBarButton IconUri="/AppFramework/Resources/Icons/Delete.png" Text="Delete" Message="DeleteSelectedQuickNote" />
</shell:ApplicationBar.Buttons>
<shell:ApplicationBar.MenuItems>
<cal:AppBarMenuItem Text="About" Message="NavigateToAddAccountView"/>
<cal:AppBarMenuItem Text="Review" Message="NavigateToAddAccountView"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
ViewModel:
public class MainPageViewModel : PropertyChangedBase
{
private ObservableCollection<QuickNote> quickNotes;
private string quickNoteBodyEditor;
private QuickNote selectedQuickNote;
// Databound Properties
public string QuickNoteBodyEditor
{
get { return quickNoteBodyEditor; }
set { quickNoteBodyEditor = value; NotifyOfPropertyChange(() => QuickNoteBodyEditor); NotifyOfPropertyChange(() => CanAddQuickNote);}
}
public QuickNote SelectedQuickNote
{
get { return selectedQuickNote; }
set { selectedQuickNote = value; NotifyOfPropertyChange(() => SelectedQuickNote); NotifyOfPropertyChange(() => CanDeleteSelectedQuickNote); }
}
public ObservableCollection<QuickNote> QuickNotes
{
get { return quickNotes; }
set { quickNotes = value; NotifyOfPropertyChange(() => QuickNotes); }
}
// Guard Clauses
public bool CanAddQuickNote
{
get { return !string.IsNullOrWhiteSpace(quickNoteBodyEditor); }
}
public bool CanDeleteSelectedQuickNote
{
get{ return selectedQuickNote == null ? false : true; }
}
// Constructors
public MainPageViewModel()
{
GetQuickNotesFromIsolatedStorage();
WatchWhatsGotFocus.StartWatching();
}
// Public Methods
public void AddQuickNote()
{
if (CanAddQuickNote)
{
quickNotes.Add(new QuickNote(quickNoteBodyEditor, DateTime.Now));
AddQuickNotesToIsolatedStorage();
quickNoteBodyEditor = string.Empty;
NotifyOfPropertyChange(() => QuickNoteBodyEditor);
NotifyOfPropertyChange(() => QuickNotes);
}
}
public void DeleteSelectedQuickNote()
{
if (CanDeleteSelectedQuickNote)
{
quickNotes.Remove(selectedQuickNote);
AddQuickNotesToIsolatedStorage();
selectedQuickNote = null;
NotifyOfPropertyChange(() => SelectedQuickNote);
NotifyOfPropertyChange(() => QuickNotes);
}
}
private void GetQuickNotesFromIsolatedStorage()
{
quickNotes = IsolatedStorage.Get<ObservableCollection<QuickNote>>("QuickNoteList");
}
private void AddQuickNotesToIsolatedStorage()
{
IsolatedStorage.Add("QuickNoteList", quickNotes);
}
}
I had the same issue, a possible solution is to set the TextBox to disabled before modifying your collection and enable it afterwards again:
TextBox.IsEnabled = false;
ObservableCollection.Remove(object);
TextBox.IsEnabled = true;
I wouldn't call it a clean approach, but it worked for me :).

Resources