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.
Related
I am studying the mvvm pattern and ran into a problem, I need to make sure that the button is inactive when the user entered his data incorrectly
I have dialog window (loginPage) where i vote Login and Password
public class LoginViewModel : ViewModel
{
ApplicationDbContext db;
IEnumerable<User> users;
IAuthorizationService _authorizationService;
IHashingManager _hashingManager;
private bool? _closeWindow;
private RelayCommand _loginUser;
private RelayCommand _cancelCommand;
public bool EnableClose { get; set; }
public LoginViewModel(IViewFactory viewFactory, ICore core) : base(viewFactory)
{
_authorizationService = core.AuthorizationService;
_hashingManager = core.HashingManager;
db = new ApplicationDbContext();
}
public ICommand Command { get; set; }
private string login;
public string Login
{
get => login;
set
{
login = value;
RaisePropertyChanged(nameof(Login));
}
}
private string password;
public string Password
{
get => password;
set
{
password = value;
RaisePropertyChanged(nameof(Password));
}
}
public RelayCommand CancelCommand
{
get
{
return _cancelCommand ??
(_cancelCommand = new RelayCommand(() =>
{
var result = _authorizationService.Login(Login, _hashingManager.Encrypt(Password));
CloseWindow = true;
}));
}
}
public bool? CloseWindow
{
get { return _closeWindow; }
set
{
_closeWindow = value;
RaisePropertyChanged(nameof(CloseWindow));
}
}
public RelayCommand LoginUser
{
get
{
return _loginUser ??
(_loginUser = new RelayCommand(() =>
{
var result = _authorizationService.Login(Login, _hashingManager.Encrypt(Password));
CloseWindow = true;
}));
}
}
public IEnumerable<User> Users
{
get { return users; }
set
{
users = value;
RaisePropertyChanged("Users");
}
}
}
My MainWindow VM
public class MainViewModel : ViewModel
{
private readonly ICore _core;
public ICommand LoginCommand { get; }
public ObservableCollection<ILayoutElementViewModel> Documents { get; private set; }
public MainViewModel(IViewFactory viewFactory, ICore core) : base(viewFactory)
{
_core = core;
this.Documents = new ObservableCollection<ILayoutElementViewModel>();
}
ServiceResult _serviceResult = new ServiceResult();
private RelayCommand openChartView;
public RelayCommand OpenChartView
{
get
{
return openChartView ??
(openChartView = new RelayCommand(()=>
{
if (_serviceResult.IsSucceed)
{
var chartView = new ChartSelectionViewModel(_viewFactory);
_viewFactory.ShowDialogView(chartView);
}
}));
}
}
private string _myProperty;
public string MyProperty
{
get => _myProperty;
set
{
_myProperty = value;
RaisePropertyChanged(() => MyProperty);
}
}
protected override void LoadedExecute()
{
base.LoadedExecute();
_viewFactory.ShowDialogView(new LoginViewModel(_viewFactory, _core));
}
}
When i wrote corectly or not, my dialog window close and main window becomes active.
There is a button , and i want disable this button when the login and password was incorrect.
I think i must use my ServiceResult in MW
public class ServiceResult
{
public bool IsSucceed { get; set; }
public string Error { get; set; }
public ServiceResult()
{
IsSucceed = true;
}
public ServiceResult(string error)
{
IsSucceed = false;
Error = error;
}
}
or
AuthorizationService
public class AuthorizationService : IAuthorizationService
{
public ServiceResult Login(string login,string password)
{
ApplicationDbContext db = new ApplicationDbContext();
var listUsers = db.Users.ToList();
foreach (var item in listUsers)
{
if (item.Login == login && item.Password == password)
{
return new ServiceResult();
}
}
return new ServiceResult("Wrong Login or Password!");
}
}
How can i do that? Thx u.
I done, it was so easy
protected override void LoadedExecute()
{
base.LoadedExecute();
var vm = new LoginViewModel(_viewFactory, _core);
_viewFactory.ShowDialogView(vm);
IsAuth = vm.AuthorizationResult;
}
private RelayCommand openChartView;
public RelayCommand OpenChartView
{
get
{
return openChartView ??
(openChartView = new RelayCommand(()=>
{
if (IsAuth)
{
var chartView = new ChartSelectionViewModel(_viewFactory);
_viewFactory.ShowDialogView(chartView);
}
}));
}
}
You can do a bool binding to the IsEnable property of the button.
code:
public bool Enabled
{
get => _enabled; set
{
_enabled = value;
NotifypropertyChanged("Enabled");
}
}
xaml:
<Button IsEnabled="{Binding Enabled}"></Button>
I'm writing a wpf application, where I have music albums and corresponding songs. I can add albums and corresponding songs. But now I want to to refresh the view when a change to the database is made. I found many possible solutions, but as I'm new to wpf and c# I don't know which one would suite my code.
In my MainView have an album list and a add button which opens another window where I can add data with a textbox.
AlbumListViewModel
#region Constants
IWindowManager addAlbum = new WindowManager();
IWindowManager addSong = new WindowManager();
private AlbumViewModel _selectedAlbum;
private SongViewModel _selectedSong;
#endregion
#region Constructor
public AlbumListViewModel()
{
Albums = new ObservableCollection<AlbumViewModel>(GetAlbumList());
AddAlbumCommand = new RelayCommand(x => AddAlbum());
AddSongCommand = new RelayCommand(x => AddSong());
}
#endregion
#region Properties
public ICommand AddAlbumCommand { get; private set; }
public ICommand AddSongCommand { get; private set; }
public ObservableCollection<AlbumViewModel> Albums { get; set; }
public AlbumViewModel SelectedAlbum
{
get
{
return _selectedAlbum;
}
set
{
if (_selectedAlbum != value)
{
_selectedAlbum = value;
}
NotifyPropertyChanged("SelectedAlbum");
}
}
public SongViewModel SelectedSong
{
get
{
return _selectedSong;
}
set
{
if (_selectedSong != value)
{
_selectedSong = value;
}
NotifyPropertyChanged("SelectedSong");
}
}
#endregion
#region Methods
public List<AlbumViewModel> GetAlbumList()
{
var controller = new BandManagerController();
return controller.GetAlbumList()
.Select(a => new AlbumViewModel(a))
.ToList();
}
private void AddAlbum()
{
addAlbum.ShowDialog(new AlbumViewModel(new AlbumData()));
}
private void AddSong()
{
addSong.ShowDialog(new SongViewModel(new SongData { AlbumID = SelectedAlbum.AlbumID }));
}
It opens the AlbumView where I add albums to the database.
public class AlbumViewModel : Screen
{
#region Constants
private AlbumData _data;
#endregion
#region Constructor
public AlbumViewModel(AlbumData data)
{
_data = data;
SongListVM = new SongListViewModel(data.AlbumID);
SaveAlbumToDatabase = new RelayCommand(x => AlbumToDatabase(data));
}
#endregion
#region Properties
public SongListViewModel SongListVM { get; set; }
public ICommand SaveAlbumToDatabase { get; private set; }
public string AlbumName
{
get
{
return _data.AlbumName;
}
set
{
if (_data.AlbumName != value)
{
_data.AlbumName = value;
NotifyOfPropertyChange("AlbumName");
}
}
}
public int AlbumID
{
get
{
return _data.AlbumID;
}
set
{
if (_data.AlbumID != value)
{
_data.AlbumID = value;
NotifyOfPropertyChange("AlbumID");
}
}
}
public string AlbumYear
{
get
{
return _data.AlbumYear;
}
set
{
if (_data.AlbumYear != value)
{
_data.AlbumYear = value;
NotifyOfPropertyChange("AlbumYear");
}
}
}
#endregion
#region Methods
public AlbumData AddAlbumEntry(AlbumData albumData)
{
var controller = new BandManagerController();
return controller.AddAlbumEntry(albumData);
}
public void ExecuteCancelCommand()
{
(GetView() as Window).Close();
}
public void AlbumToDatabase(AlbumData data)
{
AddAlbumEntry(data);
ExecuteCancelCommand();
}
#endregion
}
The AddAlbumEntry Method in the ALbumView is in a different class which is the connections to my database. I already use an ObservableCollection but don't know how to tell it the Database was updated.
Thanks in advance!
Just want to answer my question. I just changed my AddAlbum method to use a Deactivated event, to reload the Collection after the Dialog closes like:
private void AddAlbum()
{
var vm = new AlbumViewModel(new AlbumData());
vm.Deactivated += (s, e) => GetAlbumList();
addAlbum.ShowDialog(vm);
}
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; }
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
Excuse my ignorance on this subject, but I'm not schooled in asynchronous programming. However, I believe my code is close to achieving what I need it to do.
Basically the code below only works for the very first
C61 = new BridgeViewModel("C61");
await C61.Initialize();
statements. None of the other items are returning any data to the bound .xaml and I have no idea why. Does each one need to be in its own Initialize function?
Any help is greatly appreciated.
Code:
namespace SentinelApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new MainViewModel();
DataContext = vm;
vm.Initialize();
}
}
public class MainViewModel
{
public readonly string[] Bridges = { "C61", "C62", "C63", "C68", "C69", "K71", "K72", "K73", "K74", "T91", "GN01", "GE01", "GA01" };
public async Task Initialize()
{
C61 = new BridgeViewModel("C61");
await C61.Initialize();
C62 = new BridgeViewModel("C62");
await C62.Initialize();
C63 = new BridgeViewModel("C63");
await C63.Initialize();
C68 = new BridgeViewModel("C68");
await C68.Initialize();
C69 = new BridgeViewModel("C69");
await C69.Initialize();
K71 = new BridgeViewModel("K71");
await K71.Initialize();
K72 = new BridgeViewModel("K72");
await K72.Initialize();
K73 = new BridgeViewModel("K73");
await K73.Initialize();
K74 = new BridgeViewModel("K74");
await K74.Initialize();
T91 = new BridgeViewModel("T91");
await T91.Initialize();
GA01 = new BridgeViewModel("GA01");
await GA01.Initialize();
GE01 = new BridgeViewModel("GE01");
await GE01.Initialize();
GN01 = new BridgeViewModel("GN01");
await GN01.Initialize();
}
public BridgeViewModel C61 { get; set; }
public BridgeViewModel C62 { get; set; }
public BridgeViewModel C63 { get; set; }
public BridgeViewModel C68 { get; set; }
public BridgeViewModel C69 { get; set; }
public BridgeViewModel K71 { get; set; }
public BridgeViewModel K72 { get; set; }
public BridgeViewModel K73 { get; set; }
public BridgeViewModel K74 { get; set; }
public BridgeViewModel T91 { get; set; }
public BridgeViewModel GA01 { get; set; }
public BridgeViewModel GE01 { get; set; }
public BridgeViewModel GN01 { get; set; }
}
public class BridgeViewModel : ViewModel
{
private readonly ClientWrapper _client;
private readonly string _bridge;
private readonly Timer _timer = new Timer();
public BridgeViewModel(string bridge)
{
_client = new ClientWrapper();
_bridge = bridge;
}
public async Task Initialize()
{
await _client.Connect(_bridge);
await _client.SendMessage(new SessionStart("3", "25").CreateBridgeMessage());
_timer.Interval = 1000;
_timer.Elapsed += Update;
_timer.Start();
}
private async void Update(object sender, ElapsedEventArgs e)
{
try {
var response = await _client.SendMessage("BS~RESERVE~STATS~REQ~" + _bridge + "~0");
var split = response.Split('~');
Timestamp = split[4].Substring(0, 2) + ":" + split[4].Substring(2, 2) + ":" + split[4].Substring(4, 2);
FreePorts = split[6];
LongestHold = TimeSpan.FromSeconds(int.Parse(split[15])).ToString("hh:mm");
Bells = split[12];
Signals = split[8];
} catch { }
}
private string _timestamp;
public string Timestamp
{
get { return _timestamp; }
set { _timestamp = value; RaisePropertyChanged(); }
}
private string _bells;
public string Bells
{
get { return _bells; }
set { _bells = value; RaisePropertyChanged(); }
}
private string _signals;
public string Signals
{
get { return _signals; }
set { _signals = value; RaisePropertyChanged(); }
}
private string _freeports;
public string FreePorts
{
get { return _freeports; }
set { _freeports = value; RaisePropertyChanged(); }
}
private string _longesthold;
public string LongestHold
{
get { return _longesthold; }
set { _longesthold = value; RaisePropertyChanged(); }
}
}
}
Instead of using your async method inside a constructor, register and use it inside the FrameworkElement.Loaded event where you can await:
public MainWindow()
{
InitializeComponent();
Loaded += InitializeOnLoaded;
}
public async void InitializeOnLoaded(object sender, RoutedEventArgs e)
{
var vm = new MainViewModel();
DataContext = vm;
await vm.InitializeAsync();
}