MVVM binding from static method - c#

I'm working on my app that will get data from online database. I would like to show progress bar. Problem is that I can not make it work.
Current situation is:
I am using FreshMVVM.
Method to get data form online is in class FirebaseCloudNight. There is static method SynchronizeNights with which I get all nights (with function foreach). I would like to show progress bar based on nights done/remaining to be synchronized.
In ViewModel I have property CurrentProgress that is correctly bidden to View. I can not update this property correctly.
I left out a lot of code because I think is irrelevant. If you need more code please let me know.
The only solution I found is to create new instance of MV class. But after additional reading I found out that, although I see that property changed, binding was not OK, because it changed new instance of property.
Issue is that the only way I found is to update this property based on new instance. But then MVVM does not work --> UI is not refreshed because it updates different instance of property. How can this be done?
Below is my code (if it will be of any help).
Code to retrieve DB from cloud
namespace iVanApp.Services {
public class FirebaseCloudNight : FirebaseCloudBaseHelper
{
static public async Task<bool> SynchronizeNights()
{
// Synchronize from Cloud to DB
foreach (var cloudItem in cloudNights)
{
CurrentProgress= currentNight / numberOfNights;
try
{
//Here I removed code for retriving data from online DB
currentNight ++;
}
catch (Exception ex)
{
return false;
}
return true;
}
}
}
ViewModel Code
async Task GetData()
{
bool success = await FirebaseCloudNight.SynchronizeNights();>
}
float currentProgress;
public float CurrentProgress
{
get => currentProgress;
set
{
currentProgress = value;
RaisePropertyChanged();
}
}
EDIT:
What I tried and does not work (because of obvious reasons)
namespace iVanApp.Services {
public class FirebaseCloudNight : FirebaseCloudBaseHelper
{
static public async Task<bool> SynchronizeNights()
{
// Synchronize from Cloud to DB
var VM = new UserAuthenticationPageModel();
foreach (var cloudItem in cloudNights)
{
VM.CurrentProgress = currentNight / numberOfNights;
try
{
//Here I removed code for retriving data from online DB
currentNight ++;
}
catch (Exception ex)
{
return false;
}
return true;
}
}
}

Found an answer that is working
Added code in ViewModel code behind
public class UserAuthenticationPageModel : FreshBasePageModel
{
public static UserAuthenticationPageModel Instance { get; private set; }
public UserAuthenticationPageModel()
{
Instance = this;
}
Modified code in FirebaseCloudNight
namespace iVanApp.Services { public class FirebaseCloudNight :
FirebaseCloudBaseHelper {
static public async Task<bool> SynchronizeNights()
{
// Synchronize from Cloud to DB
foreach (var cloudItem in cloudNights)
{
UserAuthenticationPageModel.Instance.CurrentProgress = currentNight / numberOfNights
try
{
//Here I removed code for retriving data from online DB
currentNight ++;
}
catch (Exception ex)
{
return false;
}
return true;
}
} }

Related

Writing errors to a text file in a Web Service

I have a web service that has a default ErrorLog method for adding Logs to a Db Table. If there's an exception is caught on the ErrorLog Add or the Stored Procedure returns that it failed to add. I'd like to write the error to a textfile on the server, (in theory this should never happen).
Now before actually implementing this, I realize there's a good chance that multiple people could get an error, all of them fail, and all of them try to write to the same text file.
How can I implement a queue on the service, so that the messages get added to the queue and another service / job loops through this queue and adds the errors to the file?
I have tried looking for examples, most of them are very basic. The only thing I really want to know is how I should keep track of the queue? Do I simply create a static class?
Would the below work?
public class ErrorLogging
{
public ErrorLogging(Error error)
{
if (ErrorLoggingQueue._GlobalQueue == null)
{
ErrorLoggingQueue._GlobalQueue = new Queue<Error>();
}
ErrorLoggingQueue._GlobalQueue.Enqueue(error);
}
}
public static class ErrorLoggingQueue
{
public static Queue<Error> _GlobalQueue;
}
// Assume that this class/method gets called every x minutes or seconds from a job or something.
public class JobClass
{
public void WriteErrors()
{
if (ErrorLoggingQueue._GlobalQueue != null)
{
while (ErrorLoggingQueue._GlobalQueue.Count != 0)
{
Error error = (Error)ErrorLoggingQueue._GlobalQueue.Dequeue();
// Do stuff here
}
}
}
}
Yes, static variable with a Queue will work and would be shared between requests. Just add locking for enqueue and dequeue to make those operation atomic. Something along these lines:
class YourWebservice
{
static Queue<Error> _GlobalQueue = new Queue<Error>();
static readonly object queueLock = new object();
static Thread errorLogger;
public void SomeWebserviceMethod()
{
//Some code...
//.
//.
//Here we want to log an error
EnqueueError(new Error());
}
private void EnqueueError(Error err )
{
lock(queueLock)
{
_GlobalQueue?.Enqueue(err);
if ( errorLogger==null || !(errorLogger?.IsAlive ?? false) )
{
errorLogger = new Thread(new ThreadStart(WriteErrors));
errorLogger?.Start();
}
}
}
private static Error DequeueError()
{
try
{
lock (queueLock)
{
return _GlobalQueue?.Dequeue();
}
}
catch(Exception)
{
//if we got here it means queue is empty.
}
return null;
}
private static void WriteErrors()
{
Error error = DequeueError();
while (error!=null)
{
//Log error here
//...
//..
error = DequeueError();
}
}
}

How do I change the values of variables within one class, from another?

Please excuse my ignorance for I am new to C#.
I am currently working on an MVVM project in which a viewmodel has multiple instantiated public variables that are data-bound to elements in a view (WPF). When these variables are changed they automatically update in my view. Take for instance the code segment below from my view model...
private string _displaybind;
public string DisplayBind
{
get { return _displaybind; }
set
{
SetProperty(ref _displaybind, value);
if (_displaybind.Length > 5000)
{
DisplayBind = _displaybind.Substring(_displaybind.IndexOf('\n') + 1);
}
}
}
By using the command DisplayBind = "Hello"; within my viewmodel I can push out text to a textbox I have located in my XAML view. Unfortunately, I have reached a point where I can not simply edit the value of DisplayBind.
I need to start a state machine within my viewmodel which will access several states (classes) in separate C# files. However, I have no idea how to receive, and more importantly edit the values within my viewmodel from these separate classes.
I start my state machine in my viewmodel using this...
IPMProgram ipmprogram = new IPMProgram();
ipmprogram.StartTheIPMProgram();
This is my IPMProgram class
public class IPMProgram
{
public IPMProgramState currentState = null;
public IPMProgram()
{
currentState = new BootBannerState(this);
}
public void StartTheIPMProgram()
{
while (true)
{
currentState.GetNextState();
}
}
}
This is my IPMProgramState class
public abstract class IPMProgramState
{
private IPMProgram ipmprogram;
public IPMProgram Ipmprogram
{
get { return ipmprogram; }
set { ipmprogram = value; }
}
public abstract void GetNextState();
}
And this is my BootBannerState class (The state I want to edit DisplayBind from)
class BootBannerState : IPMProgramState
{
public BootBannerState(IPMProgramState state)
:this(state.Ipmprogram)
{
}
public BootBannerState(IPMProgram ipmprograminstance)
{
this.Ipmprogram = ipmprograminstance;
}
public override void GetNextState()
{
//DisplayBind = "Hello"!
return;
}
}
Someone suggested that I should look into Dependency Injection, but I don't quite understand how it would work for me. What should I do?
Thank you for all of your help,
Tesnich

Serializing Model using NewtonSoft in WPF Application

I am trying to serialize my model each second and push it to a server. I have set up a periodic task which executes each second. I call SendNewMessage to execute the push.
The first method call to SendNewMessage() which is called from the constructor runs fine with no exceptions or issues.
When the async task tries to call the SendNewMessage I get an exception and my application shuts down. It is the NewtonSoft code:
String PushModelToServer = JsonConvert.SerializeObject(this, jss); Which fails
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in
'C:\Users\snovva\Source\Workspaces\HMI\HMI.ViSoft\bin\x86\Debug\HMI.ViSoft.vshost.exe'.
Additional information: The runtime has encountered a fatal error. The address of the error was at 0x71041771, on thread 0x2788. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
public class Model : ModelBase
{
public Model ()
{
PeriodicTask.Run(() =>
{
SendNewMessage();
},
TimeSpan.FromSeconds(1));
SendNewMessage();
}
public void SendNewMessage()
{
// Send the message
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.Formatting = Newtonsoft.Json.Formatting.Indented;
String PushModelToServer = JsonConvert.SerializeObject(this, jss);
sendMessage(System.Text.Encoding.Unicode.GetBytes(PushModelToServer));
}
}
public class PeriodicTask
{
public static async Task Run(Action action, TimeSpan period, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(period, cancellationToken);
if (!cancellationToken.IsCancellationRequested)
action();
}
}
public static Task Run(Action action, TimeSpan period)
{
return Run(action, period, CancellationToken.None);
}
}
More Info As requested:
The call on line 10 in the constructor runs. The serialization works the first time. Since the data in the model is changing I am pushing this model every second to update server. It is the async call which fails. As time passes the data in the model will change.
You can use [IgnoreDataMember] to avoid serializing properties that should not be included.
The code below works in my application, and should hopefully help you arrive at a solution for your app.
I am hoping that the code you show above is a snippet of your real code because there are some potential issues with the 1 second timer, re-entrancy, etc. Instead of doing this timer in the Model constructor, consider moving it to another function/class and setting up the timer/calls from an additional call you setup later...again, just some suggestions on arriving at a good pattern. Do more research here...
Here is how I get my data, what you want in your PushModelToServer:
public class BackupData
{
public List<Vehicles> Vehicles { get; private set; }
public List<FuelStops> FuelStops { get; private set; }
public BackupData(List<Vehicles> vehicles, List<FuelStops> fuelStops)
{
Vehicles = vehicles;
FuelStops = fuelStops;
}
public string ToJson(Formatting formatting = Formatting.None)
{
var json = JsonConvert.SerializeObject(this, formatting);
return json;
}
public static BackupData FromJson(string jsonBackupData)
{
var data = JsonConvert.DeserializeObject<BackupData>(jsonBackupData);
return data;
}
}
Here is a snippet of one of my classes:
[DebuggerDisplay("{VehicleName}")]
public class Vehicles : IComparable<Vehicles>, INotifyPropertyChanged
{
private string id;
public string Id
{
get { return id; }
set
{
if (id != value) { id = value; NotifyPropertyChanged(); }
}
}
private string vehicleName;
public string VehicleName
{
get { return vehicleName; }
set
{
if (vehicleName != value) { vehicleName = value; NotifyPropertyChanged(); }
}
}
public override string ToString()
{
return VehicleName;
}
[IgnoreDataMember]
public UpdateState UpdateState { get; set; }
....
And here is how I get the data so I can use it anywhere I want:
#if WINDOWS_PHONE_APP
private void OnExecuteBackup(SettingsPage obj)
{
#else
private async Task<bool> OnExecuteBackup(SettingsPage obj)
{
#endif
var backupData = App.JournalModel.GetBackupData().ToJson(Formatting.Indented);
...
await SaveBackupFile(file, backupData);
...
public class JournalModel
{
...
public BackupData GetBackupData()
{
var data = new BackupData(Vehicles.ToList(), FuelStops.ToList());
return data;
}
...
Good luck with your project.
Well there must be something the the class You're trying to serialize, that makes the serializer go crazy. Maybe instead of serializing 'this' You should try serializing an actual 'DataObject' - something that can be serialized, and doesn't contain references to Timers, tasks, ect.. ?

Updating an object from another objects property history in C# for implementing a PATCH

I'm trying to implement a PATCH on Web API for an object that will be stored in a DB. The input object from the controller has all of the properties that can be modified but we allow the client to choose which fields to send back. We only want to update the MongoDB representation if some of the fields have changed or been set. We started using a Dirty object pattern (not sure this is a pattern) whereby when you set a property you also record that it is dirty. for instance
public class Example
{
private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
TitleWasSet = true;
}
}
public bool TitleWasSet {get;set;}
}
This could work but is kind of tedious and I feel it exposes lots of logic that could be contained.
So a solution I came up with was to store the update Actions in the inbound object then reapply them to the Mongo Object in a Try Update fashion.
like this:
public class Data
{
public string Header { get; set; }
public int Rating { get; set; }
}
public class EditDataRequest
{
private readonly List<Action<Data>> _updates;
public EditDataRequest()
{
_updates = new List<Action<Data>>();
}
public string Header
{
set
{
_updates.Add(data => {data.Header = value;});
}
}
public int Rating
{
set
{
_updates.Add(data => {data.Rating = value;});
}
}
public bool TryUpdateFromMe(Data original)
{
if (_updates.Count == 0)
return false;
foreach (var update in _updates)
{
update.Invoke(original);
}
return true;
}
}
Now this would work great but it doesn't take account of the values being the same. So i then looked at changing the list of actions to a list of functions that would return a bool if there was a difference in the value.
private readonly List<Func<Data, bool>> _updates;
And then the properties would look like this:
public int Rating
{
set
{
_updates.Add(data => {
if (data.Rating != value)
{
data.Rating = value;
return true;
}
return false;
});
}
}
And the try update method...
public bool TryUpdateFromMe(Data original)
{
if (_updates.Count == 0)
return false;
bool changesRequired = false;
foreach (var update in _updates)
{
changesRequired |= update.Invoke(original);
}
return changesRequired;
}
As you can see that property set implementation is rather clunky and would make the code nasty to read.
I'd like a way of extracting the check this property value then update it to another method that I can reuse in each property - I assume this is possibly somehow but it might not be.
Of course, if you have better suggestions for how to handle the PATCH situation then I'd be happy to hear them as well.
Thanks for reading this far.

How to wait until a process finishes in EntityFramework?

I'm working with EntityFramework and Silverlight, and I'm dealing with this situation. When I try to load the data from a EntitySet, I have to get the data from a callback.
Now, I need to get the data inmediately, I mean wait until the process finished.
In the next code, the part which I'd like to wait the process is Objectives property. Or I don't know if I can convert the callback method into a IAsyncResult, or something like that.
public class EntityService : IEntityService
{
public EntityService()
{
_entities = new DatabaseDomainContext();
}
private DatabaseDomainContext _entities;
public DatabaseDomainContext Entities
{
get { return _entities; }
set { _entities = value; }
}
private EntityList<Objective> _objectives;
public ObservableCollection<Objective> Objectives
{
get
{
if (_objectives == null)
{
var loadOp = _entities.Load(_entities.GetObjectivesQuery()/*, Callback, true*/);
_objectives = new EntityList<Objective>(_entities.Objectives, loadOp.Entities);
}
return _objectives;
}
}
}
Implement INotifyPropertyChanged. When the results return, raise NotifyPropertyChanged.

Categories