I am new to c# and object coding so please be gentle....
I have a class call LED, see below:
public sealed class LED
{
public GpioPinValue ReqPinValue { get; set; } //Enable/Disable LED
public bool Flashing { get; set; } //Does the LED flash
public GpioPin Pin { get; set; }
public int flashingPeriod { get; set; } //Period to flash in seconds
private GpioPinValue value; //Pin value (high/low)
private int flashCount = 0; //Times we have entered the timer loop
public LED()
{
}
public void UpdateLED()
{
int timesToCycle = 0;
if (ReqPinValue == GpioPinValue.Low)
{
if (Flashing)
{
timesToCycle = flashingPeriod * 2;
if (flashCount == timesToCycle)
{
value = (value == GpioPinValue.High) ? GpioPinValue.Low : GpioPinValue.High;
Pin.Write(value);
flashCount = 0;
}
else
flashCount++;
}
else
{
Pin.Write(GpioPinValue.Low);
}
}
else
{
Pin.Write(GpioPinValue.High);
}
}
}
In another class I create four instances of this LED class for 4 different Status LED'S.
public sealed class StatusLED
{
private const int RUN_LED = 4;
private const int IO_LED = 17;
private const int NET_LED = 27;
private const int FAULT_LED = 22;
public LED RunLed = new LED();
public LED IOLed = new LED();
public LED NetLed = new LED();
public LED FaultLed = new LED();
private GPIO GPIO = new GPIO();
private GpioController gpioController;
private ThreadPoolTimer timer;
public void InitStatusLED()
{
gpioController = GPIO.InitGPIO();
if (gpioController == null)
{
Debug.WriteLine("Failed to find GPIO Controller!");
//TODO proper error handling although this should never happen
}
else
{
//Setup the default parameters for the LEDS (ie flashing or non-flashing)
RunLed.Flashing = false;
IOLed.Flashing = false;
NetLed.Flashing = false;
FaultLed.Flashing = false;
RunLed.flashingPeriod = 0;
IOLed.flashingPeriod = 0;
NetLed.flashingPeriod = 0;
FaultLed.flashingPeriod = 0;
RunLed.Pin = GPIO.InitOutputPin(gpioController, RUN_LED);
IOLed.Pin = GPIO.InitOutputPin(gpioController, IO_LED);
NetLed.Pin = GPIO.InitOutputPin(gpioController, NET_LED);
FaultLed.Pin = GPIO.InitOutputPin(gpioController, FAULT_LED);
//Turn the LED's on to Start
RunLed.ReqPinValue = GpioPinValue.Low;
IOLed.ReqPinValue = GpioPinValue.Low;
NetLed.ReqPinValue = GpioPinValue.Low;
FaultLed.ReqPinValue = GpioPinValue.Low;
timer = ThreadPoolTimer.CreatePeriodicTimer(Timer_Tick, TimeSpan.FromMilliseconds(500));
}
}
private void Timer_Tick(ThreadPoolTimer timer)
{
RunLed.UpdateLED();
IOLed.UpdateLED();
NetLed.UpdateLED();
FaultLed.UpdateLED();
}
}
I now want to set the field "ReqPinValue" for these instances in the StatusLED class from another class using the code below
private StatusLED statusLED = new StatusLED();
statusLED.RunLed.ReqPinValue = GpioPinValue.Low;
I get the following error:
Error: Type '....' contains externally visible field '....' Fields
can be exposed only by structures.
I can see it doesn't like the line below being public, how can I can access a parameter of this instance from another class without making it public?
public LED RunLed = new LED();
You can make these properties rather than fields:
public LED RunLed {get;set;}
public LED IOLed {get;set;}
public LED NetLed {get;set;}
public LED FaultLed {get;set;}
Then, in your InitStatusLED method, initialize them:
public void InitStatusLED()
{
gpioController = GPIO.InitGPIO();
if (gpioController == null)
{
Debug.WriteLine("Failed to find GPIO Controller!");
//TODO proper error handling although this should never happen
}
else
{
//Setup the default parameters for the LEDS (ie flashing or non-flashing)
RunLed = new LED(GPIO.InitOutputPin(gpioController, RUN_LED));
IOLed = new LED(GPIO.InitOutputPin(gpioController,IO_LED));
//And so on
But wait - your LED class doesn't have a constructor that accepts a GpioPin. Let's fix that too:
public sealed class LED
{
public GpioPinValue ReqPinValue { get; set; } //Enable/Disable LED
public bool Flashing { get; set; } //Does the LED flash
public GpioPin Pin { get; set; }
public int flashingPeriod { get; set; } //Period to flash in seconds
private GpioPinValue value; //Pin value (high/low)
private int flashCount = 0; //Times we have entered the timer loop
public LED(GpioPin pin)
{
Pin = pin;
Flashing = false;
flashingPeriod = 0;
ReqPinValue = GpioPinValue.Low;
}
And see how we've eliminated a whole load of repetitive code from you InitStatusLed method too.
Having done all of this, go back and look at your properties again. For those which should only be set by the class itself, and not by any other code using the class, make the setters private:
public GpioPin Pin { get; private set; }
Related
Basically i have one class with subclass(or nested class, inner class whatever it gets called)
I have no idea why i cant access (or list doesnt include nested class i guess)
nested class.
public static List<Tag> Tags = new List<Tag>();
//cureently selected tag,also random percentage related data
public class Tag
{
public string name = null;
public int dupe = 0;
public int Tagindex = 0;
public int URLindex = 0;
public class Type
{
public bool isArtist = false;
public bool isGroup = false;
public bool isTag = false;
public bool isURL = false;
}
public class Score
{
// 0~10, sort them out!
public bool isRated = false; //make true if user modifies score
public int Story = 0;
public int Reality = 0;
public int Drawing = 0;
public int memetic = 0;
public string msg = null;
}
dataGridView1.Rows.Add(gVar.Tags[i].Tagindex,gVar.Tags[i].name/*valid*/, gVar.Tags[i].Type.isArtist/*invalid*/);
//also invalid
Tag t1 = new Tag();
t1.Type.isArtist = true;
gVar.Tags.Add(t1);
The nested class is just a declaration of the class, same as if that class was not nested.
You have to instantiate an object of that type in order to access one of its properties.
For example:
public class Tag
{
public string name = null;
public int dupe = 0;
public int Tagindex = 0;
public int URLindex = 0;
public Score Score { get; } = new Score() // declare a property of the nested type, and instantiate an object
public class Type
{
public bool isArtist = false;
public bool isGroup = false;
public bool isTag = false;
public bool isURL = false;
}
public class Score
{
// 0~10, sort them out!
public bool isRated = false; //make true if user modifies score
public int Story = 0;
public int Reality = 0;
public int Drawing = 0;
public int memetic = 0;
public string msg = null;
}
And the usage:
Tag t1 = new Tag();
t1.Score.Story = 3;
By the way, it's not recommended to use public fields, use properties instead (such as the Score property in the code above).
I have a large test set (5k+) using xUnit.net, and I'm having concurrency problems among tests running in parallel.
xUnit randomizes the execution order of tests, which makes it harder for me to detect the issue.
I'd like to know whether is there a way to log, during test execution, the moment a test starts and the moment it ends.
Note: Using constructor and disposer methods does not cut it, because you cannot know which test is being run on the constructor/disposer.
Note 2: In case it is not obvious, I'm looking for a solution that doesn't involve writing log call in each test.
Thanks,
Well, I managed to do it using the BeforeAfterTestAttribute from xUnit. Then I wrote the utility logger below to output the results to a .csv file.
public class LogTestExecutionAttribute: BeforeAfterTestAttribute
{
public override void Before(MethodInfo methodUnderTest)
{
TestExecutionDataLogger.LogBegin(methodUnderTest);
}
public override void After(MethodInfo methodUnderTest)
{
TestExecutionDataLogger.LogEnd(methodUnderTest);
}
}
public static class TestExecutionDataLogger
{
private static readonly string LogFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "DbCoud", $"UnitTests_{DateTime.UtcNow:yyyy_MM_dd_HH_mm}_D_{AppDomain.CurrentDomain.Id}.csv");
private static int _startedOrder = 0;
private static int _endedOrder = 0;
private static readonly ConcurrentDictionary<string, testExecutionData> testDataDict = new ConcurrentDictionary<string, testExecutionData>();
private static readonly ConcurrentQueue<string> logQueue = new ConcurrentQueue<string>();
public static void LogBegin(MethodInfo testInfo)
{
var name = $"{testInfo.DeclaringType.FullName}.{testInfo.Name}";
var order = Interlocked.Add(ref _startedOrder, 1);
var startedUtc = DateTime.UtcNow;
var data = testDataDict.GetOrAdd(name, new testExecutionData());
data.StartedUtc = startedUtc;
data.StartedOrder = order;
data.TestName = name;
data.Status = "Started";
data.StartThreadId = Thread.CurrentThread.ManagedThreadId;
writeLog(data);
}
public static void LogEnd(MethodInfo testInfo)
{
var name = $"{testInfo.DeclaringType.FullName}.{testInfo.Name}";
var dataEndedUtc = DateTime.UtcNow;
var order = Interlocked.Add(ref _endedOrder, 1);
var data = testDataDict[name];
data.EndedUtc = dataEndedUtc;
data.EndedOrder = order;
data.Status = "Ended";
data.EndThreadId = Thread.CurrentThread.ManagedThreadId;
writeLog(data);
}
private static void writeLog(testExecutionData data)
{
logQueue.Enqueue(data.ToCsvLine());
if (data.EndedOrder == 1)
{
Directory.CreateDirectory(Path.GetDirectoryName(LogFileName));
Task.Run(logWriter);
}
}
private static Task logWriter()
{
while (true)
{
var logs = new List<string>();
string result;
while (logQueue.TryDequeue(out result))
{
logs.Add(result);
}
if (logs.Any())
{
File.AppendAllLines(LogFileName, logs);
}
}
}
private class testExecutionData
{
public int StartedOrder { get; set; }
public int EndedOrder { get; set; }
public DateTime StartedUtc { get; set; }
public DateTime EndedUtc { get; set; }
public string TestName { get; set; }
public string Status { get; set; }
public int StartThreadId { get; set; }
public int EndThreadId { get; set; }
public string ToCsvLine() { return $"{TestName};{Status};{StartedOrder};{EndedOrder};{StartedUtc:o};{EndedUtc:o};{Math.Max(0, ( EndedUtc - StartedUtc ).TotalMilliseconds)};{StartThreadId};{EndThreadId}"; }
}
}
To use this code, add the LogTestExecutionAttribute to the test classes you want to log (or to the base classes ;p).
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
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.
I have 2 classes that hold some info about the user. One holds the data, the other one holds the controls info. Now i need to pass both of them as a parameters to a method. However they are connected to one another and i dont think that passing the 2 classes separately as parameters is okay. I wonder if i should put them in a Tuple or something that keeps them together so i can pass them as just 1 parameter to any method. Here's how they look :
The data class :
public class UsersProperties
{
public enum CUser
{
Player,
Bot1,
Bot2,
Bot3,
Bot4,
Bot5
}
public int RightCard { get; set; }
public string Name { get; set; }
public int? Chips { get; set; }
public int Type { get; set; }
public bool Turn { get; set; }
public bool FoldTurn { get; set; }
public int PreviousCall { get; set; }
public int LeftCard { get; set; }
public double Power { get; set; }
public int EnumCasted { get; set; }
}
The controls class :
public class UserControls
{
public Point CardsLocation { get; set; }
public AnchorStyles CardsAnchor { get; set; }
public Panel Panel { get; } = new Panel();
public Point PanelLocation { get; set; }
public Size PanelSize { get; } = new Size((Settings.Width + 10) * 2, Settings.Height + 20);
public int IndentationPanelXy { get; } = 10;
public Label UsernameLabel { get; set; } = new Label();
public Point UsernameLabelLocation { get; set; }
public Size UsernameLabelSize { get; } = new Size(Settings.Width * 2, 20);
public TextBox ChipsTextBox { get; set; } = new TextBox();
public Label StatusLabel { get; set; } = new Label();
public UserControls(AnchorStyles style, Point cardsLocation, bool down)
{
CardsAnchor = style;
CardsLocation = cardsLocation;
UsernameLabelLocation = down ? new Point(CardsLocation.X, CardsLocation.Y - 20) : new Point(CardsLocation.X, CardsLocation.Y + Settings.Height);
PanelLocation = new Point(CardsLocation.X - IndentationPanelXy, CardsLocation.Y - IndentationPanelXy);
}
}
Now here's how i initialize them :
private static Player Player = new Player(Properties.Settings.Default.StartingChips);
private UserControls PlayerControls = new UserControls(AnchorStyles.Bottom, new Point(560, 470),false);
And here's the method where i need to pass both of them :
private void SetPlayers(UsersProperties user, UserControls userControls, int turn, ref bool check, Image refreshbackImage)
{
if (user.Chips <= 0) return;
_foldedPlayers--;
if (turn < user.RightCard || turn > user.LeftCard) return;
if (Holder[user.RightCard].Tag != null)
{
Holder[user.LeftCard].Tag = _reserve[user.LeftCard];
}
Holder[user.RightCard].Tag = _reserve[user.RightCard];
if (!check)
{
_horizontal = userControls.CardsLocation.X;
_vertical = userControls.CardsLocation.Y;
}
check = true;
Holder[turn].Anchor = userControls.CardsAnchor;
Holder[turn].Image = refreshbackImage;
if (turn < Bot1.RightCard)
{
Holder[turn].Image = Deck[_i];
}
Holder[turn].Location = new Point(_horizontal, _vertical);
_horizontal += Holder[turn].Width;
Holder[turn].Visible = true;
Controls.Add(userControls.Panel);
userControls.Panel.Location = userControls.PanelLocation;
userControls.Panel.BackColor = Color.DarkBlue;
userControls.Panel.Size = userControls.PanelSize;
userControls.Panel.Visible = false;
if (_i != user.LeftCard) return;
check = false;
}
I want to know if there's any better way to pass 2 classes as parameters i think they should stick together anyway.
You can write a wrapper class (ie:UserContainer) which has two properties namely, usercontrol and userproperty.
Then initialize it and pass this class as parameter.
I think you could use Generics, as in here:
namespace PropertiesControls
{
public class PropsControls
{
public static void PropesAndControls<TP, TC>(TP property, TC control) where TP : UserProperties where TC: UserControls
{
//your code here
}
}
}
A generic defines a behaviour that can be applied to a class. It is used in collections, where the same approach to handling an object can be applied regardless of the type of object. I.e, a list of strings or a list of integers can be handled using the same logic without having to differentiate between both specific types.