C#: How do I share an instance of a class between classes? - c#

I have multiple instances of forms within my windows form application that I instantiate upon loading the main form (including an instance of the main form itself). I would like them to be shared between classes so I can use them from any location. I also need to use the members of each class through these instances.
Please note that I am very confused as to how this works. I don't know how I should be declaring instances of my forms but I only want one instance of each so that I can use the .Hide() method and also use each form's/class's members.
I've tried making the instances as properties but I am not sure how to proceed. I am not sure if that is correct.
// get and set for form instances
public Menu menu { get; set; }
public RandomFacts randomFacts { get; set; }
public QuizMenu qm { get; set; }
public AskHowManyQuestions ahmq { get; set; }
// in the main form load method
menu = new Menu();
randomFacts = new RandomFacts();
qm = new QuizMenu();
ahmq = new AskHowManyQuestions();
That code is all within the same 'main' form.
I hope that you can help me with being able to access these instances globally and help me solve this problem. Thank you for reading about my issue.

Trivial example:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var NewClassInstance = Singleton.GetSingleton().NewClassInstance;
Singleton.GetSingleton().NewClassInstance.Method();
var OtherClassInstance = Singleton.GetSingleton().OtherClassInstance;
var Proparty = OtherClassInstance.Name;
}
}
public class Singleton
{
public NewClass NewClassInstance {get; private set;}
public OtherClass OtherClassInstance {get; private set;}
private static readonly NewClass _newClass = new NewClass();
private static readonly OtherClass _otherClass = new OtherClass();
private static readonly Singleton _singleton = new Singleton();
private Singleton()
{
NewClassInstance = _newClass;
OtherClassInstance = _otherClass;
// Prevent outside instantiation
}
public static Singleton GetSingleton()
{
return _singleton;
}
}
public class NewClass
{
public NewClass()
{
}
public void Method()
{
}
}
public class OtherClass
{
public string Name {get; set;}
public OtherClass()
{
}
}
You can access this intance doing
Singleton.GetSingleton();
Let leave you an other exemple https://dotnetfiddle.net/C1PB05

I only want one instance of each
Move your declarations to their own Class and implement the Singleton Pattern. Since you are dealing with Forms, you can instantiate them on demand, and set them back to null when they are closed by subscribing to their FormClosed event.
Example usage:
MyForms.menu.Show();
Code:
class MyForms
{
private static Menu _menu = null;
public static Menu menu {
get {
if (_menu == null || _menu.IsDisposed)
{
_menu = new Menu();
_menu.FormClosed += (sender, e) => { _menu = null; };
}
return _menu;
}
}
private static RandomFacts _randomFacts = null;
public static Menu randomFacts
{
get
{
if (_randomFacts == null || _randomFacts.IsDisposed)
{
_randomFacts = new RandomFacts();
_randomFacts.FormClosed += (sender, e) => { _randomFacts = null; };
}
return _menu;
}
}
private static QuizMenu _qm = null;
public static QuizMenu qm
{
get
{
if (_qm == null || _qm.IsDisposed)
{
_qm = new QuizMenu();
_qm.FormClosed += (sender, e) => { _qm = null; };
}
return _qm;
}
}
private static AskHowManyQuestions _ahmq = null;
public static AskHowManyQuestions ahmq
{
get
{
if (_ahmq == null || _ahmq.IsDisposed)
{
_ahmq = new AskHowManyQuestions();
_ahmq.FormClosed += (sender, e) => { _ahmq = null; };
}
return _ahmq;
}
}
}

Just assign them to properties on your forms
// in the main form load method
// Class which holds all of the state shared by these forms
sharedState = new SharedState();
menu = new Menu() { SharedState = sharedState };
randomFacts = new RandomFacts() { SharedState = sharedState };
ahmq = new AskHowManyQuestions() { SharedState = sharedState };
qm = new QuizMenu() { SharedState = sharedState };
Obviously, your forms need to declare a SharedState property:
public SharedState SharedState { get; set; }

