ZXING mobile issue with repeat scanning - xamarin.forms

I am using the zing mobile scanner and it works well however I am calling the same action from a different button and it's refusing to scan it brings up the preview window ok but won't invoke the scan.
public async void BtnScanStockTakeItem_Clicked(object sender, EventArgs e)
{
var scanPage = new ZXingScannerPage();
scanPage.ToggleTorch();
scanPage.IsScanning = true;
await Navigation.PushAsync(scanPage);
scanPage.OnScanResult += (result) =>
{
// Stop scanning
scanPage.IsScanning = false;
// Pop the page and show the result
Device.BeginInvokeOnMainThread(async () =>
{
await Navigation.PopAsync();
}
}
I am then calling the above from another button method lets say the saved function
private async void SaveFunction(object sender, EventArgs e)
{
foreach (var item in transferList)
{
int z = await restServices.PostStockTakeTransaction(item);
}
Preferences.Set("StockTakeWarehouse", pickStockTake.SelectedIndex);
WarehouseName = pickStockTake.SelectedItem.ToString();
bool x = await DisplayAlert("Test", "Item Saved", "ReScan", "Cancel");
if (x)
{
BtnScanStockTakeItem_Clicked(sender, e);
//this is where it rescans the item
}
}
String thing is I am getting no logcat errors or nothing the viewport of the scanner shows but just won't accept the scan some reason same barcode format as before.

For anyone else who faces a simlar problem it was the fact my camera thread was not properly called I had to do
Device.BeginInvokeOnMainThread(async () =>
{
BtnScanStockTakeItem_Clicked(sender, e);
});
Works as expected

Related

Calling Async task in button click in xamarin.forms

I have xamarin.forms app contains a listview which will load values from Rest API.Which is working fine.I have button just above the listview.When I click on the button, the listview API call will be placed again and the listview should update. But stuck at this update part.I am not using MVVM pattern.The listview listing portion is an async Task.I am calling the async task again when the button click, but App gets crash. Is it due to calling the async task again from button click? Any help is appreciated.
Here is My code.
namespace app
{
public partial class List : ContentPage
{
PendingWeekRange pendingWeekRange = new PendingWeekRange();
public TimeSheetList()
{
InitializeComponent();
Task.Run(async () =>
{
await LoadScreenItems();
});
}
async Task LoadScreenItems()
{
await Task.Run(async () => {
try
{
// Doing some stuff
await loadTimeSheetList();
}
catch (Exception)
{
}
});
}
async Task loadTimeSheetList()
{
await Task.Run(() => { + string postdataForPendingList = "{\"date\":\"" + "1" + "\"}";
APICall callForAPICallResult = new APICall("/API/ListMobile/ListForApproval", postdataForList, loadingIndicator);
try
{
List<ListData> resultObjForPendingTimeSheetList = callForAPICallResult<List<ListData>>();
if (resultObjForPendingTimeSheetList != null)
{
TimesheetList.ItemsSource = resultObjForPendingTimeSheetList;
screenStackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
TimesheetList.IsVisible = true;
}
else
{
}
}
catch (Exception)
{
}
});
}
async void Button_Tapped(object sender, EventArgs e)
{
try
{
// Calling my listview again. After calling app gets crash
Task.Run(async () => await loadTimeSheetList());
}
catch (Exception ex) { }
}
}
}
A few things before getting to the problem. You've got async/await all wrong, go though Async Programming
Task.Run runs the passed action on a different thread, if you make changes to UI elements on this thread, your app will definitely(take my word) crash.
If you want to make async call at page launch, make use of OnAppearing method (if you only want to call once, maintain a flag)
Do not change the ItemsSource of a list view frequently, just clear and add items to it.
namespace app
{
public partial class List : ContentPage
{
PendingWeekRange pendingWeekRange = new PendingWeekRange();
private ObservableCollection<ListData> TimesheetObservableCollection = new ObservableCollection<ListData>();
public TimeSheetList()
{
InitializeComponent();
TimesheetList.ItemsSource = TimesheetObservableCollection;
}
protected override async OnAppearing()
{
// flag for first launch?
await LoadScreenItems();
}
async Task LoadScreenItems()
{
try
{
// Doing some stuff
TimesheetObservableCollection.Clear();
TimesheetObservableCollection.AddRange(await GetTimeSheetList());
}
catch (Exception)
{
//handle exception
}
}
async Task<List<ListData>> GetTimeSheetList()
{
string postdataForPendingList = "{\"date\":\"" + "1" + "\"}";
APICall callForAPICallResult = new APICall("/API/ListMobile/ListForApproval", postdataForList, loadingIndicator);
try
{
return callForAPICallResult<List<ListData>>();
}
catch (Exception)
{
// handle exception
}
}
async void Button_Tapped(object sender, EventArgs e)
{
try
{
// Calling my listview again. After calling app gets crash
TimesheetObservableCollection.Clear();
TimesheetObservableCollection.AddRange(await GetTimeSheetList());
}
catch (Exception ex) { }
}
}
}
#Androdevil,
Update your loadTimeSheetList with this,
async Task loadTimeSheetList()
{
try
{
// I am calling my API for Listview here.
List<TimeSheetListData> resultObjForPendingTimeSheetList = await callForPendingTimeSheetList.APICallResult<List<TimeSheetListData>>();
if (resultObjForPendingTimeSheetList != null)
{
TimesheetList.ItemsSource = resultObjForPendingTimeSheetList;
screenStackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
TimesheetList.IsVisible = true;
}
else
{
}
}
catch (Exception)
{
}
}

How to initialize bar code scanner on App startup

I have a requirement for my xamarin cross platform application that as soon as app start up .QR Scanner set in to read the code. on completing scanning a beep will be ring up.and app again ready for next scanning how can i get this done. what i have done is on button click scanner start, its read code, then i have to press button again to start it again.
public HomePage()
{
Button scanBtn = new Button
{
Text = "Scan Barcode",
HorizontalOptions = LayoutOptions.FillAndExpand,
};
scanBtn.Clicked += async (sender, args) =>
{
var scanResult = await Acr.BarCodes.BarCodes.Instance.Read();
if (!scanResult.Success)
{
await this.DisplayAlert("Alert ! ", "Sorry ! \n Failed to read the Barcode !", "OK");
}
else
{
var endpoint = new EndpointAddress("http://192.168.15.33/SMS/WebServices/SMSService.svc");
var binding = new BasicHttpBinding
{
Name = "basicHttpBinding",
MaxBufferSize = 2147483647,
MaxReceivedMessageSize = 2147483647
};
TimeSpan timeout = new TimeSpan(0, 0, 30);
binding.SendTimeout = timeout;
binding.OpenTimeout = timeout;
binding.ReceiveTimeout = timeout;
_client = new SMSServiceClient(binding, endpoint);
_client.ValidateStudentAsync("123-admin");
_client.ValidateStudentCompleted += _client_ValidateStudentCompleted; ;
// await this.DisplayAlert("Scan Successful !", String.Format("Barcode Format : {0} \n Barcode Value : {1}", scanResult.Format, scanResult.Code), "OK");
}
};
Content = new StackLayout
{
Children = {
scanBtn
}
};
}
and in app.cs
public class App : Application
{
public App()
{
// The root page of your application
MainPage = new HomePage();
}
protected override void OnStart()
{
MainPage = new HomePage();
}
protected override void OnSleep()
{
MainPage = new HomePage();
}
protected override void OnResume()
{
MainPage = new HomePage();
}
}
You can use ZXing.Net.Mobile for Forms to read QR codes. To initialize this plugin you should call method to init into each project (Android, iOS, UWP) like this:
For Android in MainActivity.cs class call:
ZXing.Net.Mobile.Forms.Droid.Platform.Init();
For iOS in AppDeletage.cs class call
ZXing.Net.Mobile.Forms.iOS.Platform.Init();
And finally to read QR Codes:
private async void Scan() {
var scanPage = new ZXingScannerPage();
scanPage.OnScanResult += (result) => {
// Stop scanning
scanPage.IsScanning = false;
// Pop the page and show the result
Device.BeginInvokeOnMainThread( async () => {
await Navigation.PopAsync();
await DisplayAlert("Scanned Barcode", result.Text, "OK");
});
};
// Navigate to our scanner page
await Navigation.PushAsync(scanPage);
}

ZXing OnScanResult is called twice on Xamarin.Forms

I have a Xamarin.Forms application. I use ZXing.Mobile.Forms to scan a QR code; however, when I point the camera to a QR code the OnScanResult event is called twice. This is my code, a faithful reproduction of the one suggested here:
private async void onScanQRCode(object sender, EventArgs e)
{
var scanPage = new ZXingScannerPage(); // executed just once
scanPage.OnScanResult += (result) => {
// Stop scanning
scanPage.IsScanning = false; // executed twice (confused)
// Pop the page and show the result
Device.BeginInvokeOnMainThread(() => {
Navigation.PopAsync();
/* Business code */
Account scannedAccount = URLInterpreter.Accept(result.Text);
ViewModel.ProcessNewAccount(scannedAccount);
/* End of business code */
});
};
// Navigate to our scanner page
await Navigation.PushAsync(scanPage);
}
And this is the XAML for the button that calls the method above:
<Button x:Name="btnScanCode" Text="Scan QR Code" Clicked="onScanQRCode" />
Any pointers?
UPDATE
Apparently, this only happens when I'm debugging the app and the phone is connected to Visual Studio. If I launch the app without attaching the debugger, the event is fired once.
I had the same issue, this answer helped me to resolve it: Xamarin.Forms ZXing.Net.Mobile loosing current page after scan result on iOS 10
Your code should be:
private async void onScanQRCode(object sender, EventArgs e)
{
var scanPage = new ZXingScannerPage();
bool scanFinished = false;
scanPage.OnScanResult += (result) => {
// Stop scanning
scanPage.IsScanning = false;
// Pop the page and show the result
Device.BeginInvokeOnMainThread(async () => {
if (!scanFinished)
{
scanFinished = true;
Account scannedAccount = URLInterpreter.Accept(result.Text);
ViewModel.ProcessNewAccount(scannedAccount);
await Navigation.PopAsync();
}
});
};
// Navigate to our scanner page
await Navigation.PushAsync(scanPage);
}
I tested on iOS 10.3.1 and ZXing.Net.Forms.Mobile 2.2.9.

Why cant change textbox text in client function SignalR

I just start testing signalr and I am trying to add text to a rich text box after I got a response from my HUB class , but it doesn't work (no text is shown in my richtextbox) I don't know why...(the code run with no errors)
//server
public class ConnectByHub : Hub
{
public void testFunc(mas) {
string ans = mas + " got it";
Clients.All.testFunc(ans);
} }
//Client
private async void connectToServer()
{
Connection = new HubConnection(LocalClient);
HubProxy = Connection.CreateHubProxy("ConnectByHub");
try
{
await Connection.Start();
}
catch (Exception ex)
{
return;
}
string msg = "Hello friend!";
HubProxy.Invoke("testFunc", (msg)).Wait();
// Option one - doesn't work
HubProxy.On<string>("testFunc", (param) => Invoke((Action)(() => { MsgTxtBox.Text = "something happened"; })));
//Option two - doesn't work
HubProxy.On<string>("testFunc", (param) => this.Invoke((Action)(() => { MsgTxtBox.AppendText("Something happend " + Environment.NewLine); })));
}
I think part of the problem is trying to send a message from the same Async method (connectToServer) in which your listener is running.
I mostly used the same code from the question but moved a couple things around:
Moved HubProxy.Invoke() out of the Async method and called it from a button_click event
Called string.format() on the parameter
SERVER:
public class ConnectByHub : Hub
{
public void Send(string message)
{
Clients.All.testFunc(message);
}
}
CLIENT:
// Added button event
private void button1_Click(object sender, EventArgs e)
{
string msg = "Hello friend!";
HubProxy.Invoke("Send", msg).Wait();
}
private async void ConnectToServerAsync()
{
Connection = new HubConnection(LocalClient);
HubProxy = Connection.CreateHubProxy("ConnectByHub");
// Put the parmater in string.format()
HubProxy.On<string>("testFunc", (param) => this.Invoke((Action)(() => MsgTxtBox.AppendText(string.Format("{0}", param)))));
try
{
await Connection.Start();
}
catch (Exception ex)
{
richTextBox1.AppendText(string.Format("Unable to Connect to server ({0})", ServerURI));
return;
}
}

ASP.Net and Parallel.Foreach causes buttons to stop working?

i have a very large database of images from the web which i am categorizing (downloaded locally).
so i have a website (locally) to do this, but the db queries were taking long, so i got an idea to "preload" the next page, so that only the very first load of the page would be slow. I save the list of items loaded in a seperate thread in session. So far so good.
I wanted to optimize further, and did some testing on what took the longest, and loading the images to check the size to see if i needed to scale them (set image height and width on the img obj) - so i wanted to do this with a parallel.foreach loop - but after doing this, my buttons on the page stopped responding? i can see the page runs through the page_load event when i press a button, but it doesn't reach the buttons "code":
protected virtual void btnSaveFollowPosts_Click(object sender, EventArgs e)
{...}
any take on what i am doing wrong? i have tried to limit the degree of paralellelism to 1 just to see if that would fix it - but it did not.
Update - code:
trying to boil it down:
protected void Page_Load(object sender, EventArgs e)
{
Search(false);
}
protected void Search(bool updateCounters)
{
if (Session[SessionItems] == null)
{
if (Session[SessionItemsCache] == null)
{
//if is being constructed, wait, else construct
//if construction is not running
if (Session[SessionCacheConstructionRunning] == null)
{
StartPreLoadContent();
}
while (Session[SessionCacheConstructionRunning] != null)
{
Thread.Sleep(25); //block main thread untill items ready
}
}
List<ContentView> contentViewList = Session[SessionItemsCache] as List<ContentView>;
Session[SessionItemsCache] = null; //clean preload cache
Session[SessionItems] = contentViewList; //save in current usage storage
Filltable(ref tblContent, contentViewList);
//preload next batch
StartPreLoadContent();
}
else
{
List<ContentView> contentViewList = Session[SessionItems] as List<ContentView>; //get items from session
Session[SessionItems] = contentViewList; //save in current usage storage
Filltable(ref tblContent, contentViewList);
}
}
protected void StartPreLoadContent()
{
Session[SessionCacheConstructionRunning] = true;
//start task
Thread obj = new Thread(new ThreadStart(RunPreLoadContent));
obj.IsBackground = true;
obj.Start();
}
protected void RunPreLoadContent()
{
using (DBEntities entities = new DBEntities())
{
entities.CommandTimeout = 86400;
IQueryable<ContentView> query = entities.ContentView.Where(some criterias);
List<ContentView> contentViewListCache = query.ToList();
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 7;
Parallel.ForEach(contentViewListCache, options, content =>
{
try
{
Interlocked.Increment(ref imageSizeCount);
string path = Path.Combine(basePath, content.LocalPath);
int imageSize = 150;
using (System.Drawing.Image realImage = System.Drawing.Image.FromFile(path))
{
double scale = 0;
if (realImage.Height > realImage.Width)
{
scale = (double)realImage.Height / imageSize;
}
else
{
scale = (double)realImage.Width / imageSize;
}
if (scale > 1)
{
content.ImageHeight = (int)((double)realImage.Height / scale);
content.ImageWidth = (int)((double)realImage.Width / scale);
content.ImageScaled = true;
}
content.ShowImage = true;
}
}
catch (Exception)
{
}
});
Session[SessionItemsCache] = contentViewListCache;
Session[SessionCacheConstructionRunning] = null; //cache ready
}
protected virtual void btnSave_Click(object sender, EventArgs e)
{
try
{
//save
...some reading and saving going on here...
//update
Session[SessionItems] = null;
Search(true);
}
catch (Exception error)
{
ShowError(error);
}
}
I agree with a previous comment: you should probably do this logic earlier in the page lifecycle. Consider overriding OnInit and putting it there.
Also, you could try this line of code instead of your current thread code (which is more suited to Windows not Web programming):
using System.Threading.Tasks;
Task.Run(() => { RunPreLoadContent(); });

Resources