Like the title says, I try to notify a property change, the method RaisePropertyChanged is called coorectly, but PropertyChanged is always null.
Here the shortened class:
public class BluetoothManager : INotifyPropertyChanged {
private string selectedBluetoothResult;
private List<string> foundDevices = new List<string>(5);
public List<DeviceInformation> penDevices = new List<DeviceInformation>();
private GattCharacteristic TxCharacteristic;
public string SelectedBluetoothResult {
get {
return selectedBluetoothResult;
}
set {
selectedBluetoothResult = value;
RaisePropertyChanged();
}
}
public List<string> FoundDevices {
get
{
return foundDevices;
}
set
{
foundDevices = value;
RaisePropertyChanged();
}
}
public BluetoothManager() {
StartScanWatcher();
}
public void StartScanWatcher() {
Debug.WriteLine("Starting device watcher...");
String query = "";
//query for Bluetooth LE devices
query += "System.Devices.DevObjectType:=5 AND System.Devices.Aep.ProtocolId:=\"{BB7BB05E-5972-42B5-94FC-76EAA7084D49}\"";
//query for devices with controllers' name
query += " AND (System.ItemNameDisplay:=\"" + DeviceName + "\" )";
var deviceWatcher = DeviceInformation.CreateWatcher(query); //, requestedProperties, DeviceInformationKind.AssociationEndpoint);
deviceWatcher.Added += DeviceWatcher_OnAdded;
deviceWatcher.EnumerationCompleted += DeviceWatcher_OnEnumComplete;
deviceWatcher.Removed += DeviceWatcher_Removed;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
deviceWatcher.Updated += DeviceWatcher_Updated;
deviceWatcher.Start();
Debug.WriteLine(" StartScanWatcher end");
}
private void DeviceWatcher_OnAdded(DeviceWatcher sender, DeviceInformation deviceInfo) {
Debug.WriteLine(" DeviceWatcher_OnAdded Start");
lock (foundDevices) {
if (foundDevices.Contains(deviceInfo.Id)) {
return;
}
foundDevices.Add(deviceInfo.Id);
RaisePropertyChanged("FoundDevices");
}
Debug.WriteLine($"[{deviceInfo.Name}] DeviceWatcher_OnAdded...");
if (SelectedBluetoothResult == null)
{
SelectedBluetoothResult = deviceInfo.Id;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
Debug.WriteLine("<<<<<<<<<<<<< BluetoothManager, PropertyChanging: " + propertyName);
if (PropertyChanged == null) {
Debug.WriteLine("============ BluetoothManager, PropertyChanged == null, " + propertyName);
return;
}
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
Debug.WriteLine(">>>>>>>>>>>>> BluetoothManager, PropertyChanged: " + propertyName);
}
}
}
And here the Binding in the XAML file:
<ListView ItemsSource="{Binding BluetoothManager.FoundDevices}" SelectedItem="{Binding BluetoothManager.SelectedBluetoothResult}">
<ListView.Resources>
<DataTemplate x:Key="BluetoothDeviceTemplate">
<TextBlock Text="{Binding Path=Sap}"/>
</DataTemplate>
</ListView.Resources>
</ListView>
The binding seems to work properly.
Please note, that the class in which the PropertyChanged is always null is not the DataContext auf the XAML file. Does that mean I have to work differently with the PropertyChange notification?
Thanks in advance.
EDIT:
The complete MainWindowViewModel:
public class MainWindowViewModel : INotifyPropertyChanged {
private ObservableCollection<BookGame> _booksToDisplay = new ObservableCollection<BookGame>();
private ObservableCollection<BookGame> _games = new ObservableCollection<BookGame>();
private string _url;
private int[] _newBooksMID;
private int[] _oldBooksMID;
private Dictionary<int, int> _newBooksVersionNumbers;
private Dictionary<int, int> _oldBooksVersionNumbers;
private Dictionary<int, int> _allVersionNumbers;
private List<BookGame> _booksToAdd;
private long _downloadSpeed;
private bool _isDownloading = true;
private bool _toggleLastSearchKeyWasReturn = false;
string _volumeLabel = "";
FileInfo[] _filesTxt = { };
FileInfo[] _filesAll = { };
private string _folderPath = "";
private string _driveName = null;
List<BookGame> _allGames;
List<BookGame> _allBooks;
List<MP3> _allMP3;
long lengthAllBooks = 0;
long lengthAllGames = 0;
int _percentDownloaded = 100;
private long _amountBytesToDownload;
private long _amountBytesDownloaded;
private long _amountMBytesToDownload;
private long _amountMBytesDownloaded;
private int _downloadTime;
//private bool _isDownloadAborted;
ServerCommi serverComm;
public BluetoothManager BluetoothManager { get; set; }
public MainWindowViewModel() {
DownloadTime = 0;
AmountBytesToDownload = 0;
AmountBytesDownloaded = 0;
DriveInfo drive = null;
foreach (DriveInfo driveInfo in DriveInfo.GetDrives()) {
if (driveInfo.IsReady && driveInfo.VolumeLabel == _volumeLabel) {
drive = driveInfo;
_driveName = drive.Name;
_folderPath = _driveName + _folderPath;
}
}
DirectoryInfo di = new DirectoryInfo(_folderPath);
if (di.Exists)
{
_filesTxt = di.GetFiles("*.txt");
FilesAll = di.GetFiles("*.*");
foreach (FileInfo file in _filesTxt)
{
try
{
Convert.ToInt32(file.Name.Split('_')[0]);
AddBookGameToList(file);
}
catch (Exception e)
{
}
}
}
SearchResults = new ObservableCollection<ResultItem>();
MenuCommand = new RelayCommand(o => {
Debug.WriteLine("Menu Command " + o);
SwitchBooks(o);
});
SearchReturnKeyCommand = new RelayCommand(o => {
Debug.WriteLine("00000000000000000000000000000000 SearchReturnKeyCommand " + o);
SearchActivated();
});
BrowserCommand = new RelayCommand(o => {
Debug.WriteLine("Browser Command main" + o);
CallBrowser("");
});
DeleteCommand = new RelayCommand(o => {
Debug.WriteLine("Delete Command main" + o);
});
ToggleDownloadsCommand = new RelayCommand(o => {
Debug.WriteLine(" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ");
Debug.WriteLine(" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ");
Debug.WriteLine("ToggleDownloadsCommand Command main" + o);
ToggleDownloads();
});
_viewModelMusic = new ViewModelMusic(_driveName);
AllGames = Games.ToList<BookGame>();
AllBooks = BooksToDisplay.ToList<BookGame>();
AllMP3 = _viewModelMusic.Mp3s.ToList<MP3>();
long lengthAllMP3 = 0;
foreach (MP3 mp3 in AllMP3) {
lengthAllMP3 += mp3.LengthValue;
}
_viewModelBooks = new ViewModelBooks(BooksToDisplay);
_viewModelGames = new ViewModelGames(Games);
_viewModelFiles = new ViewModelFiles(FilesAll);
_viewModelLumi = new ViewModelLumi(drive, lengthAllBooks, lengthAllGames, lengthAllMP3);
_viewModelOverview = new ViewModelOverview(AllBooks, AllGames, AllMP3);
_screens[0] = _viewModelOverview;
_screens[1] = _viewModelBooks;
_screens[2] = _viewModelGames;
_screens[3] = _viewModelMusic;
_screens[4] = _viewModelFiles;
_screens[5] = _viewModelVideos;
_screens[6] = _viewModelAdults;
_screens[7] = _viewModelLumi;
SearchText = "";
SelectedItem = _viewModelBooks;
Debug.WriteLine("CALLING ServerCommi! Ring, ring!");
serverComm = new ServerCommi(this);
//serverComm.DownloadBooksAsync();
BluetoothManager = new BluetoothManager();
}
private void ToggleDownloads() {
IsDownloading = !IsDownloading;
serverComm.ToggleDownloads(IsDownloading);
_viewModelBooks.ToggleDownloads(IsDownloading);
}
internal void DownloadStateChange(int mid, int newState) {
_viewModelBooks.DownloadStateChange(mid, newState);
}
// params bool[] isDownload : varargs
// returns the mid
public int AddBookGameToList(FileInfo file, bool isDownload = false) {
BookGame bg = new BookGame(file);
if (isDownload) {
bg.DownloadState = 2;
if (bg.Mid == serverComm.DownloadingMID) {
bg.DownloadState = 1;
}
}
if (bg.Group.StartsWith("B")) {
bg.Group = "Bücher";
}
switch (bg.Group) {
case "Bücher":
if (isDownload) {
BooksToDisplay.Insert(0, bg);
} else {
BooksToDisplay.Add(bg);
}
lengthAllBooks += bg.LengthValue;
break;
case "Spiele":
Games.Add(bg);
lengthAllGames += bg.LengthValue;
break;
default:
Debug.WriteLine("Default: " + bg.Title);
break;
}
return bg.Mid;
}
private void CallBrowser(string url) {
Debug.WriteLine("Url: " + Url);
try {
System.Diagnostics.Process.Start(Url);
} catch (System.ComponentModel.Win32Exception noBrowser) {
if (noBrowser.ErrorCode == -2147467259)
MessageBox.Show(noBrowser.Message);
} catch (System.Exception other) {
MessageBox.Show(other.Message);
}
}
string _searchText;
public string SearchText {
get {
return _searchText;
}
set {
Debug.WriteLine("SearchText Value= " + value);
if (!_toggleLastSearchKeyWasReturn) {
_searchText = value;
SearchResults.Clear();
List<ResultItem> _allBooksRI = new List<ResultItem>();
List<ResultItem> _allBooksHelperList = _allBooks.ToList<ResultItem>();
List<ResultItem> _allGamesHelperList = _allGames.ToList<ResultItem>();
List<ResultItem> _allMP3HelperList = _allMP3.ToList<ResultItem>();
if (SelectedItem != null && SelectedItem.Equals(_viewModelGames)) {
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
Debug.WriteLine("===================================== Games - " + SearchResults);
Debug.WriteLine("SelectedItem - " + SelectedItem);
} else if (SelectedItem != null && SelectedItem.Equals(_viewModelMusic)) {
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
Debug.WriteLine("====================================== Music " + SearchResults);
Debug.WriteLine("SelectedItem - " + SelectedItem);
} else {
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
Debug.WriteLine("====================================== Books " + SearchResults);
}
if (SearchResults.Count == 0) {
SearchResults.Add(new ErrorResultItem("Error", "Nichts passendes gefunden."));
}
} else {
_toggleLastSearchKeyWasReturn = false;
}
}
}
private ObservableCollection<ResultItem> AddAllResultItemsIf(ObservableCollection<ResultItem> searchResults, List<ResultItem> toAdd, string searchText) {
foreach (ResultItem item in toAdd) {
if (item.Title.ToLower().Contains(_searchText.ToLower())) {
searchResults.Add(item);
}
}
return searchResults;
}
public ObservableCollection<ResultItem> SearchResults {
get; set;
}
ResultItem _selectedResult;
public ResultItem SelectedResult {
get {
return _selectedResult;
}
set {
_selectedResult = value;
SearchItemSelected(value);
}
}
private void SearchItemSelected(ResultItem value) {
switch (value.Group) {
case "Bücher":
SelectedItem = _viewModelBooks;
break;
case "Spiele":
SelectedItem = _viewModelGames;
break;
case "Musik":
SelectedItem = _viewModelMusic;
break;
default:
Debug.WriteLine("Search Item Selected, jumped to default: " + value);
break;
}
Unmark(Marked);
Mark(value);
}
ResultItem _marked;
internal void Mark(ResultItem value) {
Marked = value;
value.Marked = true;
}
internal void Unmark(ResultItem value) {
Marked = null;
if (value != null) {
value.Marked = false;
}
}
public ResultItem Marked {
get => _marked;
set => _marked = value;
}
private bool _isSearchResult;
public bool IsSearchResult {
get {
return _isSearchResult;
}
set {
_isSearchResult = value;
Debug.WriteLine("IsSearchResult= " + value);
RaisePropertyChanged();
}
}
private void SearchActivated() {
_toggleLastSearchKeyWasReturn = true;
SelectedItem = _viewModelOverview;
IsSearchResult = true;
}
private object _selectedItem;
public object SelectedItem {
get {
return _selectedItem;
}
set {
_selectedItem = value;
Debug.WriteLine("SELECTED_ITEM SETTER: " + value);
Unmark(Marked);
IsSearchResult = false;
if (SearchText != null) {
SearchText = SearchText;
}
RaisePropertyChanged();
}
}
ViewModelOverview _viewModelOverview;
ViewModelBooks _viewModelBooks;
ViewModelGames _viewModelGames;
ViewModelMusic _viewModelMusic;
ViewModelFiles _viewModelFiles;
ViewModelVideos _viewModelVideos = new ViewModelVideos();
ViewModelAdults _viewModelAdults = new ViewModelAdults();
ViewModelLumi _viewModelLumi;
object[] _screens = new object[8];
public object[] Screens {
get {
return _screens;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = null) {
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public ICommand MenuCommand {
get; set;
}
public ICommand SearchReturnKeyCommand {
get; set;
}
public ICommand BrowserCommand {
get; set;
}
public ICommand ToggleDownloadsCommand {
get; set;
}
public RelayCommand DeleteCommand {
get;
private set;
}
public List<BookGame> AllGames {
get => _allGames;
set => _allGames = value;
}
public List<BookGame> AllBooks {
get => _allBooks;
set => _allBooks = value;
}
public List<MP3> AllMP3 {
get => _allMP3;
set => _allMP3 = value;
}
public ViewModelBooks ViewModelBooks {
get => _viewModelBooks;
set => _viewModelBooks = value;
}
public ObservableCollection<BookGame> BooksToDisplay {
get => _booksToDisplay;
set => _booksToDisplay = value;
}
public ObservableCollection<BookGame> Games {
get => _games;
set => _games = value;
}
public string Url {
get {
return _url;
}
set {
_url = value;
RaisePropertyChanged();
}
}
public int[] NewBooksMID {
get => _newBooksMID;
set => _newBooksMID = value;
}
public int[] OldBooksMID {
get => _oldBooksMID;
set => _oldBooksMID = value;
}
public Dictionary<int, int> NewBooksVersionNumbers {
get => _newBooksVersionNumbers;
set => _newBooksVersionNumbers = value;
}
public Dictionary<int, int> OldBooksVersionNumbers {
get => _oldBooksVersionNumbers;
set => _oldBooksVersionNumbers = value;
}
public Dictionary<int, int> AllVersionNumbers {
get => _allVersionNumbers;
set => _allVersionNumbers = value;
}
public int[] OldBooksMID1 {
get => _oldBooksMID;
set => _oldBooksMID = value;
}
public List<BookGame> BooksToAdd {
get => _booksToAdd;
set => _booksToAdd = value;
}
public FileInfo[] FilesAll {
get => _filesAll;
set => _filesAll = value;
}
public string FolderPath {
get => _folderPath;
set => _folderPath = value;
}
public int PercentDownloaded {
get {
return _percentDownloaded;
}
set {
_percentDownloaded = value;
RaisePropertyChanged();
}
}
public long DownloadSpeed {
get {
return _downloadSpeed;
}
set {
_downloadSpeed = value;
RaisePropertyChanged();
}
}
public long AmountBytesToDownload {
get {
return _amountBytesToDownload;
}
set {
_amountBytesToDownload = value;
Debug.WriteLine("Property Changed: " + "AmountBytesToDownload");
AmountMBytesToDownload = value / 1024 / 1024;
}
}
public long AmountBytesDownloaded {
get {
return _amountBytesDownloaded;
}
set {
_amountBytesDownloaded = value;
AmountMBytesDownloaded = value / 1024 / 1024;
}
}
public int DownloadTime {
get {
return _downloadTime;
}
set {
_downloadTime = value;
RaisePropertyChanged();
}
}
/*
public bool IsDownloadAborted {
get {
return _isDownloadAborted;
}
set {
_isDownloadAborted = value;
RaisePropertyChanged();
}
}
*/
public long AmountMBytesDownloaded {
get {
return _amountMBytesDownloaded;
}
set {
_amountMBytesDownloaded = value;
RaisePropertyChanged();
}
}
public long AmountMBytesToDownload {
get {
return _amountMBytesToDownload;
}
set {
_amountMBytesToDownload = value;
RaisePropertyChanged();
}
}
public bool IsDownloading {
get {
return _isDownloading;
}
set {
_isDownloading = value;
RaisePropertyChanged();
}
}
internal void SwitchBooks(object o) {
Debug.WriteLine("SwitchBooksEx " + o);
if (o.ToString().Equals("Tessloff.ViewModelBooks")) {
((ViewModelBooks)_screens[0]).SwitchView();
Debug.WriteLine("SwitchBooksIn " + o);
}
}
}
public class CommandViewModel {
private MainWindowViewModel _viewmodel;
public CommandViewModel(MainWindowViewModel viewmodel) {
_viewmodel = viewmodel;
Debug.WriteLine("LALALALALA");
MenuCommand = new RelayCommand(o => {
Debug.WriteLine("CommandViewModel " + o);
_viewmodel.SwitchBooks(o);
});
DeleteCommand = new RelayCommand(o => {
Debug.WriteLine("Delte Command CVM" + o);
});
}
public ICommand MenuCommand {
get; set;
}
public ICommand DeleteCommand {
get; set;
}
public string Title {
get;
private set;
}
}
public class RelayCommand : ICommand {
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null) {
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute) {
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter) {
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
}
remove {
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter) {
_execute(parameter);
}
#endregion // ICommand Members
}
public class ViewModelAdults {
public ViewModelAdults() {
Title = "Erwachsene";
ImgUrl = "/Resources/Erwachsene.png";
}
public string Title {
get; set;
}
public string ImgUrl {
get;
private set;
}
}
Edit tl;dr:
Why do all "direct" properties of MainWindowViewModel update great (like MainWindowViewModel.IsSearchResult), but the two "indirect" properties don't (MainWindowViewModel.BluetoothManager.SelectedBluetoothResult).
List.add() doesnt trigger PropertyChange. You need to use ObservableCollection or raise PropertyChange yourself after adding item.
Related
I have a simple app that stores different stock data, my add stock button opens a new window with a form and when I press save I add the stock to the database but the datagrid doesn't get updated
I access the static instance of my main Viewmodel from my EntryViewModel via:
Main View Model(StockViewModel)
public class StockViewModel:INotifyPropertyChanged
{
#region Fields
private IList<Stock> _stockList;
private StatsBuilder _statsBuilder = new StatsBuilder();
public Stock stock = new Stock();
public Stock10 stock10 = new Stock10();
public Stock20 stock20 = new Stock20();
private ICommand _searchCommand;
private static StockViewModel _instance = new StockViewModel();
public static StockViewModel Instance { get { return _instance; } }
public IList<Stock> Stocks
{
get { return _stockList; }
set { _stockList = value; OnPropertyChanged(nameof(Stocks)); }
}
#endregion
#region Constructor
public StockViewModel()
{
using (var stocks = new AppDbContext())
{
Stocks = stocks.LowFloatStocks.ToList();
}
}
#endregion
#region Day1's
private string _ticker;
public string Ticker
{
get { return _ticker; }
set
{
_ticker = value;
OnPropertyChanged("Ticker");
}
}
private DateTime _date = DateTime.Now;
public DateTime Date
{
get { return _date; }
set { _date = value; }
}
private decimal _preivousClose;
public decimal PreviousClose
{
get { return _preivousClose; }
set { _preivousClose = value; OnPropertyChanged("PreviousClose"); }
}
private decimal _pmOpeningPrice;
public decimal PM_OpeningPrice
{
get { return _pmOpeningPrice; }
set { _pmOpeningPrice = value; OnPropertyChanged("PM_OpeningPrice"); }
}
private decimal _openingPrice;
public decimal OpeningPrice
{
get { return _openingPrice; }
set { _openingPrice = value; OnPropertyChanged("OpeningPrice"); }
}
private decimal _high;
public decimal High
{
get { return _high ; }
set { _high = value; OnPropertyChanged("High"); }
}
private decimal _low;
public decimal Low
{
get { return _low; }
set { _low = value; OnPropertyChanged("Low"); }
}
private decimal _close;
public decimal Close
{
get { return _close; }
set { _close = value; OnPropertyChanged("Close"); }
}
private string _catalyst;
public string Catalyst
{
get { return _catalyst; }
set { _catalyst = value; OnPropertyChanged("Catalyst"); }
}
private decimal _float;
public decimal Float
{
get { return _float; }
set {_float = value; OnPropertyChanged("Float"); }
}
private string _dilution;
public string Dilution
{
get { return _dilution; }
set { _dilution = value; OnPropertyChanged("Dilution"); }
}
#endregion
#region Day2's
//public decimal Day2Open
//{
// //get { return stock.Day2Open; }
// set { stock.Day2Open = value; OnPropertyChanged("Day2Open"); }
//}
//public decimal Day2High
//{
// get { return stock.Day2High; }
// set { stock.Day2High = value; OnPropertyChanged("Day2High"); }
//}
//public decimal Day2Low
//{
// get { return stock.Day2Low; }
// set { stock.Day2Low = value; OnPropertyChanged("Day2Low"); }
//}
//public decimal Day2Close
//{
// get { return stock.Day2Close; }
// set { stock.Day2Close = value; OnPropertyChanged("Day2Close"); }
//}
#endregion
#region Stats
private Stock _selectedstock;
public Stock SelectedStock
{
private get
{
return _selectedstock;
}
set
{
_selectedstock = value;
OnPropertyChanged("SelectedStock");
GetStats(_selectedstock.Ticker);
}
}
public int Gaps10 { get { return stock10.Gaps10; } set { stock10.Gaps10 = value; OnPropertyChanged("Gaps10"); } }
public decimal AvgGap10 { get {return stock10.AvgGap10; } set { stock10.AvgGap10 = value; OnPropertyChanged("AvgGap10"); } }
public int CloseGreen10 { get { return stock10.CloseGreen10; } set { stock10.CloseGreen10 = value; OnPropertyChanged("CloseGreen10"); } }
public decimal CloseGreenPercent10 { get { return stock10.CloseGreenPercent10; } set { stock10.CloseGreenPercent10 = value; OnPropertyChanged("CloseGreenPercent10"); } }
public int CloseRed10 { get { return stock10.CloseRed10; } set { stock10.CloseRed10 = value; OnPropertyChanged("CloseRed10"); } }
public decimal CloseRedPercent10 { get { return stock10.CloseRedPercent10; } set { stock10.CloseRedPercent10 = value; OnPropertyChanged("CloseRedPercent10"); } }
public decimal AvgSpike10 { get; set; }
public decimal Downside10 { get; set; }
public int PMFade10 { get { return stock10.PMFade10; } set { stock10.PMFade10 = value; OnPropertyChanged("PMFade10"); } }
public decimal PMFadePercent10 { get { return stock10.PMFadePercent10; } set { stock10.PMFadePercent10 = value; OnPropertyChanged("PMFadePercent10"); } }
public int Gaps20 { get {return stock20.Gaps20 ; } set { stock20.Gaps20 = value; OnPropertyChanged("Gaps20"); } }
public decimal AvgGap20 { get { return stock20.AvgGap20; } set { stock20.AvgGap20 = value; OnPropertyChanged("AvgGap20"); } }
public int CloseGreen20 { get { return stock20.CloseGreen20; } set { stock20.CloseGreen20 = value; OnPropertyChanged("CloseGreen20"); } }
public decimal CloseGreenPercent20 { get { return stock20.CloseGreenPercent20; } set { stock20.CloseGreenPercent20 = value; OnPropertyChanged("CloseGreenPercent20"); } }
public int CloseRed20 { get { return stock20.CloseRed20; } set { stock20.CloseRed20 = value; OnPropertyChanged("CloseRed20"); } }
public decimal CloseRedPercent20 { get { return stock20.CloseRedPercent20; } set { stock20.CloseRedPercent20 = value; OnPropertyChanged("CloseRedPercent20"); } }
public decimal AvgSpike20 { get; set; }
public decimal Downside20 { get; set; }
public int PMFade20 { get { return stock20.PMFade20; } set { stock20.PMFade20 = value; OnPropertyChanged("PMFade20"); } }
public decimal PMFadePercent20 { get { return stock20.PMFadePercent20; } set { stock20.PMFadePercent20 = value; OnPropertyChanged("PMFadePercent20"); } }
#endregion
#region PropertyChange
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region Commands
public ICommand SearchCommand => _searchCommand ?? (_searchCommand = new RelayCommand(param => this.SearchStock(param)));
#endregion
#region Actions
private void SearchStock(object _ticker)
{
try
{
var stock = Stocks.First(x => x.Ticker.Trim() == _ticker.ToString());
_selectedstock = (Stock)stock;
GetStats(_ticker.ToString());
}
catch (Exception)
{
MessageBox.Show("No matching Ticker");
}
}
private void GetStats(string ticker)
{
//Stocks with 10% gap ups
stock10 = _statsBuilder.GetStats10(ticker);
stock20 = _statsBuilder.GetStats20(ticker);
Gaps10 = stock10.Gaps10;
AvgGap10 = stock10.AvgGap10;
CloseGreen10 = stock10.CloseGreen10;
CloseGreenPercent10 = stock10.CloseGreenPercent10;
CloseRed10 = stock10.CloseRed10;
CloseRedPercent10 = stock10.CloseRedPercent10;
PMFade10 = stock10.PMFade10;
PMFadePercent10 = stock10.PMFadePercent10;
//Stock with 20% gap ups
Gaps20 = stock20.Gaps20;
AvgGap20 = stock20.AvgGap20;
CloseGreen20 = stock20.CloseGreen20;
CloseGreenPercent20 = stock20.CloseGreenPercent20;
CloseRed20 = stock20.CloseRed20;
CloseRedPercent20 = stock20.CloseRedPercent20;
PMFade20 = stock20.PMFade20;
PMFadePercent20 = stock20.PMFadePercent20;
}
#endregion
}
When I click the add stock button it fires the AddCommand which in turn fires the Addstock method, this adds the stock to the database and updates the list in the StockViewModel instance but it does not update the datagrid OnPropertyChanged for some reason
EntryViewModel:
public ICommand AddCommand => _addCommand ?? (_addCommand = new RelayCommand(param => this.AddStock()));
#endregion
#region PropertyChange
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region Methods
private void AddStock()
{
using (var stocks = new AppDbContext())
{
stock.Id = 0;
stock.Ticker = _ticker;
stock.PreviousClose = _preivousClose;
stock.PM_OpeningPrice = _pmOpeningPrice;
stock.OpeningPrice = _openingPrice;
stock.High = _high;
stock.Low = _low;
stock.Close = _close;
stock.Catalyst = _catalyst;
stock.Float = _float;
stock.Dilution = _dilution;
stocks.LowFloatStocks.Add(stock);
stocks.SaveChanges();
StockViewModel.Instance.Stocks = stocks.LowFloatStocks.ToList();
Clear();
}
}
Data Grid Binding;
<DataGrid Name="StockGrid" Margin="5,5,5,5" Height="250" ItemsSource="{Binding Stocks}" IsReadOnly="True" AutoGeneratingColumn ="StockGrid_AutoGeneratingColumn" Grid.ColumnSpan="3" VerticalScrollBarVisibility="Auto" SelectedItem="{Binding SelectedStock, Mode=TwoWay}">
</DataGrid>
Data Context of StockView Model:
<Window.DataContext> <local1:StockViewModel/> </Window.DataContext>
Any suggestions?
The following sets the DataContext to an new instance of the StockViewModel which is not the same as the instance returned by the Instance property:
<Window.DataContext> <local1:StockViewModel/> </Window.DataContext>
The fact that you can do this means that StockViewModel is not really a singleton. You should add a private constuctor to it to make it a real singleton if this is what you want:
private StockViewModel() { }
You would then set the DataContext to the instance returned by the Instance property:
<Window.DataContext>
<x:Static Member="this:StockViewModel.Instance" />
</Window.DataContext>
I have a MVVM program with a model:
public class Deelnemer
{
public int Id { get; set; }
public string Voornaam { get; set; }
public string Werkplek { get; set; }
public List<string> Aanwezig { get; set; }
public Deelnemer()
{
}
}
In my View I have a listBox in which I want to be able to select multiple values (days to put in the list aanwezig).
<ListBox Name="listDagdelen" SelectionMode="Multiple" ItemsSource="{Binding Dagdelen}" SelectedItem="{Binding SelectedDagdeel, Mode=TwoWay}">
The ViewModel looks as follows:
class DeelnemerViewModel : INotifyPropertyChanged
{
#region Private Variables
private readonly Deelnemer dlnObject;
private readonly ObservableCollection<Deelnemer> deelnemers;
private readonly DeelnemerManager deelnemerManager;
private readonly ICommand addDeelnemerCmd;
private readonly ICommand deleteDeelnemerCmd;
#endregion
public ObservableCollection<string> Dagdelen { get; private set; }
#region constructor
public DeelnemerViewModel()
{
Dagdelen = new ObservableCollection<string>() { "maandagochtend", "maandagmiddag", "dinsdagochtend", "dinsdagmiddag", "woensdagochtend", "woensdagmiddag", "donderdagochtend", "donderdagmiddag", "vrijdagochtend", "vrijdagmiddag" };
dlnObject = new Deelnemer();
deelnemerManager = new DeelnemerManager();
deelnemers = new ObservableCollection<Deelnemer>();
addDeelnemerCmd = new RelayCommand(Add, CanAdd);
deleteDeelnemerCmd = new RelayCommand(Delete, CanDelete);
}
#endregion
#region Properties
private string _selectedDagdeel = null;
public string SelectedDagdeel
{
get { return _selectedDagdeel; }
set
{
_selectedDagdeel = value;
dlnObject.Aanwezig.Add(value);
OnPropertyChanged("SelectedDagdeel");
}
}
public int Id
{
get { return dlnObject.Id; }
set
{
dlnObject.Id = value;
OnPropertyChanged("Id");
}
}
public string Voornaam
{
get { return dlnObject.Voornaam; }
set
{
dlnObject.Voornaam = value;
OnPropertyChanged("Voornaam");
}
}
public string Werkplek
{
get { return dlnObject.Werkplek; }
set
{
dlnObject.Werkplek = value;
OnPropertyChanged("Werkplek");
}
}
public List<string> Aanwezig
{
get { return dlnObject.Aanwezig; }
set
{
dlnObject.Aanwezig = value;
OnPropertyChanged("Aanwezig");
}
}
public ObservableCollection<Deelnemer> Deelnemers { get { return deelnemers; } }
public Deelnemer SelectedDeelnemer
{
set
{
Id = value.Id;
Voornaam = value.Voornaam;
Werkplek = value.Werkplek;
Aanwezig = value.Aanwezig;
}
}
#endregion
#region Commands
public ICommand AddDeelnemerCmd { get { return addDeelnemerCmd; } }
public ICommand DeleteDeelnemerCmd { get { return deleteDeelnemerCmd; } }
#endregion
public bool CanAdd(object obj)
{
//Enable the Button only if the mandatory fields are filled
if (Voornaam != string.Empty && Werkplek != string.Empty)
return true;
return false;
}
public void Add(object obj)
{
var deelnemer = new Deelnemer { Voornaam = Voornaam, Werkplek = Werkplek, Aanwezig = Aanwezig };
if (deelnemerManager.Add(deelnemer))
{
Deelnemers.Add(deelnemer);
//string txt = string.Join(String.Empty,Aanwezig);
//MessageBox.Show(txt);
//ResetDeelnemer();
}
else
MessageBox.Show("Vul correcte waardes in!");
}
#region DeleteCommand
private bool CanDelete(object obj)
{
//Enable the Button only if the patients exist
if (Deelnemers.Count > 0)
return true;
return false;
}
private void Delete(object obj)
{
//Delete patient will be successfull only if the patient with this ID exists.
if (!deelnemerManager.Remove(Id))
MessageBox.Show("Deelnemer met dit id bestaat niet!");
else
{
//Remove the patient from our collection as well.
deelnemers.RemoveAt(GetIndex(Id));
ResetDeelnemer();
MessageBox.Show("Deelnemer succesvol verwijderd !");
}
}
#endregion
#region Private Methods
private void ResetDeelnemer()
{
Id = 0;
Voornaam = string.Empty;
Werkplek = string.Empty;
Aanwezig.Clear();
}
private int GetIndex(int Id)
{
for (int i = 0; i < Deelnemers.Count; i++)
if (Deelnemers[i].Id == Id)
return i;
return -1;
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
I can't figure out how I should use the List with the listbox values. How do I add (multiple) listbox values to the object's List?
The current code throws a nullreferenceexception at
dlnObject.Aanwezig.Add(value);
You must initialize the Aanwezig property of the Deelnemer object before you can add any values to it, either in the contructor of DeelnemerViewModel:
dlnObject = new Deelnemer();
dlnObject.Aanwezig = new List<string();
...or in the constructor of the Deeelnemer class:
public Deelnemer()
{
Aanwezig = new List<string();
}
I've a WPF application that loads a menu from an XML file, each node as a tag that identifies the user function. Each user has visibility permission that match against the tag defined in the xml file. I wish some help on simplifing that code since I's quite complex and from my point of view poor performing. Consider that the main menu is composed of main items and inside each there're specific areas function. If a user is enabled to at element at list the main menu node is shown otherwise not.
public virtual System.Threading.Tasks.Task<MenuItemNode> RegisterMenu(IDictionary<string,Type> functions)
{
var assembly = Assembly.GetCallingAssembly(); //I should get the module that invoked the base class
string filename = GetFullFileName(assembly, MenuFilename);
return Task.Factory.StartNew<MenuItemNode>(() =>
{
string xmlFileName = string.Format(filename);
var doc = new XmlDocument();
using (Stream stream = assembly.GetManifestResourceStream(xmlFileName))
{
if (stream != null)
{
using (var reader = new StreamReader(stream))
{
doc.LoadXml(reader.ReadToEnd());
}
}
}
MenuItemNode menu = BuildMenu(doc.SelectSingleNode(#"/Node"), "/", functions);
return menu;
});
}
private string GetFullFileName(Assembly assembly,string filename)
{
var resourceFiles = assembly.GetManifestResourceNames();
return resourceFiles.First(x => x.EndsWith(filename));
}
private MenuItemNode BuildMenu(XmlNode parent, string path, IDictionary<string, Type> functions)
{
Argument.IsNotNull(() => parent);
if (functions == null || (functions.Count == 0)) return null;
MenuItemNode menuItem = null;
string subPath = "Node";
string name = string.Empty;
string tag = string.Empty;
int position = 0;
bool forceVisible = false;
string parameters = string.Empty;
string group = string.Empty;
bool showInDialog = false;
if (parent.Attributes != null)
{
if (parent.Attributes["name"] != null)
name = parent.Attributes["name"].Value;
if (parent.Attributes["tag"] != null)
tag = parent.Attributes["tag"].Value;
if (parent.Attributes["position"] != null)
position = System.Convert.ToInt32(parent.Attributes["position"].Value);
if (parent.Attributes["force_visible"] != null)
forceVisible = Convert.ToBoolean(parent.Attributes["force_visible"].Value);
if (parent.Attributes["parameters"] != null)
parameters = parent.Attributes["parameters"].Value;
if (parent.Attributes["group"] != null)
group = parent.Attributes["group"].Value;
if (parent.Attributes["showindialog"] != null)
showInDialog = Convert.ToBoolean(parent.Attributes["showindialog"].Value);
}
//parent item
if (string.IsNullOrEmpty(tag))
{
menuItem = CreateMenuItem(name, position);
menuItem.ForceVisible = forceVisible;
// menuItem.Group = group;
}
else//child item
{
if (functions.ContainsKey(tag))
{
menuItem = CreateMenuItem(name, tag, position);
menuItem.ForceVisible = forceVisible;
//menuItem.GroupName = group;
menuItem.ShowInDialog = showInDialog;
//menuItem.MenuParameter = GetMenuItemParameters(parameters);
#region Multiple-tag
if ((functions == null) || !functions.Any()) return null;
#endregion
}
else
{
//todo: add-logging
}
}
if (parent.HasChildNodes)
{
foreach (XmlNode child in parent.SelectNodes(subPath))
{
MenuItemNode childMenuItem = BuildMenu(child, subPath, functions);
if (childMenuItem == null) continue;
int childPosition = childMenuItem.SortIndex;
//This to prevent out-of-boundaries exception
if (childPosition > menuItem.Children.Count)
childPosition = menuItem.Children.Count;
menuItem.Children.Insert(childPosition, childMenuItem);
}
}
return menuItem;
}
private MenuItemNode CreateMenuItem(string text, int position)
{
var item = new MenuItemNode();
item.Text = text;
item.SortIndex = position;
return item;
}
private MenuItemNode CreateMenuItem(string text, string tag, int? position)
{
MenuItemNode item = CreateMenuItem(text, (!position.HasValue) ? 0 : position.Value);
item.FunctionTag = tag;
item.SortIndex = (!position.HasValue) ? 0 : position.Value;
return item;
}
And here's the MenuItemNode class
[ContentProperty("Children")]
public class MenuItemNode : INotifyPropertyChanged
{
private string text;
private ICommand command;
private Uri imageSource;
private int sortIndex;
private bool forceVisible;
private bool showInDialog;
private bool isChecked;
public bool IsChecked
{
get
{
return this.isChecked;
}
set
{
if (this.isChecked != value)
{
this.isChecked = value;
this.RaisePropertyChanged(() => this.IsChecked);
}
}
}
public bool IsSeparator { get; set; }
public MenuItemNode()
{
Children = new MenuItemNodeCollection();
SortIndex = 50;
SetCommand();
}
public MenuItemNode(String path)
: base()
{
Path = path;
}
public MenuItemNodeCollection Children { get; private set; }
public virtual ICommand Command
{
get
{
return command;
}
set
{
if (command != value)
{
command = value;
RaisePropertyChanged(() => this.Command);
}
}
}
public Uri ImageSource
{
get
{
return imageSource;
}
set
{
if (imageSource != value)
{
imageSource = value;
RaisePropertyChanged(() => this.ImageSource);
}
}
}
public string Text
{
get
{
return text;
}
set
{
if (text != value)
{
text = value;
RaisePropertyChanged(() => this.Text);
}
}
}
private MenuGroupDescription group;
public MenuGroupDescription Group
{
get { return group; }
set
{
if (group != value)
{
group = value;
RaisePropertyChanged(() => this.Group);
}
}
}
public int SortIndex
{
get
{
return sortIndex;
}
set
{
if (sortIndex != value)
{
sortIndex = value;
RaisePropertyChanged(() => this.SortIndex);
}
}
}
public string Path
{
get;
private set;
}
public bool ForceVisible
{
get
{
return this.forceVisible;
}
set
{
if (forceVisible != value)
{
this.forceVisible = value;
RaisePropertyChanged(() => ForceVisible);
}
}
}
public bool ShowInDialog
{
get
{
return this.showInDialog;
}
set
{
if (showInDialog = value)
{
this.showInDialog = value;
RaisePropertyChanged(() => ShowInDialog);
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyExpression.Name));
}
#endregion
protected virtual void SetCommand()
{
this.Command = FunctionMenuCommands.OpenFunctionCommand;
}
public string FunctionTag { get; set; }
}
In specific what I did is to process each child node then if visible I add it to the collection... do you see any possible better solution?
Thanks
Whoever wrote that code clearly didn't know how to write WPF. In WPF, there is a much simpler option... just use the MenuItem.Visibility property to hide (collapse) MenuItems that users don't have access to. Of course, you'd need some data bind-able security bool properties which you could then data bind to the MenuItem.Visibility property of each MenuItem via a BooleanToVisibilityConverter. Here's a simple example:
<MenuItem Header="Some option" Visibility="{Binding User.Security.HasSomeOptionPermission,
Converter={StaticResource BooleanToVisibilityConverter}}" ... />
If a particular user has the SomeOptionPermission, then the MenuItem will be displayed, otherwise it will be hidden.
I am trying to reach a foreach but my program never gets inside because my ICollection Coletores is always empty even if I put a lot of stuff in there.
The code where I want to get inside and it is always empty (I want to get inside the second foreach):
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (NavigationContext.QueryString.TryGetValue("email", out email))
{
//MessageBox.Show(email);
List<HyperlinkButton> listaLinks = new List<HyperlinkButton>();
AppDataContext db = new AppDataContext();
int i = 0;
HyperlinkButton aux = new HyperlinkButton();
foreach (Pessoa pessoa in db.Pessoas)
{
if (pessoa.Email == email)
{
foreach (Coletor coletor in pessoa.Coletores)
{
aux.Content = "Coletor " + (i + 1).ToString();
aux.FontSize = 24;
aux.NavigateUri = new Uri("/OcorrenciasPage.xaml?coletorId=" + coletor.Id.ToString(), UriKind.RelativeOrAbsolute);
listaLinks.Add(aux);
i++;
}
}
}
ListBox coletores = new ListBox();
coletores.ItemsSource = listaLinks;
stcList.Children.Add(coletores);
}
base.OnNavigatedTo(e);
}
Now the code that I am adding data:
if (txtLat.Text != "" && txtLong.Text != "" && rdNorte.IsChecked == true || rdSul.IsChecked == true && rdLeste.IsChecked == true || rdOeste.IsChecked == true)
{
foreach (var pessoa in db.Pessoas)
{
if (pessoa.Email == email)
{
pessoa.Coletores.Add(coletor);
}
}
db.Coletores.InsertOnSubmit(coletor);
db.SubmitChanges();
NavigationService.Navigate(new Uri("/ColetoresPage.xaml?email=" + email, UriKind.RelativeOrAbsolute));
}
Now, my Pessoa class:
public class Pessoa : INotifyPropertyChanged
{
private int _id;
[Column(IsDbGenerated = true, IsPrimaryKey = true)]
public int Id {
get { return _id;}
set { _id = value;
OnPropertyChanged("Id");
}
}
private string _nome;
[Column]
public string Nome
{
get { return _nome; }
set { _nome = value;
OnPropertyChanged("Nome");
}
}
private string _email;
[Column]
public string Email
{
get { return _email; }
set { _email = value;
OnPropertyChanged("Email");
}
}
private string _senha;
[Column]
public string Senha { get { return _senha; }
set { _senha = value;
OnPropertyChanged("Senha");
}
}
private string _profissao;
[Column]
public string Profissao { get { return _profissao; }
set { _profissao = value;
OnPropertyChanged("Profissao");
}
}
private int _idade;
[Column]
public int Idade { get { return _idade; }
set { _idade = value;
OnPropertyChanged("Idade");
}
}
private string _endereco;
[Column]
public string Endereco { get { return _endereco; }
set { _endereco = value;
OnPropertyChanged("Endereco");
}
}
private string _cidade;
[Column]
public string Cidade { get { return _cidade; }
set { _cidade = value;
OnPropertyChanged("Cidade");
}
}
private string _estado;
[Column]
public string Estado { get { return _estado; }
set { _estado = value;
OnPropertyChanged("Estado");
}
}
private EntitySet<Coletor> _coletores = new EntitySet<Coletor>();
[Association(Name = "FK_Coletores_PessoaColetores", Storage = "_coletores", ThisKey = "Id", OtherKey = "pessoaId")]
public ICollection<Coletor> Coletores
{
get { return _coletores; }
set { _coletores.Assign(value); }
}
private EntitySet<PessoaColetor> _pessoaColetores = new EntitySet<PessoaColetor>();
[Association(Name = "FK_PessoaColetores_Pessoas", Storage = "_pessoaColetores", OtherKey = "pessoaId", ThisKey = "Id")]
private ICollection<PessoaColetor> PessoaColetores
{
get { return _pessoaColetores; }
set { _pessoaColetores.Assign(value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
The Coletores property on the Pessoa class looks alright. There is also a PessoaColetores property. Are you sure there has been no confusion between the two? Especially with intellisense one might dot or tab the wrong one.
Have you put a break point on the line that actually adds coletors (second code snippet)? Maybe stuff is added to the wrong collection.
Cheers, B.
I populate a data grid with a list of objects that come from a repository like this:
public static IEnumerable<Order> GetOrdersForDataGrid()
{
IEnumerable<Order> query;
using (RSDContext = new RSDContext())
{
query = context.Orders.Include(o=>o.OrderDetails).ToList();
}
return query;
}
When I want to edit an order I pass the selected row to a new window like this:
OrderEditWindow orderEdit = new OrderEditWindow();
orderEdit.SelectedOrder = SelectedOrder;
orderEdit.ShowDialog();
Here I set the DataContext of the Window to:
DataContext = SelectedOrder;
In this window I have another data grid that binds to OrderDetails collection property of Order. The problem is on CRUD operations on OrderDetails. For example, after I add a new orderDetail like this:
private void AddProductDetailButton_OnClick(object sender, RoutedEventArgs e)
{
if (!ValidateProductDetail())
return;
var _selectedProduct = ProductAutoCompleteBox.SelectedItem as Product;
var selectedProduct = ProductsRepository.GetProductById(_selectedProduct.ProductId);
OrderDetail orderDetail = new OrderDetail();
orderDetail.Price = selectedProduct.Price;
orderDetail.ProductCode = selectedProduct.Code;
orderDetail.ProductName = selectedProduct.Name;
orderDetail.Quantity = int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Um = selectedProduct.Um;
orderDetail.Total = selectedProduct.Price * int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Group = selectedProduct.Subgroup.Group.Name;
orderDetail.Subgroup = selectedProduct.Subgroup.Name;
orderDetail.SupplierName = selectedProduct.Supplier.Name;
//orderDetail.Order=SelectedOrder;
//orderDetail.OrderId = SelectedOrder.OrderId;
SelectedOrder.OrderDetails.Add(orderDetail);
ProductAutoCompleteBox.Text = string.Empty;
QuantityNumericUpDown.Value = 1;
ProductAutoCompleteBox.Focus();
}
and then I call the update method from repository:
public static void UpdateOrder(Order order)
{
using (RSDContext context = new RSDContext())
{
context.Orders.Attach(order);
context.Entry(order).State = EntityState.Modified;
context.SaveChanges();
}
}
I get an error about OrderId. If i set manualy the navigation property and the id I don't get an error but changes dont get saved into db.
My Order model look like this:
public class Order : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Order()
{
_OrderDetails = new ObservableCollection<OrderDetail>();
_OrderDetails.CollectionChanged += _OrderDetails_CollectionChanged;
}
void _OrderDetails_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
AttachProductChangedEventHandler(e.NewItems.Cast<OrderDetail>());
if (e.OldItems != null)
CalcualteTotals();
}
[NotMapped]
public decimal CalculatedTotal
{
get
{
return OrderDetails.Sum(x => x.Total);
}
}
public int OrderId { get; set; }
private int _Number;
public int Number
{
get { return _Number; }
set
{
_Number = value;
NotifyPropertyChanged("Number");
}
}
private DateTime _Date;
public DateTime Date
{
get { return _Date; }
set
{
_Date = value;
NotifyPropertyChanged("Date");
}
}
private bool _Canceled;
public bool Canceled
{
get { return _Canceled; }
set
{
_Canceled = value;
NotifyPropertyChanged("Canceled");
}
}
private string _ClientName;
public string ClientName
{
get { return _ClientName; }
set
{
_ClientName = value;
NotifyPropertyChanged("ClientName");
}
}
private string _ClientPhone;
public string ClientPhone
{
get { return _ClientPhone; }
set
{
_ClientPhone = value;
NotifyPropertyChanged("ClientPhone");
}
}
private string _DeliveryAddress;
public string DeliveryAddress
{
get { return _DeliveryAddress; }
set
{
_DeliveryAddress = value;
NotifyPropertyChanged("DeliveryAddress");
}
}
private decimal _Transport;
public decimal Transport
{
get { return _Transport; }
set
{
_Transport = value;
NotifyPropertyChanged("Transport");
}
}
private decimal _Total;
public decimal Total
{
get { return _Total; }
set
{
_Total = value;
NotifyPropertyChanged("Total");
}
}
private ObservableCollection<OrderDetail> _OrderDetails;
public virtual ObservableCollection<OrderDetail> OrderDetails
{
//get { return _OrderDetails ?? (_OrderDetails = new ObservableCollection<OrderDetail>()); }
get
{
return _OrderDetails;
}
set
{
_OrderDetails = value;
NotifyPropertyChanged("OrderDetails");
}
}
private void AttachProductChangedEventHandler(IEnumerable<OrderDetail> orderDetails)
{
foreach (var p in orderDetails)
{
p.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "Quantity":
case "Price":
case "Total":
CalcualteTotals();
break;
}
};
}
CalcualteTotals();
}
public void CalcualteTotals()
{
NotifyPropertyChanged("CalculatedTotal");
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
And my OrderDetail model look like this:
public class OrderDetail : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int OrderDetailId { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
private int _ProductCode;
public int ProductCode
{
get { return _ProductCode; }
set
{
_ProductCode = value;
NotifyPropertyChanged("ProductCode");
}
}
private string _ProductName;
public string ProductName
{
get { return _ProductName; }
set
{
_ProductName = value;
NotifyPropertyChanged("ProductName");
}
}
private string _Um;
public string Um
{
get { return _Um; }
set
{
_Um = value;
NotifyPropertyChanged("Um");
}
}
private decimal _Price;
public decimal Price
{
get { return _Price; }
set
{
_Price = value;
NotifyPropertyChanged("Price");
NotifyPropertyChanged("Total");
}
}
private int _Quantity;
public int Quantity
{
get { return _Quantity; }
set
{
_Quantity = value;
NotifyPropertyChanged("Quantity");
NotifyPropertyChanged("Total");
}
}
private string _SupplierName;
public string SupplierName
{
get { return _SupplierName; }
set
{
_SupplierName = value;
NotifyPropertyChanged("SupplierName");
}
}
private string _Subgroup;
public string Subgroup
{
get { return _Subgroup; }
set
{
_Subgroup = value;
NotifyPropertyChanged("Subgroup");
}
}
private string _Group;
public string Group
{
get { return _Group; }
set
{
_Group = value;
NotifyPropertyChanged("Group");
}
}
public decimal _Total;
public decimal Total
{
get { return Quantity * Price; }
set
{
_Total = value;
NotifyPropertyChanged("Total");
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
I'm really trying to use some sort of unit of work and I don't understand how i'm supposed to apply CRUD on objects with child collections and keep the UI updated in the same time (by working in a ObservableCollection and using Binding ClientPhone, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged my parent window is updated as I type)
A final working solution:
using (RSDContext context = new RSDContext())
{
var details = order.OrderDetails;
order.OrderDetails = null;
List<int> OriginalOrderDetailsIds =
context.OrderDetails.Where(o => o.OrderId == order.OrderId).Select(o => o.OrderDetailId).ToList();
List<int> CurrentOrderDetailsIds = details.Select(o => o.OrderDetailId).ToList();
List<int> DeletedOrderDetailsIds = OriginalOrderDetailsIds.Except(CurrentOrderDetailsIds).ToList();
context.Entry(order).State = EntityState.Modified;
foreach (var deletedOrderDetailId in DeletedOrderDetailsIds)
{
context.Entry(context.OrderDetails.Single(o => o.OrderDetailId == deletedOrderDetailId)).State = EntityState.Deleted;
}
foreach (OrderDetail detail in details)
{
// Add.
if (detail.OrderDetailId == 0)
{
detail.OrderId = order.OrderId;
context.Entry(detail).State = EntityState.Added;
}
// Update.
else
{
context.Entry(detail).State = EntityState.Modified;
}
}
context.SaveChanges();
}
You could do this way for adding and updating the child, but not sure about deleted order details in the ui. If you don't want to get the order from entity, you need some kind of marking in the OrderDetail for deleted OrderDetail.
using (RSDContext context = new RSDContext())
{
var details = order.OrderDetails;
order.OrderDetails = null;
context.Entry(order).State = EntityState.Modified;
foreach (var detail in details)
{
if (detail.Id == 0)
{
// Adds.
detail.OrderId = order.Id;
context.Entry(detail).State = EntityState.Added;
}
else if (detail.IsDeleted)
// Adds new property called 'IsDeleted'
// and add [NotMapped] attribute
// then mark this property as true from the UI for deleted items.
{
// Deletes.
context.Entry(detail).State = EntityState.Deleted;
}
else
{
// Updates.
context.Entry(detail).State = EntityState.Modified;
}
}
order.OrderDetails = details;
context.SaveChanges();
}