Related

C# Static property in non-static class as indicator of main object of this class

I have class Important and some objects of this class created. I want allow user to choose main object of this class. Have a look at code below:
public class Program
{
public static void Main(string[] args)
{
Important imp1 = new Important("Important 1");
Important imp2 = new Important("Important 2");
Important imp3 = new Important("Important 3");
imp2.SetMostImportant();
Console.Write(Important.MostImportant.Name);
}
public class Important
{
public Important(string name)
{
Name = name;
if(MostImportant == null)
SetMostImportant();
}
public string Name { get; private set; }
public static Important MostImportant { get; private set; }
public void SetMostImportant()
{
MostImportant = this;
}
}
}
Is it good solution? If not, please tell me why not.
Before, to achieve this kind of things I just created boolean field named e.g. IsMainObject and, when I wanted to change main object, I iterated through all objects (or group of object) of specific class except element that I want to be main, and changed boolean to false, in my new candidate I simply set flag to true. Example below:
public class Program
{
public static void Main(string[] args)
{
Important imp1 = new Important("Important 1");
Important imp2 = new Important("Important 2");
Important imp3 = new Important("Important 3");
List<Important> list = new List<Important> { imp1, imp2, imp3 };
foreach(var item in list.Where(x => x.Name != "Important 2"))
{
item.SetMostImportant(false);
}
imp2.SetMostImportant(true);
Console.Write(list.FirstOrDefault(x => x.MostImportant == true).Name);
}
public class Important
{
public Important(string name)
{
Name = name;
}
public string Name { get; private set; }
public bool MostImportant { get; private set; }
public void SetMostImportant(bool val)
{
MostImportant = val;
}
}
}
I don't like this solution because:
I don't know if MostImportant is true for more than one objects without iterating.
I need to write extra-code to handle much more cases.
I don't have possibility to always iterate through all instances of specific class (groups not always are enough).
... and much more, but you got the idea.
public static Important MostImportant { get; private set; }
is a fine solution, and much better than
public bool MostImportant { get; private set; }
It's not uncommon to have a static property of the type that it's inside of when implementing "singleton" classes. I've written code that resembles this:
class MyClass
{
public static MyClass Instance { get; private set; }
public MyClass()
{
if (Instance == null)
{
Instance = this;
}
else
{
throw new Exception("MyClass already instantiated.");
}
}
}

Sharing Object between Views & ViewModels in MVVM

