zxing qr/barcode scanning using MVVM? - xamarin

Im new in xamarin, Im trying to make a Button that opens a scanner form that scans qr/barcode that is MVVM method. Im trying to get the result and display it into a label. this is my best guest but it doesn't work, hope someone can help.
view:
<StackLayout>
<Label Text="{Binding CodigoQr}"/>
<zxing:ZXingScannerView x:Name="ucZXingScannerView"
IsScanning="True"
IsAnalyzing="True"
Result="{Binding CodigoQr}"
ScanResultCommand="{Binding ScanCommand }" />
</StackLayout>
ViewModel:
public class BarcodeScanVM : BaseViewModel
{
private Result _codigoQr;
public Result CodigoQr
{
get { return _codigoQr; }
set
{
_codigoQr = value;
OnPropertyChanged();
}
}
public AsyncCommand ScanCommand { get; set; }
public BarcodeScanVM()
{
ScanCommand = new AsyncCommand(OnScanResultCommand);
}
async Task OnScanResultCommand()
{
var text = CodigoQr;
}
}```

You can use the code-behind the view for the actions. And use the VM for other properties
XAML:
<zxing:ZXingScannerView
IsAnalyzing="{Binding IsAnalyzing}"
IsScanning="{Binding IsScanning}"
OnScanResult="CameraScanner_OnScanResult" />
Code behind:
private void CameraScanner_OnScanResult(ZXing.Result result)
{
((MyViewModel)BindingContext).OnScanComplete(result.Text);
}

Try without using ScannerView. In XAML add a Label (I'm using an Entry) and a Button that opens the scanner:
<Button Text="QR Scan"
TextColor="White"
CornerRadius="30"
Clicked="ButtonScan"/>
<Entry BackgroundColor="White"
IsTextPredictionEnabled="False"
TextTransform="Uppercase"
FontSize="Body"
TextChanged="Search"
Placeholder="Search"
TextColor="Black"
PlaceholderColor="Black"
x:Name="lblBarcode"
Keyboard="Chat">
On the Clicked Event of the Button:
private async void ButtonScan(object sender, EventArgs e)
{
PermissionStatus granted = await Permissions.CheckStatusAsync<Permissions.Camera>();
if (granted != PermissionStatus.Granted)
{
_ = await Permissions.RequestAsync<Permissions.Camera>();
}
if (granted == PermissionStatus.Granted)
{
try
{
MobileBarcodeScanner scanner = new MobileBarcodeScanner();
ZXing.Result result = await scanner.Scan();
if (result != null && result.Text != "")
{
lblBarcode.Text = result.Text; // <--- This places the result of scanner at Entry/Label
scanner.Cancel(); // <--- This closes the scanner
}
}
catch (Exception)
{
await DisplayAlert("Problem", "Something went wrong.", "ΟΚ");
}
}
else
{
await DisplayAlert("Problem", "No permissions to use camera.", "ΟΚ");
}
}

update: I tried this one, seems like the scanning command works but the program stops afterwards.
ViewMode:
private Result bcScanResult;
public Result BcScanResult
{
get => bcScanResult;
set
{
if (value == bcScanResult)
return;
bcScanResult = value;
OnPropertyChanged();
}
}
public AsyncCommand BcScanCommand { get; }
public CodeScanVM()
{
BcScanCommand = new AsyncCommand(BcScanCommand_Call);
}
async Task BcScanCommand_Call()
{
await App.Current.MainPage.DisplayAlert("Item", "Code Async
Command:" + Result, "OK");
return;
}
View:
<zxing:ZXingScannerView
x:Name="ScanView"
Result="{Binding BcScanResult}"
ScanResultCommand="{Binding BcScanCommand }"
IsScanning="True"
WidthRequest="300"
HeightRequest="300"/>

You can give a look at my sample app on github
xam-barcode-scanner
It works in both platforms and without the need of ZXing library

Related

How do I display a Lottie animation at least one time when IsBusy is true during data loading?

On my Xamarin.Forms project, I would like to display a Lottie animation during API calls or during the loading of a website in a WebView.
For this, I've bounded the IsVisible property of the Lottie animation to the IsBusy property of my ViewModels: this works well.
<lottie:AnimationView Animation="resource://lottie_loading.json?assembly=MyApp"
AnimationSource="EmbeddedResource"
BackgroundColor="Transparent"
AutoPlay="True"
RepeatMode="Infinite"
IsVisible="{Binding IsBusy}">
But the loading duration is sometimes very short, so I would like to found a way to display the Lottie animation once in full before to hidden it.
Is it possible? What would be the better approach to achieve this?
I would like to display a Lottie animation during API calls
public async void loadData()
{
//Data load started
viewModel.IsBusy = true;
await methodOfLoadingData...;
//Data load finished
viewModel.IsBusy = false;
}
during the loading of a website in a WebView:
private void MyWebView_Navigating(object sender, WebNavigatingEventArgs e)
{
viewModel.IsBusy = true;
}
private void MyWebView_Navigated(object sender, WebNavigatedEventArgs e)
{
viewModel.IsBusy = false;
}
But the loading duration is sometimes very short
The loading duration is depending on the time you completely loading the data/webview. If you load the data/webview very fast, the loading duration should be short.
I've found another approach that works, even if this solution is a bit heavy and can be improved.
Firstly, as recommended there, I've created 2 Triggers:
public class PlayLottieAnimationTriggerAction : TriggerAction<AnimationView>
{
protected override void Invoke(AnimationView sender)
{
Debug.WriteLine($"PlayLottieAnimationTriggerAction()");
sender.PlayAnimation();
}
}
public class StopLottieAnimationTriggerAction : TriggerAction<AnimationView>
{
protected override void Invoke(AnimationView sender)
{
Debug.WriteLine($"StopLottieAnimationTriggerAction()");
sender.StopAnimation();
}
}
I also used EventToCommandBehaviors, like described there.
After this I can use the Lottie animation like this:
<forms:AnimationView
x:Name="animationView"
BackgroundColor="Transparent"
AutoPlay="True"
IsVisible="{Binding ShowAnimation}"
Animation="resource://lottie_4squares_apricot_blond.json?assembly=Example.Forms"
AnimationSource="EmbeddedResource"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<forms:AnimationView.Triggers>
<MultiTrigger TargetType="forms:AnimationView">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding ShowAnimation}" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.EnterActions>
<triggers:LottieTriggerAction />
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<actions:StopLottieAnimationTriggerAction />
</MultiTrigger.ExitActions>
</MultiTrigger>
</forms:AnimationView.Triggers>
<forms:AnimationView.Behaviors>
<behaviors:EventToCommandBehavior
EventName="OnFinishedAnimation"
Command="{Binding OnFinishedAnimationCommand}"
CommandParameter="{x:Reference animationView}"/>
</forms:AnimationView.Behaviors>
</forms:AnimationView>
And in my ViewModel, I've declared a property ShowAnimation that is related to IsBusy and the Command OnFinishedAnimationCommand like this:
private bool _showAnimation;
public bool ShowAnimation
{
get => _showAnimation;
set => Set(ref _showAnimation, value);
}
public ICommand OnFinishedAnimationCommand
{
get
{
return new Xamarin.Forms.Command<object>(async (object sender) =>
{
if (sender != null)
{
await OnFinishedAnimation(sender);
}
});
}
}
private Task OnFinishedAnimation(object sender)
{
var view = sender as AnimationView;
if (IsBusy)
{
view.PlayAnimation();
}
else
{
ShowAnimation = false;
}
return Task.CompletedTask;
}
In case of the Loader is related to a WebView, the ShowLoadingView property is set like this:
private Task WebViewNavigatingAsync(WebNavigatingEventArgs eventArgs)
{
IsBusy = true;
ShowLoadingView = true;
return Task.CompletedTask;
}
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
}
But, as I also display an ErrorView in case of issues (timeout, unreachable server, ...) and a Reload/Retry button, I had to add some code:
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
// for display loading animation on Refresh
while (ShowLoadingView)
await Task.Delay(50);
SetServiceError();
}
In case of the Loader is related to Data loading, the ShowLoadingView property is set like this:
private async Task GetNewsAsync(bool forceRefresh = false)
{
try
{
ShowErrorView = false;
ErrorKind = ServiceErrorKind.None;
IsBusy = true;
ShowLoadingView = true;
var _news = await _dataService.GetNews(forceRefresh);
News = new ObservableCollection<News>(_news);
}
catch (Exception ex)
{
ErrorKind = ServiceErrorKind.ServiceIssue;
}
finally
{
IsBusy = false;
await SetServiceError();
}
}
However, I noticed that in some cases the SetServiceError() was not fired, as OnFinishedAnimation() was called in the same time. I haven't yet investigated, but I've fixed this by adding the call to SetServiceError() in in OnFinishedAnimation():
private async Task OnFinishedAnimation(object sender)
{
var view = sender as AnimationView;
if (IsBusy)
{
view.PlayAnimation();
}
else
{
ShowLoadingView = false;
// fix SetServiceError() call issue
await SetServiceError();
}
}
Don't hesitate to tell what could be done to optimize this.

Xamarin iOS webview underlap behind navigation bar

I am using xamarin custom webview to load my page in app. But facing issue that title of webpage hides behind navigation bar . Or sometimes bottom of page not shown. I have tried adding scrollbar to my layout but still facing issue. Same works perfectly on android. Is it due to custom webview? I just want my webview to start below navigation bar and load completely according to device size.
my custom webview code :
public class CustomWebView : WebView
{
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(CustomWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
Xaml Page :
<StackLayout Orientation="Vertical" HorizontalOptions="StartAndExpand" VerticalOptions="StartAndExpand">
<StackLayout>
<Label x:Name="type" Text="Loading..." FontSize="Medium"/>
</StackLayout>
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<ScrollView Orientation="Vertical" FlowDirection="MatchParent" HorizontalOptions="StartAndExpand" VerticalOptions="StartAndExpand" Visual="Material" VerticalScrollBarVisibility="Always">
<OnPlatform x:TypeArguments="View">
<On Platform="Android">
<WebView x:Name="dashboard_android" HeightRequest="1000" WidthRequest="1000" />
</On>
<On Platform="iOS">
<local:CustomWebView x:Name="dashboard_ios" VerticalOptions="StartAndExpand" HorizontalOptions="FillAndExpand" WidthRequest="1000" HeightRequest="1000"/>
</On>
</OnPlatform>
</ScrollView>
</StackLayout>
</StackLayout>
code behind :
dashboard_android.Source = url;
dashboard_ios.Uri = url;
Following are solutions i have tried but no success
Solution 1 :
I have tried adding two properties, but no use
this.EdgesForExtendedLayout = UIRectEdge.None;
this.ExtendedLayoutIncludesOpaqueBars = false;
Solution 2 :
Tried enabling this unsafe area property , still no success
ios:Page.UseSafeArea="true"
Solution 3 :
Tried setting webview height on content size dynamically , but no success
public override async void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
// base.DidFinishNavigation(webView, navigation);
var wv = _webViewRenderer.Element as CustomWebView;
if (wv != null)
{
await System.Threading.Tasks.Task.Delay(100); // wait here till content is rendered
wv.HeightRequest = (double)webView.Frame.Size.Height; // ScrollView.ContentSize.Height;
}
}
Updated Xaml Code :
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<local:CustomWebView x:Name="dashboard" HeightRequest="1000" WidthRequest="1000" />
</StackLayout>
Updated Code behind :
public partial class DashboardView : ContentPage
{
string url;
public DashboardView()
{
InitializeComponent();
url= ""; //adding url to load here
dashboard.Uri = url;
}
}
Custom WebView Renderer
[assembly: ExportRenderer(typeof(CustomWebView), typeof(MyCustomWebViewRenderer))]
namespace Report.iOS
{
public class MyCustomWebViewRenderer : ViewRenderer<CustomWebView, WKWebView>
{
WKWebView webView;
protected override void OnElementChanged(ElementChangedEventArgs<CustomWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
webView = new WKWebView(Frame, new WKWebViewConfiguration());
webView.NavigationDelegate = new WebViewDelegate();
SetNativeControl(webView);
}
if (e.NewElement != null)
{
Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Uri)));
}
}
}
public class WebViewDelegate : WKNavigationDelegate, INSUrlConnectionDataDelegate
{
string uname = null;
string pass = null;
public override async void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
try
{
uname = Xamarin.Forms.Application.Current.Properties.ContainsKey("Username") ? Convert.ToString(Xamarin.Forms.Application.Current.Properties["Username"]) : null;
pass = await SecureStorage.GetAsync("Password");
}
catch (Exception ex)
{
}
completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, new NSUrlCredential(uname, pass, NSUrlCredentialPersistence.ForSession));
return;
}
}
}
Screenshot of webview screen :
Here i am loading this webpage(https://learn.microsoft.com/en-us/xamarin/essentials/device-display?tabs=android). As you can see half of footer is hidden and i am not able to scroll it.
Screenshot of app
The reason for it quite simple actually you have added the WebView inside a scrollView which is, in turn, causing the issue webview has its own scroll so all you have to do is something like:
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<local:CustomWebView x:Name="dashboard" />
</StackLayout>
Also, you do not need the on the platform you can directly use the below and the custom renderer you have created.
The Height/Width request & layout options are not needed Webview by default will capture the whole viewport, You could actually even remove the StackLayouts, But that's on you.
Also, you might wanna read more about the webview
Good luck
Feel free to get back if you have queries
You can use latest WkWebViewRenderer:
public class MyCustomWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
//this.LoadUrl("https://learn.microsoft.com/en-us/xamarin/essentials/device-display?tabs=android");
this.NavigationDelegate = new WebViewDelegate();
}
}
In your code behind, you can directly set the source or set your binding:
dashboard.Source = "https://learn.microsoft.com/en-us/xamarin/essentials/device-display?tabs=android";
Also, start from xamarin.forms 4.5+, xamarin use WKWebview as the default control in iOS and that means you no longer need a custom renderer if you use xamarin.forms 4.5+. Refer:
UIWebView Deprecation and App Store Rejection (ITMS-90809)
I was facing that issue just beacuse i was using custom renderer.
My solution code is as follows :
Xaml Code :
<ContentPage.Content>
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<WebView x:Name="dashboard" HeightRequest="1000" WidthRequest="1000"/>
</StackLayout>
</ContentPage.Content>
Code Behind :
public partial class DashboardView : ContentPage
{
public DashboardView()
{
InitializeComponent();
dashboard.Source = "url";
}
}
Authentication Renderer iOS :
[assembly: ExportRenderer(typeof(WebView), typeof(Report.iOS.WebViewRenderer))]
namespace Report.iOS
{
class WebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
this.NavigationDelegate = new WebViewDelegate();
}
}
public class WebViewDelegate : WKNavigationDelegate, INSUrlConnectionDataDelegate
{
string uname = null;
string pass = null;
public override async void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
try
{
uname = Xamarin.Forms.Application.Current.Properties.ContainsKey("Username") ? Convert.ToString(Xamarin.Forms.Application.Current.Properties["Username"]) : null;
pass = await SecureStorage.GetAsync("Password");
}
catch (Exception ex)
{
}
completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, new NSUrlCredential(uname, pass, NSUrlCredentialPersistence.ForSession));
return;
}
}
}
Authentication Renderer Android :
[assembly: ExportRenderer(typeof(WebView), typeof(AuthWebViewRenderer))]
namespace Report.Droid
{
public class AuthWebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
AuthWebViewClient _authWebClient = null;
public AuthWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (_authWebClient == null)
{
_authWebClient = new AuthWebViewClient();
}
Control.SetWebViewClient(_authWebClient);
}
}
public class AuthWebViewClient : WebViewClient
{
public AuthWebViewClient()
{
}
public override async void OnReceivedHttpAuthRequest(global::Android.Webkit.WebView view, HttpAuthHandler handler, string host, string realm)
{
string uname = null;
string pass = null;
try
{
uname = Application.Current.Properties.ContainsKey("Username") ? Convert.ToString(Application.Current.Properties["Username"]) : null;
pass = await SecureStorage.GetAsync("Password");
}
catch (Exception ex)
{
Log.Error("Apprise :", "Error Occurred while getting login credentials " + ex);
}
handler.Proceed(uname, pass);
}
}
}

Get start position of a listview scroll to end in xamarin forms wpf

I have worked on getting listview scroll position scroll to end in xamarin forms WPF application. I have tried below solution, it works in ios and android but unfortunately, it doesn't work in wpf application. Please suggest any idea to get scroll position of a listview end in xamarinforms WPF application.
Sample code you can find in below link
https://stackoverflow.com/questions/40373761/how-to-set-listview-to-start-showing-the-last-item-instead-in-xamarin-forms
If you're working with Xamarin Forms, you can create a control that extend from ListView and add methods for scrolling to top or bottom.
namespace YourAppName.Controls
{
public class CustomListView : ListView
{
public CustomListView() : this(ListViewCachingStrategy.RecycleElement)
{
}
public CustomListView(ListViewCachingStrategy cachingStrategy)
: base(cachingStrategy)
{
}
public void ScrollToFirst()
{
Device.BeginInvokeOnMainThread(() =>
{
try
{
if (ItemsSource != null && ItemsSource.Cast<object>().Count() > 0)
{
var firstItem = ItemsSource.Cast<object>().FirstOrDefault();
if (firstItem != null)
{
ScrollTo(firstItem, ScrollToPosition.Start, false);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
});
}
public void ScrollToLast()
{
try
{
if (ItemsSource != null && ItemsSource.Cast<object>().Count() > 0)
{
var lastItem = ItemsSource.Cast<object>().LastOrDefault();
if (lastItem != null)
{
ScrollTo(lastItem, ScrollToPosition.End, false);
}
}
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
}
}
And on your xaml:
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:YourAppName.Controls"
x:Class="YourAppName.Views.CustomListViewPage">
<controls:CustomListView
x:Name="customListView"
ItemsSource="{Binding Items}"
SeparatorVisibility="None"
SelectionMode="None"
HasUnevenRows="true">
<controls:CustomListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label
FontSize="Medium"
Text="{Binding TestText}" />
</ViewCell>
</DataTemplate>
</controls:CustomListView.ItemTemplate>
</controls:CustomListView>
</ContentPage>
And on the code behind you can do something like this:
namespace YourAppName.Views
public partial class CustomListViewPage : ContentPage
{
public CustomListViewPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
this.customListView.ScrollToLast();
}
}

Xamarin Forms ListView text not displayed

I'm new to Xamarin Forms, I'm following the official tutorial for learning Xamarin forms. While learning about navigation using Phoneword project of the following link
https://developer.xamarin.com/guides/xamarin-forms/getting-started/hello-xamarin-forms-multiscreen/quickstart/
The listview text is not appearing. Please help me!
CallHistoryPage.xaml: Here the listview is there.
<?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:local="clr-namespace:App1;assembly=App1"
x:Class="App1.CallHistoryPage"
Title="Call History">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="20, 40, 20, 20"/>
<On Platform="Android" Value="20"/>
</OnPlatform>
</ContentPage.Padding>
<StackLayout>
<ListView ItemsSource="{x:Static local:App.PhoneNumbers}" />
</StackLayout>
</ContentPage>
MainPage.xaml.cs: SourceItem values are updated in this class.
namespace App1
{
public partial class MainPage : ContentPage
{
string translatedNumber;
public MainPage()
{
InitializeComponent();
}
void OnTranslate(object sender, EventArgs e)
{
translatedNumber = PhonewordTranslator.ToNumber(phoneNumberText.Text);
if (!string.IsNullOrWhiteSpace(translatedNumber))
{
callButton.IsEnabled = true;
callButton.Text = "Call " + translatedNumber;
}
else
{
callButton.IsEnabled = false;
callButton.Text = "Call";
}
}
async void OnCall(object sender, EventArgs e)
{
if (await this.DisplayAlert(
"Dial a Number",
"Would you like to call " + translatedNumber + "?",
"Yes",
"No"))
{
var dialer = DependencyService.Get<IDialer>();
if (dialer != null)
{
App.PhoneNumbers.Add(translatedNumber);
callHistoryButton.IsEnabled = true;
dialer.Dial(translatedNumber);
}
}
}
async void OnCallHistory(object sender, EventArgs e)
{
await Navigation.PushAsync(new CallHistoryPage());
}
}
}
App.xaml.cs: Sourceitem for listview is in this class
namespace App1
{
public partial class App : Application
{
public static IList<string> PhoneNumbers { get; set; }
public App()
{
InitializeComponent();
PhoneNumbers = new List<string>();
MainPage = new NavigationPage(new MainPage());
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
For more details please follow the link added above. Same tutorial is followed.
You forgot to 'tell' ListView what to display.
<ListView ItemsSource="{x:Static local:App.PhoneNumbers}" />
creates a ListView with empty cells, hence they are not displaying anything. You'll have to set the ListView.ItemTemplate in order to display anything
<ListView ItemsSource="{x:Static local:App.PhoneNumbers}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding .}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The BindingContext within the DataTemplate will be the respective item from App.PhoneNumbers. Since the items are bare strings we bind to ., which refers to the bound element itself.
See here for ListViews in Xamarin.Forms.
You have not added any numbers in PhoneNumbers list. Add number first in PhoneNumbers list and then check.
public App()
{
InitializeComponent();
PhoneNumbers = new List<string>();
PhoneNumbers.Add("123456789");
PhoneNumbers.Add("178967897");
PhoneNumbers.Add("178945678");
MainPage = new NavigationPage(new MainPage());
}
I think you have forget to take input from user.So add this line in OnCall method
translatedNumber = PhonewordTranslator.ToNumber(phoneNumberText.Text);
Try this,
async void OnCall(object sender, EventArgs e)
{
translatedNumber = PhonewordTranslator.ToNumber(phoneNumberText.Text);
if (await this.DisplayAlert(
"Dial a Number",
"Would you like to call " + translatedNumber + "?",
"Yes",
"No"))
{
var dialer = DependencyService.Get<IDialer>();
if (dialer != null)
{
App.PhoneNumbers.Add(translatedNumber);
callHistoryButton.IsEnabled = true;
dialer.Dial(translatedNumber);
}
}
}

Saving the state of multiple checkboxes for wp7

I created a button to create multiple checkbox on no. of clicks for wp7. Below the codes I used for it.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox x:Name="txtNewTask" HorizontalAlignment="Left" Height="72" TextWrapping="Wrap" VerticalAlignment="Top" Width="328"/>
<Button x:Name="btnAdd" Content="add" HorizontalAlignment="Left" Margin="328,0,0,0" VerticalAlignment="Top" Width="123" Click="btnAdd_Click"/>
<ListBox x:Name="lbToDoList" Margin="0,72,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Click="CheckBox_Click" Background="{x:Null}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" Name="tbkTextName" VerticalAlignment="Center" Margin="5,0,5,0" />
</StackPanel>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Now when I exit and re-open my app, I noticed the checkbox’s are unchecked (default state) and its state is not saved. Can you please help me to save the multiple checkbox's value or state?
Can anybody help me to save the multiple checkbox's state. Thanks in advance for your help!
You need to save data to a time when your application is not running. For that staff I use IsolatedStorage. You can save anything, what you need. I found great tutorial, how it implement. hope it's help.
I Think the best way is, to save the value of the checkbox instantly when it changes.
To do so you can do the following:
Assume that the check box in the myPage.xaml looks like:
<CheckBox Content="{Binding Title}" Name="myAutoSavingCheckBox" Click="myAutoSavingCheckBox_Click"/>
In the myPage.xaml.cs you have to define the following method:
private void myAutoSavingCheckBox_Click(object sender, RoutedEventArgs e)
{
App.ViewModel.MyProperty = myAutoSavingCheckBox.IsChecked;
}
The App.ViewModel is declared in the App.xaml.cs:
public partial class App : Application
{
...
public static MainViewModel ViewModel
{
get
{
// Erstellung des Ansichtsmodells verzögern bis erforderlich
if (viewModel == null)
viewModel = new MainViewModel();
return viewModel;
}
}
...
}
Now you define your Property and the saving Function in the MainViewModel.cs as follows:
public class MainViewModel
{
private bool? myProperty;
public bool? MyProperty
{
get
{
return myProperty;
}
set
{
if (value != myProperty)
{
myProperty = value;
SaveSetting("MyProperty", myProperty);
}
}
}
public void SaveSettings(string whatShallBeSavedKey, object whatShallBeSavedValue)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains("whatShallBeSavedKey"))
IsolatedStorageSettings.ApplicationSettings["whatShallBeSavedKey"] = whatShallBeSavedValue;
else
IsolatedStorageSettings.ApplicationSettings.Add("whatShallBeSavedKey", whatShallBeSavedValue);
}
}
Use IsolatedStorage.ApplicationSettings
Here are two helper methods for accessing application settings
/// Get the current value of the setting, or if it is not found, set the
/// setting to the default setting.
protected valueType GetValueOrDefault<valueType>(string Key, valueType defaultValue)
{
valueType value;
object storedValue = null;
try
{
if (_isolatedStore.TryGetValue(Key, out storedValue))
{
value = (valueType)(_isolatedStore[Key] ?? defaultValue);
}
else
{
//the key was not found
value = defaultValue;
}
}
catch (Exception ex)
{
value = defaultValue;
Logger.Error(ex, "Exception while getting IsolatedStorageSettings: ");
}
return value;
}
protected bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
object storedValue = null;
try
{
if (_isolatedStore.TryGetValue(Key, out storedValue))
{
if (storedValue != value)
{
_isolatedStore[Key] = value;
valueChanged = true;
}
}
else
{
//the key was not found
_isolatedStore.Add(Key, value);
}
}
catch (Exception ex)
{
Logger.Error(ex, "Exception while adding IsolatedStorageSettings.");
}
return valueChanged;
}
And you can then create a property on some settings class or view model that is backed by IsolatedStorage like this.
string CheckBoxValueKeyName = "checkbox_value";
bool CheckBoxValueDefault = false;
public bool CheckBoxValue
{
get
{
return GetValueOrDefault<bool>(CheckBoxValueKeyName, CheckBoxValueDefault );
}
set
{
AddOrUpdateValue(CheckBoxValueKeyName, value);
}
}
If you don't want to apply the changes of checking the box immediately to isolated storage, the WP7 Tombstone Helper is a quick way to persist the state of your controls after the app tombstones. So, yes, for persistent storage after the application is closed use Isolated Storage.

Resources