I am still beginner in Xamarin .
I created an application to connect with machine using Mobile app ( Xamarin.forms ).
I created a button , when clicked , i receive the data ( number of product produced ) in a Entry ( read only ) .
<ContentPage Title="Production Data">
<StackLayout>
<Label Text="Packs Produced"></Label>
<Entry x:Name="Packs" IsReadOnly="True"></Entry>
<Button x:Name="ReadData" Text="Read" Clicked="ReadData_Clicked"></Button>
</StackLayout>
</ContentPage>
Then
private void ReadData_Clicked(object sender, EventArgs e)
{
Packs.Text = string.Format();
}
I need to update the packs.text every 5 sec .
I did the same with another application using windows Form using timer ( when ReadData button is clicked , it enable the timer ) and timer_tick ( to read the data every 5 second).
Could this be done using xiamarin ?
I did the same with another application using windows Form using timer ( when ReadData button is clicked , it enable the timer ) and timer_tick ( to read the data every 5 second).Could this be done using xiamarin ?
If you want to do something like Timer in Xamarin.forms Android, you could try code below.
Device.StartTimer(TimeSpan.FromSeconds(30), () =>
{
// Do something
return true; // True = Repeat again, False = Stop the timer
});
I use the number i to update the value in entry each 5 seconds for your reference.
private void ReadData_Clicked(object sender, EventArgs e)
{
int i = 0;
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
{
// Do something
Packs.Text = i.ToString();
i++;
return true; // True = Repeat again, False = Stop the timer
});
}
If you want to do more in IOS, UWP, you could check the code in the link.
https://xamarinhelp.com/xamarin-forms-timer/
You can implement this by easily using Matcha.BackgroundService plugin.More info https://github.com/winstongubantes/MatchaBackgroundService
You can initiate the task on every X seconds or minutes using this plugin.
In your button click, You can start the timer service like
private void Button_Tapped(object sender, EventArgs e)
{
//Register Periodic Tasks
BackgroundAggregatorService.Add(() => new PeriodicCall(5));
//Start the background service
BackgroundAggregatorService.StartBackgroundService();
Device.BeginInvokeOnMainThread( () =>
{
Packs.Text = string.Format();
});
}
Create a class named PeriodicCall and in your Periodic Call
public class PeriodicCall : IPeriodicTask
{
public PeriodicCallTest(int seconds)
{
Interval = TimeSpan.FromSeconds(seconds);
}
public TimeSpan Interval { get; set; }
public Task<bool> StartJob()
{
// Messeging center used for updating the value.
MessagingCenter.Send<Object>(new Object(), "FetchValue");
return true;
}
}
In your xaml.cs where you want to get the value
MessagingCenter.Subscribe<Object>(this, "FetchValue", async (sender) =>
{
Device.BeginInvokeOnMainThread( () =>
{
Packs.Text = string.Format();
});
});
Related
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
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.
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(); });
I am calling few methods on a button click.
functionA()
functionB()
functionC()
All three functions are independent from each other and they take long time to execute. I checked and found that by threading I can run all three together which will save the execution time.
As I am new to threading concept, could anyone please guide me the simplest way I can do threading in scenario or other way which will be useful in this scenario.
EDIT
One more problem in the same function:
I am binding 5 gridviews after the three functions execution. Like this
gv1.DataSource = GetData("Mill");
gv1.DataBind();
gv2.DataSource = GetData("Factory");
gv2.DataBind();
gv3.DataSource = GetData("Garage");
gv3.DataBind();
gv4.DataSource = GetData("Master");
gv4.DataBind();
They all are using the same method for getting the result and they are also taking time to load. Is there any way I can run them parallel too? I afraid, because they are using same method to get the data. Is it possible to do threading for them. How ?
I am not sure how Parallel.Invoke() decides what to execute in parallel, but if you want an assurance that they will execute in parallel, use threads:
var t1 = new Thread(MySlowFunction);
t1.IsBackground = true;
t1.Start();
var t2 = new Thread(MySlowFunction);
t2.IsBackground = true;
t2.Start();
# To resync after completion:
t1.Join();
t2.Join();
Or even better, use the ThreadPool:
ThreadPool.QueueUserWorkItem(MyWork);
Remember to handle your thread exceptions.
The simplest answer is to use MSDN: Parallel.Invoke().
You should also consider: Asynchronous Pages.
Try using System.Threading.Tasks namespace
Something like
var task1 = Task.Factory.StartNew(() => DoA());
var task2 = Task.Factory.StartNew(() => DoB());
var task3 = Task.Factory.StartNew(() => DoC());
Task.WaitAll(task1, task2, task3);
http://www.codethinked.com/net-40-and-systemthreadingtasks
Here's an example which will execute the 4 tasks in parallel:
public partial class _Default : System.Web.UI.Page
{
public class MyViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void BtnBindClick(object sender, EventArgs e)
{
// we define the input for the tasks: each element consists
// of the grid we are willing to bind the results at the end and
// some optional parameter we want to pass to the GetData function
var inputs = new[]
{
new { Grid = gv1, Input = "Mill" },
new { Grid = gv2, Input = "Factory" },
new { Grid = gv3, Input = "Garage" },
new { Grid = gv4, Input = "Master" },
};
// define the tasks we want to execute in parallel
var tasks = inputs
.Select(x => Task.Factory.StartNew(
() => new { Grid = x.Grid, Output = GetData(x.Input) })
)
.ToArray();
// define a task which will be executed once all tasks have finished
var finalTask = Task.Factory.ContinueWhenAll(tasks, x => x);
// wait for the final task
finalTask.Wait();
// consume the results
foreach (var item in finalTask.Result)
{
if (item.Exception == null)
{
// if no exception was thrown for this task we could bind the results
item.Result.Grid.DataSource = item.Result.Output;
item.Result.Grid.DataBind();
}
}
}
private MyViewModel[] GetData(string input)
{
// Simulate slowness
Thread.Sleep(1000);
return Enumerable.Range(1, 5).Select(x => new MyViewModel
{
Id = x,
Name = input
}).ToArray();
}
}
Greetings, creating my first MVVM based WPF app and trying to figure out why I'm unable to hook into the PropertyChanged event of a dependency property.
Code in the parent view model:
void createClients()
{
var clients = from client in Repository.GetClients()
select new ClientViewModel(Repository, client);
foreach (var client in clients)
{
client.PropertyChanged += onClientPropertyChanged;
}
Clients = new ViewableCollection<ClientViewModel>(clients);
Clients.CollectionChanged += onClientsCollectionChanged;
}
// Never gets called
void onClientPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Name")
{
//...
}
}
ViewableCollection is a simple extension of ObservableCollection to encapsulate a View.
In the ClientViewModel the setters are being called but RaisePropertyChanged isn't working as I would expect, because onClientPropertyChanged isn't being invoked. Both view models inherit from ViewModelBase.
public string Name
{
get { return client.Name; }
set
{
if (value == client.Name) return;
client.Name = value;
RaisePropertyChanged("Name");
}
}
If I wire up PropertyChanged to a method inside the ClientViewModel then it is being fired, so I'm stumped as to why this isn't working in the parent view model. Where am I going wrong?
This SO question explains the problem; ObservableCollection protects the PropertyChanged event.
One solution is to use MVVM-Light Messenger:
void createClients()
{
var clients = from client in Repository.GetClients()
select new ClientViewModel(Repository, client);
Clients = new ViewableCollection<ClientViewModel>(clients);
Clients.CollectionChanged += onClientsCollectionChanged;
Messenger.Default.Register<PropertyChangedMessage<string>>(this, (pcm) =>
{
var clientVM = pcm.Sender as ClientViewModel;
if (clientVM != null && pcm.PropertyName == "Name")
{
// ...
}
});
}
createClients() should be refactored, but for consistency with the question code I'll leave it in there. Then a slight change to the property setter:
public string Name
{
get { return client.Name; }
set
{
if (value == client.Name) return;
string oldValue = client.Name;
client.Name = value;
RaisePropertyChanged<string>("Name", oldValue, value, true);
}
}