I'm new to WPF + MVVM and have been having trouble getting around viewmodels.
I have a object called FSystem which contains a alot of lists which are populated from a XML.
public class FSystem : ObservableObject
{
public List<FUser> _userList;
public List<FZone> _zoneList;
public List<FSource> _sourceList;
public string _projectName { get; set; }
private string _projectVersion { get; set; }
private string _processorIp { get; set; }
private bool _isMultiLingualModeOn { get; set; }
private int _systemIncludeLighting { get; set; }
private int _systemIncludeWindowsTreatments { get; set; }
private int _systemIncludeSip { get; set; }
private int _systemIncludeCamaras { get; set; }
public FSystem()
{
UserList = new List<FUser>();
}
}
This is the XMLParser which is called when the user loads the XML to the application.
public static class XMLParsers
{
public static FSystem ParseByXDocument(string xmlPath)
{
var fSystem = new FSystem();
XDocument doc = XDocument.Load(xmlPath);
XElement fSystemElement = doc.Element("FSystem");
if (fSystemElement != null)
{
fSystem.ProjectName = fSystemElement.Element("ProjectName").Value;
fSystem.ProjectVersion = fSystemElement.Element("ProjectVersion").Value;
fSystem.ProcessorIp = fSystemElement.Element("ProcessorIP").Value;
fSystem.ProcessorFilePath = fSystemElement.Element("ProcessorFilePath").Value;
fSystem.SystemIncludeLighting = Convert.ToInt16(fSystemElement.Element("SystemIncludeLighting").Value);
fSystem.SystemIncludeSip = Convert.ToInt16(fSystemElement.Element("SystemIncludeLighting").Value);
fSystem.SystemIncludeCamaras = Convert.ToInt16(fSystemElement.Element("SystemIncludeCameras").Value);
}
fSystem.UserList = (from user in doc.Descendants("FUser")
select new FUser()
{
Id = user.Element("Id").Value,
Name = user.Element("Name").Value,
Icon = user.Element("IconColour").Value,
Pin = user.Element("UserPin").Value,
IsPinEnabled = Convert.ToBoolean(Convert.ToInt16(user.Element("UserPinEnabled").Value)),
ListIndex = user.Element("ListIndex").Value
}).ToList();
return fSystem;
}
}
And this is the MainViewModel below is what contains the Commands which Load the XML and the property FSystem I wish to use in other view models.
public class MainViewModel : ViewModel
{
private Fystem fSystem;
public FSystem FSystem
{
get { return fSystem; }
private set
{
fSystem = value;
NotifyPropertyChanged("FSystem");
}
}
public MainViewModel()
{
InitiateState();
WireCommands();
}
private void InitiateState()
{
FSystem = new FSystem();
}
private void WireCommands()
{
XDocumentLoadCommand = new RelayCommand(XDocumentLoad) {IsEnabled = true};
ClearDataCommand = new RelayCommand(ClearData) {IsEnabled = true};
}
public RelayCommand XDocumentLoadCommand { get; private set; }
private void XDocumentLoad()
{
var openDlg = new OpenFileDialog
{
Title = "Open .FAS",
DefaultExt = ".fas",
Filter = "F System Files (*.fas)|*.fas",
Multiselect = false
};
bool? result = openDlg.ShowDialog() == DialogResult.OK;
if (result != true) return;
FSystem = XMLParsers.ParseByXDocument(openDlg.FileName);
}
The application basically lets the user change the different objects (FUser,FZone,FSource, ect). The idea I had was the user would load the XML then be able to edit the different list objects on different views.
What would the correct way be to go about this in MVVM?
I plan to (hopefully) get the User, Zone and Source views to display Datagrids which are populated with their respective data from the Model.
Create you specific view models, and use dependency injection to pass the relevant data into them (this list or that list).
This way, the view models don't need to know about other stuff, and you can easily mock it for testing and for dummy data to see on the designer.
Copy paste into Linqpad for the simplest example. Both mock viewmodels take a dependency (i in our case). You can just pass your lists:
void Main()
{
int someInt = 5;
int anotherInt = 7;
VM vm1 = new VM(someInt);
VM vm2 = new VM(anotherInt);
vm1.RevealI();
vm2.RevealI();
}
public class VM{
private int _i;
public VM(int i)
{
_i = i;
}
public void RevealI() { Console.WriteLine("value of i is: " + _i); }
}
Othen than that, here's more items:
MSDN
Code Project
stack overflow

Updating another ViewModel when button clicked

I'm trying to update another ViewModel when a button is clicked. That Viewmodel already has a button that updates its own ViewModel but I want the exact same functionallity on another viewModel
Here is my code:
OlyckorViewModel (The view that I want to update and that already has a button that updates it) SearchActiveInvestigationsCommand is the button binding that updates it
public class OlyckorViewModel : NotificationObject
{
private readonly ISosServiceDelegate _sosService;
private readonly IDialogService _dialogService;
private string _searchConditionDiarienummer;
private string _searchConditionFartygsnamn;
private string _searchConditionRegisterbeteckning;
private int? _searchConditionIMONummer;
private DateTime? _searchConditionHaendelseDatum;
private string _searchConditionOlyckshaendelsetypKod;
private bool _isSearching;
private bool _isSearchExpanded = true;
private ObservableCollection<SosListOlycka> _olyckor;
private SosListOlycka _selectedOlycka;
private string _statusText;
public OlyckorViewModel(ISosServiceDelegate sosService, ILoggerFacade logger, IDialogService dialogServce)
{
logger.Log("Initializing OlyckorViewModel", Category.Debug, Priority.Low);
_sosService = sosService;
_dialogService = dialogServce;
SearchCommand = new DelegateCommand(ExecuteSearch, CanExecuteSearch);
SearchActiveInvestigationsCommand = new DelegateCommand(ExecuteSearchActiveInvestigations, CanExecuteSearchActiveInvestigations);
OpenCommand = new DelegateCommand(ExecuteOpen, CanExecuteOpen);
DeleteCommand = new DelegateCommand(ExecuteDelete, CanExecuteDelete);
CreatePdfReportCommand = new DelegateCommand(ExecuteCreatePdfReport, CanExecuteCreatePdfReport);
}
private void ExecuteSearch()
{
if (IsSearching)
return;
IsSearching = true;
StatusText = "Söker olyckor...";
var criteria = new SosOlyckaSearchCriteria();
criteria.Diarienummer = SearchConditionDiarienummer;
criteria.Fartygsnamn = SearchConditionFartygsnamn;
criteria.Registerbeteckning = SearchConditionRegisterbeteckning;
criteria.IMONummer = SearchConditionIMONummer;
criteria.HaendelseDatum = SearchConditionHaendelseDatum;
criteria.OlyckshaendelseTypKod = SearchConditionOlyckshaendelsetypKod;
_sosService.SearchOlyckor(
criteria,
olyckor =>
{
HandleResultFromSearch(olyckor);
},
exception =>
{
IsSearching = false;
StatusText = "Misslyckades att söka olyckor";
DialogHelper.ShowException(exception);
}
);
}
private void HandleResultFromSearch(SosSearchResult<SosListOlycka> olyckor)
{
IsSearching = false;
IsSearchExpanded = false;
Olyckor = new ObservableCollection<SosListOlycka>(olyckor.Items);
StatusText = Olyckor.Count + " " + (Olyckor.Count == 1 ? "olycka." : "olyckor.");
if (olyckor.IsResultTruncated)
{
var statusTextResultTruncated = "Resultatet var för stort (" + olyckor.OriginalNumberOfHits + " olyckor) och trunkerades på servern.";
StatusText += " " + statusTextResultTruncated;
}
// if search result only contains a single item, it should be opened
if (Olyckor.Count == 1)
DialogHelper.OpenOlyckaDialog(Olyckor[0].OlyckaId);
}
OlyckaViewModel (The viewModel that is supposed to have a save button to update the viewmodel above) SaveCommand is the button binding that I want to update like the button above
public class OlyckaViewModel : DialogWindowViewModel
{
private readonly ISosServiceDelegate _sosService;
private readonly Repository _repository;
private readonly IDialogService _dialogService;
private readonly IInteractionService _interactionService;
private readonly FroCodesViewModel _froCodesViewModel;
private SosOlycka _model;
private SosOlycksorsak _selectedOlycksorsak;
private SosOlycksorsak _selectedHuvudorsak;
private SosStegIOlycksfoerlopp _selectedStegIOlycksfoerlopp;
private SosStegIOlycksfoerlopp _selectedInledandeSteg;
private SosOlycka _selectedOtherOlycka;
private OlyckorViewModel _olyckorlist;
private readonly ObservableCollection<CheckBoxListItemViewModel<TrsFartygsunderkategori>> _fartygsunderkategorier = new ObservableCollection<CheckBoxListItemViewModel<TrsFartygsunderkategori>>();
private int? _olycksrapportIdToHaemtmarkeraWhenSaving;
private ObservableCollection<SosListOlycka> _olyckor;
private SosListOlycka _selectedOlycka;
private bool _isSearching;
private bool _isSearchExpanded = true;
private readonly List<KnownValue> _oestEllerVaest = new List<KnownValue>()
{
new KnownValue("Välj", null),
new KnownValue("E", "E"),
new KnownValue("W", "W")
};
private readonly List<KnownValue> _nordEllerSyd = new List<KnownValue>()
{
new KnownValue("Välj", null),
new KnownValue("N", "N"),
new KnownValue("S", "S")
};
public OlyckaViewModel(ISosServiceDelegate sosService, Repository repository, IDialogService dialogService, IInteractionService interactionService)
{
_sosService = sosService;
_repository = repository;
_dialogService = dialogService;
_interactionService = interactionService;
_froCodesViewModel = new FroCodesViewModel(ServiceLocator.Current.GetInstance<ISitsServiceDelegate>());
SaveCommand = new DelegateCommand(ExecuteSave);
ReloadCommand = new DelegateCommand(ExecuteReload, CanExecuteIfExistingOlycka);
CloseCommand = new DelegateCommand(Close);
DeleteCommand = new DelegateCommand(ExecuteDelete, CanExecuteIfExistingOlycka);
AvslutaUtredningCommand = new DelegateCommand(ExecuteAvslutaUtredning, CanExecuteIfExistingOlycka);
CreatePdfReportCommand = new DelegateCommand(ExecuteCreatePdfReport, CanExecuteIfExistingOlycka);
AddOlycksorsakCommand = new DelegateCommand(ExecuteAddOlycksorsak);
RemoveOlycksorsakCommand = new DelegateCommand(ExecuteRemoveOlycksorsak, CanExecuteRemoveOlycksorsak);
AddStegIOlycksfoerloppCommand = new DelegateCommand(ExecuteAddStegIOlycksfoerlopp);
RemoveStegIOlycksfoerloppCommand = new DelegateCommand(ExecuteRemoveStegIOlycksfoerlopp, CanExecuteRemoveStegIOlycksfoerlopp);
FetchFartygsinformationFromSitsCommand = new DelegateCommand(ExecuteFetchFartygsinformationFromSits);
NewOlyckaFromHaendelseCommand = new DelegateCommand(ExecuteNewOlyckaFromHaendelse);
OpenOtherOlyckaCommand = new DelegateCommand(ExecuteOpenOtherOlycka, CanExecuteOpenOtherOlycka);
MoveOlyckaToNewHaendelseCommand = new DelegateCommand(ExecuteMoveOlyckaToNewHaendelse);
MoveOlyckaToOtherHaendelseCommand = new DelegateCommand(ExecuteMoveOlyckaToOtherHaendelse);
MarkSelectedOlycksorsakAsHuvudorsakCommand = new DelegateCommand(ExecuteMarkSelectedOlycksorsakAsHuvudorsak);
MarkSelectedStegIOlycksfoerloppAsInledandeStegCommand = new DelegateCommand(MarkSelectedStegIOlycksfoerloppAsInledandeSteg);
SearchActiveInvestigationsCommand = new DelegateCommand(ExecuteSearchActiveInvestigations, CanExecuteSearchActiveInvestigations);
}
public DelegateCommand SaveCommand { get; private set; }
public DelegateCommand ReloadCommand { get; private set; }
public DelegateCommand CloseCommand { get; private set; }
public DelegateCommand DeleteCommand { get; private set; }
public DelegateCommand AvslutaUtredningCommand { get; private set; }
public DelegateCommand CreatePdfReportCommand { get; private set; }
public DelegateCommand AddOlycksorsakCommand { get; private set; }
public DelegateCommand RemoveOlycksorsakCommand { get; private set; }
public DelegateCommand AddStegIOlycksfoerloppCommand { get; private set; }
public DelegateCommand RemoveStegIOlycksfoerloppCommand { get; private set; }
public DelegateCommand FetchFartygsinformationFromSitsCommand { get; private set; }
public DelegateCommand NewOlyckaFromHaendelseCommand { get; private set; }
public DelegateCommand OpenOtherOlyckaCommand { get; private set; }
public DelegateCommand MoveOlyckaToNewHaendelseCommand { get; private set; }
public DelegateCommand MoveOlyckaToOtherHaendelseCommand { get; private set; }
public DelegateCommand MarkSelectedOlycksorsakAsHuvudorsakCommand { get; private set; }
public DelegateCommand MarkSelectedStegIOlycksfoerloppAsInledandeStegCommand { get; private set; }
public DelegateCommand SearchActiveInvestigationsCommand { get; private set; }
public DelegateCommand SearchCommand { get; private set; }
public FroCodesViewModel FroCodesViewModel { get { return _froCodesViewModel; } }
public OlyckorViewModel OlyckorViewModel { get { return _olyckorlist; } }
public SosOlycka Model
{
get { return _model; }
private set
{
if (value != _model)
{
_model = value;
RaisePropertyChanged(() => Model);
RaisePropertyChanged(() => IsExistingOlycka);
RaiseCanExecuteChangedForOlyckaCommands();
LoadDescriptionsForFroCodes();
SynchronizeFromModel();
}
}
}
private void ExecuteSave()
{
if (IsBusy)
throw new InvalidOperationException("Cannot save olycka, is already busy");
SynchronizeToModel();
// Validate ad-acta
List<string> missingAdActaFields = null;
if (Model.MyndighetensUtredningAvslutad.HasValue)
{
missingAdActaFields = DataHelper.ValidateAdActa(Model);
}
// Validate skrovskada
List<string> missingSkrovskadaFields = null;
if (Model.SosFartygsskada.Skrovskada == "J")
{
missingSkrovskadaFields = DataHelper.ValidateSkrovskada(Model);
}
if ((missingAdActaFields != null && missingAdActaFields.Count > 0)
|| (missingSkrovskadaFields != null && missingSkrovskadaFields.Count > 0))
{
// Bring up window of missing fields (or update if already open)
var vm = _dialogService.GetOpenDialogs().OfType<MissingFieldsViewModel>().FirstOrDefault();
if (vm != null)
{
vm.AdActaFields = missingAdActaFields;
vm.SkrovskadaFields = missingSkrovskadaFields;
_dialogService.Activate(vm);
}
else
{
vm = ServiceLocator.Current.GetInstance<MissingFieldsViewModel>();
vm.AdActaFields = missingAdActaFields;
vm.SkrovskadaFields = missingSkrovskadaFields;
_dialogService.Show(vm);
}
//
// Cancel save operation
return;
}
else
{
// Close window with missing fields if open)
var vm = _dialogService.GetOpenDialogs().OfType<MissingFieldsViewModel>().FirstOrDefault();
if (vm != null)
{
vm.Close();
}
}
SetBusy("Sparar ändringar...");
_sosService.SaveOlycka(
Model,
result =>
{
// load olycka using the id returned from save method (useful if olycka was new / not previously persisted)
ResetBusy();
if (IsGoingToHaemtmarkeraWhenSaving)
{
SetBusy("Markerar olycksrapport som hämtad...");
var rosService = ServiceLocator.Current.GetInstance<IRosServiceDelegate>();
rosService.HaemtmarkeraOlycksrapport(
OlycksrapportIdToHaemtmarkeraWhenSaving.Value,
result,
() =>
{
ResetBusy();
OlycksrapportIdToHaemtmarkeraWhenSaving = null;
LoadOlycka(result);
},
haemtmarkeraException =>
{
ResetBusy();
DialogHelper.ShowException(haemtmarkeraException);
}
);
}
else
{
LoadOlycka(result);
}
},
exception =>
{
ResetBusy();
DialogHelper.ShowException(exception);
}
);
ExecuteSearchActiveInvestigations();
}
I know it's alot of code, I just wanted to make sure not to miss anything.
I tried to copy the same code from the already working button to the button I want to work the same but it didn't work and I suspect it's because I didn't tell it to update another view and not itself. I could be wrong tho.
I appreciate any help,
Raise an event from OlyckaViewModel with the required parameters and subscribe in OlyckorViewModel.
Make the code common in the SearchActiveInvestigationsCommand and call the same function from the subscribed event method.
I'm trying to update another ViewModel when a button is clicked.
In the another viewmodel centralize the update code into a public method.
In the App code, make a static reference to the VM in question.
Make the another viewmodel place a reference to itself onto the app as a static reference.
Centralize the update code into a public method on that VM. The method may have multiple variables which have to be pass through to do any update from any foreign VMs or button clicks from views.
On the button click, get the global app from (see Application.Current Property (System.Windows)) and find the reference to the VM in question. Then call the update method.

Invoke a delegate on the main thread in a tiered architecture

I have a background process that i want to regularly maintain the state of gps location. I am not clear on how to invoke a delegate on the main thread in the ui layer when the threaded method is in another class. Here is sample code. My form launches the thread on load:
public partial class MainScreen : Form
{
.
. // form stuff
.
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
Thread t = new Thread(gpsStatusManager.UpdateLocation);
t.IsBackground = true;
t.Start();
}
delegate void GpsDataParameterDelegate(GpsStatus value);
public void UpdateGpsStatus(GpsStatus value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new GpsDataParameterDelegate(UpdateGpsStatus), new object[] { value });
return;
}
// Must be on the UI thread if we've got this far
gpsStatus.SetGpsStatus(value);
}
}
I have a domain object class for the gps information:
public class GpsStatus
{
public void SetGpsStatus(GpsStatus gpsStatus)
{
Latitude = gpsStatus.Latitude;
Longitude = gpsStatus.Longitude;
CurrentDateTime = gpsStatus.CurrentDateTime;
NumberOfSatellites = gpsStatus.NumberOfSatellites;
TotalNumberSatellites = gpsStatus.TotalNumberSatellites;
}
public float Latitude { get; private set; }
public float Longitude { get; private set; }
public DateTime CurrentDateTime { get; private set; }
public int NumberOfSatellites { get; private set; }
public int TotalNumberSatellites { get; private set; }
}
Then, my manager class where i update status in the secondary thread:
public class GpsStatusManager
{
private GpsStatus _gpsStatus;
public void UpdateLocationx()
{
while (UpdateGpsData())
{
Thread.Sleep(2000);
}
}
private bool UpdateGpsData()
{
SError error;
SGpsPosition gpsPosition;
try
{
if (CApplicationAPI.GetActualGpsPosition(out error, out gpsPosition, true, 0) != 1)
return false;
}
catch (Exception)
{
return false;
}
var numberOfSatellites = gpsPosition.Satellites;
var totalSatellites = gpsPosition.satellitesInfo;
var datetime = gpsPosition.Time;
var lat = gpsPosition.Latitude;
var lon = gpsPosition.Longitude;
_gpsStatus.SetGpsStatus(lat, lon, datetime, numberOfSatellites, totalSatellites);
//How do I invoke the delegate to send the _gpsStatus data to my main thread?
return true;
}
}
Thanks for any assistance.
Here's one way to do it, just off the top of my head:
public class GpsStatusEventArgs : EventArgs
{
public GpsStatus Status { get; private set; }
public GpsStatusEventArgs(GpsStatus status)
{
Status = status;
}
}
public class GpsStatusManager
{
...
public event EventHandler<GpsStatusEventArgs> GpsStatusUpdated;
private void OnGpsStatusUpdated(GpsStatus gpsStatus)
{
EventHandler<GpsStatusEventArgs> temp = GpsStatusUpdated;
if (temp != null)
temp.Invoke(this, new GpsStatusEventArgs(gpsStatus));
}
}
public partial class MainScreen : Form
{
...
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
gpsStatusManager.GpsStatusUpdated += new EventHandler<GpsStatusEventArgs>(GpsStatusManager_GpsStatusUpdated);
...
}
private void GpsStatusManager_GpsStatusUpdated(object sender, GpsStatusEventArgs e)
{
UpdateGpsStatus(e.Status);
}
...
}
Then add this to the bottom of UpdateGpsData:
OnGpsStatusUpdated(_gpsStatus);
You should use the SynchronizationContext class.
In the UI thread (in any class), set a field (perhaps static) to SynchronizationContext.Current.
You can then call Send or Post on the saved instance to execute code on the UI thread.
Here is another approach using the ISynchronizeInvoke interface. This is the same pattern the System.Timers.Timer class uses to raise the Elapsed event.
public class GpsStatusManager
{
public ISynchronizeInvoke SynchronizingObject { get; set; }
public event EventHandler Update;
public void UpdateGpsData()
{
// Code omitted for brevity.
OnUpdate(_gpsStatus);
return true;
}
private OnUpdate(GpsStatus status)
{
if (SynchronizingObject != null && SynchronizingObject.IsInvokeRequired)
{
ThreadStart ts = () => { OnUpdate(status); };
SynchronizingObject.Invoke(ts, null);
}
else
{
if (Update != null)
{
Update(this, status);
}
}
}
public class UpdateEventArgs : EventArgs
{
public GpsStatus Status { get; set; }
}
}

Help with Singleton - Setting Auto Properties?

I'm trying to set my Auto Properties but they are non-static and so I get the error "Cannot access non-static property in static context" when trying to set the properties Credentials, Certificate, and UrlEndPoint.
public class PayPalProfile
{
#region Fields
static PayPalProfile _instance;
#endregion
#region Constructors
PayPalProfile()
{
// is only called if a new instance is created
SetProfileState();
}
#endregion
#region Properties
public static PayPalProfile CurrentProfile
{
get
{
if (_instance == null)
_instance = new PayPalProfile();
return _instance;
}
}
public CustomSecurityHeaderType Credentials { get; private set; }
public X509Certificate2 Certificate { get; private set; }
public string UrlEndPoint { get; private set;}
#endregion
#region Methods
private static void SetProfileState()
{
// Set the profile state
SetApiCredentials();
SetPayPalX509Certificate();
}
private static void SetApiCredentials()
{
Credentials = new CustomSecurityHeaderType
{
Credentials =
{
Username = PayPalConfig.CurrentConfiguration.ApiUserName,
Password = PayPalConfig.CurrentConfiguration.ApiPassword
}
};
UrlEndPoint = PayPalConfig.CurrentConfiguration.ExpressCheckoutSoapApiEndPoint;
}
private static void SetPayPalX509Certificate()
{
PayPalCerfiticate paypalCertificate = new PayPalCerfiticate();
Certificate = paypalCertificate.PayPalX509Certificate;
}
#endregion
}
There is no need for SetProfileState, SetApiCredentials and SetPayPalX509Certificate to be static.
SetApiCredentials and SetPayPalX509Certificate are setting values for non static properties and so an instance is required. By removing the static modifiers from the above mentioned methods the properties will be set on the instance being constructed when SetProfileState is called.
This means that you have a static method where you are trying to assign instance properties. As there is no instance available in static methods/properties, the error is given.
The example:
public class Test {
public int InstanceProperty { get; set; }
public static void StaticMethod() {
InstanceProperty = 55; // ERROR HERE
}
}
Instead bothe should either be in static or instance context:
public class Test {
public static int StaticProperty { get; set; }
public static void StaticMethod() {
StaticProperty = 55; // Ok
}
}
public class Test {
public int InstanceProperty { get; set; }
public void InstanceMethod() {
InstanceProperty = 55; // Ok
}
}

Categories