I am developing my first WPF browser application.
I load invoices in a dataGrid then I filter with textBox or comboBox.
Because it takes few seconds to load, I'am trying to put a loading animation according the following example:
here
It doesn't work the first time I navigate to the page. My dataGrid remains empty. When I debug I have this following error which happens on my query in Get() function.
'System.Data.Entity.Core.EntityCommandExecutionException' occurred in mscorlib.dll but was not handled in user code
But the this query used to work well before I made the changes for the animation. So maybe the problem doesn't come from the query.
Exception:Thrown: "Connection must be valid and open." (System.InvalidOperationException)
A System.InvalidOperationException was thrown: "Connection must be valid and open."
Time: 11/20/2015 12:36:31 PM
Thread:Worker Thread[13324]
public class ConsultInvoiceViewModel : ViewModelBase
{
public Context ctx = new Context();
private ICollectionView _dataGridCollection;
private string _filterString;
private ObservableCollection<Invoice> invoiceCollection;
public ConsultInvoiceViewModel()
{
if (!WPFHelper.IsInDesignMode)
{
var tsk = Task.Factory.StartNew(InitialStart);
tsk.ContinueWith(t => { MessageBox.Show(t.Exception.InnerException.Message); }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
}
}
private void InitialStart()
{
try
{
State = StateEnum.Busy;
DataGridCollection = CollectionViewSource.GetDefaultView(Get());
DataGridCollection.Filter = new Predicate<object>(Filter);
GetShop(); //load one comboBox
GetSupplier(); //load one comboBox
}
finally
{
State = StateEnum.Idle;
}
}
private ObservableCollection<Invoice> Get()
{
DateTime date2 = DateTime.Now.AddMonths(-2);
var query = ctx.Invoices
.GroupBy(x => new { x.suppInvNumber, x.shop1, x.date, x.foodSupplier })
.ToList()
.Select(i => new Invoice
{
suppInvNumber = i.Key.suppInvNumber,
shop1 = i.Key.shop1,
date = i.Key.date,
foodSupplier = i.Key.foodSupplier,
totalPrice = i.Sum(t => t.totalPrice),
})
.Where(d => d.date >= date2)
.OrderByDescending(d => d.date)
.AsQueryable();
invoiceCollection = new ObservableCollection<Invoice>(query);
return invoiceCollection;
}
public ICollectionView DataGridCollection
{
get
{
return _dataGridCollection;
}
set
{
_dataGridCollection = value;
OnPropertyChanged("DataGridCollection"); }
}
public string FilterString
{
get
{
return _filterString;
}
set
{
_filterString = value;
OnPropertyChanged("FilterString");
FilterCollection();
}
}
public static readonly PropertyChangedEventArgs StateArgs = ViewModelBase.CreateArgs<ConsultInvoiceViewModel>(c => c.State);
private StateEnum _State;
public StateEnum State
{
get
{
return _State;
}
set
{
var oldValue = State;
_State = value;
if (oldValue != value)
{
OnStateChanged(oldValue, value);
OnPropertyChanged(StateArgs);
}
}
}
protected virtual void OnStateChanged(StateEnum oldValue, StateEnum newValue)
{
}
private void FilterCollection()
{
if (_dataGridCollection != null)
{
_dataGridCollection.Refresh();
}
}
private bool Filter(object obj)
{
var data = obj as Invoice;
if (data != null)
{
if (!string.IsNullOrEmpty(_filterString))
{
return data.suppInvNumber.Contains(_filterString);
}
return true;
}
return false;
}
private void SearchFilter()
{
IOrderedEnumerable<Invoice> invs;
invs = ctx.Invoices
.Where(s => s.shop == Shop && s.supplier == Supplier && s.date >= From && s.date <= To)
.GroupBy(x => new {x.suppInvNumber, x.shop1, x.date, x.foodSupplier })
.ToList()
.Select(i => new Invoice
{
suppInvNumber = i.Key.suppInvNumber,
shop1 = i.Key.shop1,
date = i.Key.date,
foodSupplier = i.Key.foodSupplier,
totalPrice = i.Sum(t => t.totalPrice),
})
.OrderByDescending(d => d.date);
}
invoiceCollection.Clear();
if (invs != null)
foreach (var inv in invs)
{
invoiceCollection.Add(inv);
}
FilterCollection();
}
#region combobox
private void GetShop()
{
ctx.shops.ToList().ForEach(shop => ctx.shops.Local.Add(shop));
SShop = ctx.shops.Local;
}
private void GetSupplier()
{
ctx.foodSuppliers.ToList().ForEach(supplier => ctx.foodSuppliers.Local.Add(supplier));
FoodSupplier = ctx.foodSuppliers.Local;
}
private IList<foodSupplier> supplier;
public IList<foodSupplier> FoodSupplier
{
get
{
if (supplier == null)
GetSupplier();
return supplier;
}
set
{
supplier = value;
OnPropertyChanged("FoodSupplier");
}
}
private IList<shop> shop;
public IList<shop> SShop
{
get
{
return shop;
}
set
{
shop = value;
OnPropertyChanged("SShop");
}
}
private int _shop;
public int Shop
{
get
{
return _shop;
}
set
{
_shop = value;
OnPropertyChanged("Shop");
SearchFilter();
}
}
private int _supplier;
public int Supplier
{
get
{
return _supplier;
}
set
{
_supplier = value;
OnPropertyChanged("Supplier");
SearchFilter();
}
}
#endregion
#region "Command"
private ICommand searchCommand;
public ICommand SearchCommand
{
get
{
return searchCommand ?? (searchCommand = new RelayCommand(p => this.Search(), p => this.CanSearch()));
}
}
private bool CanSearch()
{
return true;
}
#endregion
}
The exception you are getting indicates an error connecting to the database. It's hard to diagnose this because of the way you keep a single Context reference for the life of the application. That connection could be failing at any point.
Try wrapping your data access in a new Context for each logical operation like this. Keeping one Context around for the life of an application is an Anti-pattern that can lead to all kinds of errors, especially when trying to do things in the background.
private ObservableCollection<Invoice> Get()
{
using (var ctx = new Context())
{
DateTime date2 = DateTime.Now.AddMonths(-2);
var query = ctx.Invoices
.GroupBy(x => new { x.suppInvNumber, x.shop1, x.date, x.foodSupplier })
.ToList()
.Select(i => new Invoice
{
suppInvNumber = i.Key.suppInvNumber,
shop1 = i.Key.shop1,
date = i.Key.date,
foodSupplier = i.Key.foodSupplier,
totalPrice = i.Sum(t => t.totalPrice),
})
.Where(d => d.date >= date2)
.OrderByDescending(d => d.date)
.AsQueryable();
invoiceCollection = new ObservableCollection<Invoice>(query);
}
return invoiceCollection;
}
Related
I am getting nuts trying to figure out why my code is not working.
I am removing or adding items to a list in EditIncidentViewModel and using IEventAggregator to pass that list to a Combobox in DisplayIncidentViewModel but I am unable to get the items refreshed.
In DisplayIncidentViewModel intially, the list is filled by parsing a text file, how can I get the updated list?
Here is DisplayIncidentViewModel:
namespace WpfUI.ViewModels
{
public class DisplayIncidentViewModel : Screen, IHandle<BindableCollection<Incident>>
{
private Incident _selectedIncident;
private string _firstName;
private string _resolutionText;
private bool _hasOptions;
private bool _isChecked;
private string output = "";
private string _text;
private IEventAggregator _events;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
NotifyOfPropertyChange(() => FirstName);
NotifyOfPropertyChange(() => ResolutionText);
}
}
public string ResolutionText
{
get { return CreateResolutionText(); }
set
{
_resolutionText = value;
NotifyOfPropertyChange(() => ResolutionText);
}
}
public bool HasOptions
{
get
{
if (SelectedIncident == null)
{
Incident inc = new Incident();
SelectedIncident = inc;
_isChecked = false;
return false;
}
if (string.IsNullOrWhiteSpace(SelectedIncident.Option))
{
_isChecked = false;
return false;
}
else return true;
}
set
{
_hasOptions = value;
NotifyOfPropertyChange(() => HasOptions);
}
}
public bool IsChecked
{
get { return _isChecked; }
set
{
if (_isChecked == value) return;
_isChecked = value;
NotifyOfPropertyChange(() => IsChecked);
NotifyOfPropertyChange(() => ResolutionText);
}
}
public string Text
{
get { return _text; }
set {
_text = value;
NotifyOfPropertyChange(() => Text);
}
}
public DisplayIncidentViewModel(IEventAggregator events)
{
_events = events;
var parser = new JsonParser();
parser.JsonLoadFile();
var list = parser.SortIncidentsByName();
foreach (var item in list)
{
Incidents.Add(new Incident
{
Name = item.Name,
Description = item.Description,
OtherDescription = item.OtherDescription,
Option = item.Option
});
}
Incidents.Refresh();
}
#region Combobox
// this is the backend that fires-up combobox with the values from json file
public BindableCollection<Incident> Incidents { get; set; } = new BindableCollection<Incident>();
public Incident SelectedIncident
{
get { return _selectedIncident; }
set
{
_selectedIncident = value;
IsChecked = false;
NotifyOfPropertyChange(() => SelectedIncident);
NotifyOfPropertyChange(() => ResolutionText);
NotifyOfPropertyChange(() => HasOptions);
NotifyOfPropertyChange(() => Text);
}
}
#endregion
public string CreateResolutionText()
{
if (SelectedIncident == null)
{
Incident inc = new Incident();
SelectedIncident = inc;
var nou = inc.Description;
SelectedIncident.Description = nou;
NotifyOfPropertyChange(() => SelectedIncident);
}
if (FirstName != "" && !string.IsNullOrWhiteSpace(SelectedIncident.Name))
{
if (!IsChecked)
{
output = $"{ FirstName },{Environment.NewLine}{SelectedIncident.Description}{Environment.NewLine}{Environment.NewLine}{ Globals.GetUsersFirstName(Globals.UserName) }";
Clipboard.SetText(output);
}
if (IsChecked)
{
output = $"{ FirstName },{Environment.NewLine}{SelectedIncident.OtherDescription}{Environment.NewLine}{Environment.NewLine}{ Globals.GetUsersFirstName(Globals.UserName) }";
Clipboard.SetText(output);
}
switch (SelectedIncident.Name)
{
case "Message":
Text = $"Dummy text here";
_events.PublishOnUIThread(new StatusText(Text));
break;
default:
_events.PublishOnUIThread(new StatusText($"Text copied to cliboard"));
break;
}
}
return output;
}
public void Handle(BindableCollection<Incident> message)
{
Incidents.Clear();
Incidents = message;
NotifyOfPropertyChange(() => Incidents);
}
}
}
Here is EditIncidentViewModel:
public class EditIncidentViewModel : Screen
{
private IEventAggregator _events;
private Incident _selectedIncident;
public BindableCollection<Incident> Incidents { get; set; } = new BindableCollection<Incident>();
private string _text;
private string _incidentDescription;
private string _incidentName;
private string output = "";
public Incident SelectedIncident
{
get { return _selectedIncident; }
set
{
_selectedIncident = value;
NotifyOfPropertyChange(() => SelectedIncident);
NotifyOfPropertyChange(() => IncidentDescription);
// NotifyOfPropertyChange(() => HasOptions);
NotifyOfPropertyChange(() => Text);
NotifyOfPropertyChange(() => IncidentName);
}
}
public string IncidentDescription
{
get { return GetIncidentDescription(); }
set
{
_incidentDescription = value;
NotifyOfPropertyChange(() => IncidentDescription);
}
}
#region Constructor
public EditIncidentViewModel(IEventAggregator events)
{
_events = events;
var parser = new JsonParser();
parser.JsonLoadFile();
var list = parser.SortIncidentsByName();
foreach (var item in list)
{
Incidents.Add(new Incident
{
Name = item.Name,
Description = item.Description,
OtherDescription = item.OtherDescription,
Option = item.Option
});
}
}
#endregion
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyOfPropertyChange(() => Text);
}
}
public string IncidentName
{
get {
if (SelectedIncident == null)
{
SelectedIncident = new Incident
{
Name = ""
};
}
return SelectedIncident.Name;
}
set {
_incidentName = value;
NotifyOfPropertyChange(() => IncidentName);
}
}
public string GetIncidentDescription()
{
if (SelectedIncident == null)
{
Incident inc = new Incident();
SelectedIncident = inc;
var nou = inc.Description;
SelectedIncident.Description = nou;
NotifyOfPropertyChange(() => SelectedIncident);
}
output = SelectedIncident.Description;
return output;
}
public void SaveIncident()
{
var newIncident = new Incident();
if (!string.IsNullOrWhiteSpace(_incidentName) || !string.IsNullOrWhiteSpace(_incidentDescription))
{
// Get SelectedIncident Name
newIncident.Name = _incidentName;
// Get SelectedIncident Description
newIncident.Description = _incidentDescription;
// Create a new Incident with the new properties
newIncident.OtherDescription = "dummy text here";
newIncident.Option = "";
// Incidents.Clear();
Incidents.Remove(SelectedIncident);
Incidents.Add(newIncident);
Incidents.Refresh();
// Save to file
string strResultJson = JsonConvert.SerializeObject(Incidents);
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "Data", "configuration.json"), strResultJson);
NotifyOfPropertyChange(() => IncidentDescription);
NotifyOfPropertyChange(() => IncidentName);
}
if (string.IsNullOrWhiteSpace(_incidentDescription) || _incidentDescription == IncidentDescription)
{
Incidents.Remove(SelectedIncident);
Text = $"Incident with name { SelectedIncident.Name } was deleted.";
_events.PublishOnUIThread(new StatusText(Text));
Incidents.Refresh();
// Save to file
string strResultJson = JsonConvert.SerializeObject(Incidents);
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "Data", "configuration.json"), strResultJson);
NotifyOfPropertyChange(() => IncidentDescription);
NotifyOfPropertyChange(() => IncidentName);
_events.BeginPublishOnUIThread(new BindableCollection<Incident>(Incidents));
}
}
}
DisplayIncidentView.xaml:
<ComboBox x:Name="Incidents" Height="40"
BorderBrush="#FFC7CC00" Foreground="#DD000000"
SelectedItem="{Binding SelectedIncident, Mode=OneWayToSource}"
DisplayMemberPath="Name"
materialDesign:HintAssist.Hint="Search" IsEditable="True" Style="{StaticResource MaterialDesignFloatingHintComboBox}"/>
I forgot to add to DisplayIncidentViewModel constructor:
_events.Subscribe(this);
I have read about the IEqualityComparer interface. Here is my code (which says more then a thousand words)
static void Main(string[] args)
{
var Send = new ObservableCollection<ProdRow>() {
new ProdRow() { Code = "8718607000065", Quantity = 1 },
new ProdRow() { Code = "8718607000911", Quantity = 10 }
};
var WouldSend = new ObservableCollection<ProdRow>() {
new ProdRow() { Code = "8718607000065", Quantity = 1 },
new ProdRow() { Code = "8718607000072", Quantity = 1 },
new ProdRow() { Code = "8718607000256", Quantity = 1 },
new ProdRow() { Code = "8718607000485", Quantity = 1 },
new ProdRow() { Code = "8718607000737", Quantity = 1 },
new ProdRow() { Code = "8718607000911", Quantity = 20 }
};
//var sendToMuch = Send.Except(WouldSend).ToList();
//var sendToLittle = WouldSend.Except(Send).ToList();
//if (sendToMuch.Any() || sendToLittle.Any())
// var notGood = true;
//else
// var okay = true;
var sendToMuch = Send.ToList();
var sendToLittle = WouldSend.ToList();
foreach (var s in Send) {
var w = WouldSend.FirstOrDefault(d => d.Code.Equals(s.Code));
if (w != null) {
if (w.Quantity == s.Quantity) {
sendToMuch.Remove(s);
sendToLittle.Remove(w);
continue;
}
if (w.Quantity > s.Quantity) {
sendToLittle.Single(l => l.Code == w.Code).Quantity = (w.Quantity - s.Quantity);
sendToMuch.Remove(s);
} else {
sendToMuch.Single(l => l.Code == w.Code).Quantity = (s.Quantity - w.Quantity);
sendToLittle.Remove(s);
}
} else {
sendToMuch.Add(s);
}
}
}
The commented lines where what I would hoped that would work... the stuff below with what I ended up with.
As reference, here is my ProdRow class:
class ProdRow : INotifyPropertyChanged, IEqualityComparer<ProdRow>
{
private string _code;
private int _quantity;
public string Code {
get { return _code; }
set {
_code = value;
OnPropertyChanged("Code");
}
}
public int Quantity {
get { return _quantity; }
set {
_quantity = value;
OnPropertyChanged("Quantity");
}
}
private void OnPropertyChanged(string v) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(v));
}
public new bool Equals(object x, object y) {
if (((ProdRow)x).Code.Equals(((ProdRow)y).Code) && ((ProdRow)x).Quantity == ((ProdRow)y).Quantity)
return true;
else
return false;
}
public int GetHashCode(object obj) {
return obj.GetHashCode();
}
public bool Equals(ProdRow x, ProdRow y) {
if (x.Code.Equals(y.Code) && x.Quantity == y.Quantity)
return true;
else
return false;
}
public int GetHashCode(ProdRow obj) {
throw new NotImplementedException();
}
public event PropertyChangedEventHandler PropertyChanged;
}
I did not expected the commented part to work, because it cannot know to decrease the int of quantity etc. but I would like to know if there is a more efficient way to do this then the solution I used (below the commented lines). Perhaps flatten the collection like a string[]?
P.S. Sorry for the "PascalCase" of Send and WouldSend
IEqualityComparer<T> is not the right interface to implement for a class whose instances you wish to compare. IEqualityComparer<T> implementations are for creating objects that do comparisons from the outside of the objects being compared, which becomes important when you need to re-define what it means for two objects to be equal without access to the code of these objects, or when you need to use different semantic for equality depending on the context.
The right interface for strongly typed equality comparison is IEquatable<T>. However, in your case all you need is overriding Object's Equals(object) and GetHashCode():
public new bool Equals(object obj) {
if (obj == this) return true;
var other = obj as ProdRow;
if (other == null) return false;
return Code.Equals(other.Code) && Quantity == other.Quantity;
}
public int GetHashCode() {
return 31*Code.GetHashCode() + Quantity;
}
As far as computing quantities goes, you can do it with negative numbers and GroupBy:
var quantityByCode = WouldSend.Select(p => new {p.Code, p.Quantity})
.Concat(Send.Select(p => new {p.Code, Quantity = -p.Quantity}))
.GroupBy(p => p.Code)
.ToDictionary(g => g.Key, g => g.Sum(p => p.Quantity));
var tooLittle = quantityByCode
.Where(p => p.Value > 0)
.Select(p => new ProdRow {Code = p.Key, Quantity = p.Value})
.ToList();
var tooMuch = quantityByCode
.Where(p => p.Value < 0)
.Select(p => new ProdRow {Code = p.Key, Quantity = -p.Value})
.ToList();
I am developing an windows phone app using sqlite database.I am able to show out the database and delete the particular row I want to delete.But the problem is after I select the row and click delete the row does not vanishes at that time.I have to renter that page to see that it is deleted.
Below here is the code of the class where I use the click_delete event
public partial class History : PhoneApplicationPage
{
ObservableCollection<historyTableSQlite> DB_HistoryList = new ObservableCollection<historyTableSQlite>();
DbHelper Db_helper = new DbHelper();
//public static int Selected_HistoryId;
//int Selected_HistoryId;
public static int Selected_HistoryId {get; set;}
// string dbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "db.sqlite");
public History()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Db_helper.AddInfo();
ReadHistoryList_Loaded();
// Selected_HistoryId = int.Parse(NavigationContext.QueryString["SelectedHistoryID"]);
}
public void ReadHistoryList_Loaded()
{
ReadAllContactsList dbhistory = new ReadAllContactsList();
DB_HistoryList = dbhistory.GetAllHistory();//Get all DB contacts
ListData.ItemsSource = DB_HistoryList.OrderByDescending(i => i.Id).ToList();
//Latest contact ID can Display first
}
public void ListData_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ListData.SelectedIndex != -1)
{
historyTableSQlite listitem = ListData.SelectedItem as historyTableSQlite;
History.Selected_HistoryId = listitem.Id;
}
}
private void Delete_Click(object sender, EventArgs e)
{
Db_helper.DeleteContact(History.Selected_HistoryId);
NavigationService.Navigate(new Uri("/History.xaml", UriKind.Relative));
}
private void DeleteAll_Click(object sender, EventArgs e)
{
DbHelper Db_helper = new DbHelper();
Db_helper.DeleteAllContact();//delete all DB contacts
DB_HistoryList.Clear();//Clear collections
ListData.ItemsSource = DB_HistoryList;
}
}
}
below is the class with all main functions
public class DbHelper
{
SQLiteConnection dbConn;
public async Task<bool> onCreate(string DB_PATH)
{
try
{
if (!CheckFileExists(DB_PATH).Result)
{
using (dbConn = new SQLiteConnection(DB_PATH))
{
dbConn.CreateTable<historyTableSQlite>();
}
}
return true;
}
catch
{
return false;
}
}
private async Task<bool> CheckFileExists(string fileName)
{
try
{
var store = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
return true;
}
catch
{
return false;
}
}
//retrieve all list from the database
public ObservableCollection<historyTableSQlite> ReadHistory()
{
using (var dbConn = new SQLiteConnection(App.DB_PATH))
{
List<historyTableSQlite> myCollection = dbConn.Table<historyTableSQlite>().ToList<historyTableSQlite>();
ObservableCollection<historyTableSQlite> HistoryList = new ObservableCollection<historyTableSQlite>(myCollection);
return HistoryList;
}
}
// Insert the new info in the histrorytablesqlite table.
public void Insert(historyTableSQlite newcontact)
{
using (var dbConn = new SQLiteConnection(App.DB_PATH))
{
dbConn.RunInTransaction(() =>
{
dbConn.Insert(newcontact);
});
}
}
public void AddInfo()
{
DbHelper Db_helper = new DbHelper();
Db_helper.Insert((new historyTableSQlite
{
Date = DateTime.Now.ToShortDateString(),
Time = DateTime.Now.ToShortTimeString(),
Zone = Checkin.Zone_st,
Floor = Checkin.Floor_st,
latitude = Checkin.Latitud_do,
longtitude = Checkin.Longtitude_do
}));
}
// Delete specific contact
public void DeleteContact(int Id)
{
using (var dbConn = new SQLiteConnection(App.DB_PATH))
{
var existingvalue = dbConn.Query<historyTableSQlite>("select * from historyTableSQlite where Id =" + Id).FirstOrDefault();
if (existingvalue != null)
{
dbConn.RunInTransaction(() =>
{
dbConn.Delete(existingvalue);
});
}
}
}
//Delete all contactlist or delete Contacts table
public void DeleteAllContact()
{
using (var dbConn = new SQLiteConnection(App.DB_PATH))
{
//dbConn.RunInTransaction(() =>
// {
dbConn.DropTable<historyTableSQlite>();
dbConn.CreateTable<historyTableSQlite>();
dbConn.Dispose();
dbConn.Close();
//});
}
}
below is the class with all tables
public class historyTableSQlite : INotifyPropertyChanged
{
[SQLite.PrimaryKey, SQLite.AutoIncrement]
public int Id
{
get;
set;
}
private int idValue;
private string dateValue = string.Empty;
public string Date
{
get { return this.dateValue; }
set
{
if (value != this.dateValue)
{
this.dateValue = value;
NotifyPropertyChanged("Date");
}
}
}
private string timeValue = string.Empty;
public string Time
{
get { return this.timeValue; }
set
{
if (value != this.timeValue)
{
this.timeValue = value;
NotifyPropertyChanged("Time");
}
}
}
private string floorValue = string.Empty;
public string Floor
{
get { return this.floorValue; }
set
{
if (value != this.floorValue)
{
this.floorValue = value;
NotifyPropertyChanged("Floor");
}
}
}
public string zoneValue;
public string Zone
{
get { return this.zoneValue; }
set
{
if (value != this.zoneValue)
{
this.zoneValue = value;
NotifyPropertyChanged("Zone");
}
}
}
private double latValue;
public double latitude
{
get { return latValue; }
set
{
if (value != this.latValue)
{
this.latValue = value;
NotifyPropertyChanged("Latitude");
}
}
}
private double lonValue;
public double longtitude
{
get { return this.lonValue; }
set
{
if (value != this.lonValue)
{
this.lonValue = value;
NotifyPropertyChanged("Longitude");
}
}
}
// public string isMarkPoint { get; set; }
public historyTableSQlite()
{
}
public historyTableSQlite(string date, string time, string floor, string zone, double lat, double lng)
{
Date = date;
Time = time;
Floor = floor;
Zone = zone;
latitude = lat;
longtitude = lng;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
If you delete the item from your ObservableCollection, it will notify the ListBox to update its container.
In your code you have
// this is correct
ObservableCollection<historyTableSQlite> DB_HistoryList = new ObservableCollection<historyTableSQlite>();
But your problem is that you don't actually link your ListBox to it.
In your code you create a copy (and the worst kind of copy given what you're trying to do) and you set the ListBox ItemsSource to it. See below (you have this)
ListData.ItemsSource = DB_HistoryList.OrderByDescending(i => i.Id).ToList();
So basically, your ListBox is not an ObservableCollection but it's a List structure.
Deleting and Inserting into the List will not update the ListBox's UI.
Get rid of this List, find another way to sort your ObservableCollection.
Then you can basically do this
ListData.ItemsSource = DB_HistoryList; // set the listbox to the actual obs collection
DB_HistoryList.RemoveAt(i); // remove the item at index i
DB_HistoryList.RemoveItem(object); // remove the object that matches
I'm new on CSLA.Net and I've some difficult to remove a child object from a list.
I've 3 classes :
Scenario : BusinessBase<Scenario>
ScenarioPermissions : BusinessListBase<ScenarioPermissions, ScenarioPermission>
ScenarioPermission : BusinessBase<ScenarioPermission>
Class Scenario contains one field of type ScenarioPermissions.
When I Try to do Scenario.Permissions.Add(obj) and Scenario.Save(), it works correctly.
But if I want to do Scenario.Permissions.Remove(obj) and Scenario.Save(), it continues without deleting my ScenarioPermission object from the database.
public class Scenario : BusinessBase<Scenario>, IMakeCopy
{
private static readonly PropertyInfo<ScenarioPermissions> m_PermissionsProperty = RegisterProperty<ScenarioPermissions>(c => c.m_Permissions);
public ScenarioPermissions m_Permissions
{
get
{
if (!FieldManager.FieldExists(m_PermissionsProperty))
{
SetProperty(m_PermissionsProperty, ScenarioPermissions.NewPermissions());
}
return GetProperty(m_PermissionsProperty);
}
}
public ReadOnlyCollection<Model.Users.User> Permissions
{
get
{
var collection = new List<Model.Users.User>();
foreach (var item in m_Permissions)
{
collection.Add(Model.Users.User.GetUser(item.UserID));
}
//Adds administrators users...
var admins = Users.Users.GetUsers(true).Where(u => u.Role.InvariantName == "SystemAdministrator" || u.Role.InvariantName == "SuperAdministrator");
foreach (var item in admins)
{
collection.Add(item);
}
return new ReadOnlyCollection<Model.Users.User>(collection.OrderBy(u => u.FullName).ToArray());
}
}
public void AddPermission(Model.Users.User user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
ScenarioPermission permission = ScenarioPermission.NewPermission(this, user);
if (!this.m_Permissions.Contains(permission))
{
this.m_Permissions.Add(permission);
}
}
public void RemovePermission(Model.Users.User user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
ScenarioPermission permission = this.m_Permissions.FirstOrDefault(p => p.UserID == user.Id);
if (permission != null)
{
this.m_Permissions.Remove(permission);
}
}
protected override void DataPortal_Update()
{
using (var ctx = DbContextManager<DatabaseContext>.GetManager())
{
var context = ctx.DbContext;
var scenarioId = ReadProperty(m_IdProperty);
var scenario = context.Scenarios.FirstOrDefault(s => s.Id == scenarioId);
if (scenario != null)
{
scenario.Name = ReadProperty(m_NameProperty);
//Some codes....
context.SaveChanges();
}
FieldManager.UpdateChildren(this);
}
}
protected override void DataPortal_DeleteSelf()
{
DataPortal_Delete(ReadProperty(m_IdProperty));
}
private void DataPortal_Delete(Guid id)
{
using (var contextManager = DbContextManager<DatabaseContext>.GetManager())
{
var context = contextManager.DbContext;
var scenario = context.Scenarios.FirstOrDefault(s => s.Id == id);
if (scenario != null)
{
context.Scenarios.Remove(scenario);
context.SaveChanges();
}
}
Dispatcher.CurrentDispatcher.Invoke(new Action(() => ScenarioList.Delete(id)));
}
}
public class ScenarioPermissions : BusinessListBase<ScenarioPermissions, ScenarioPermission>
{
public static ScenarioPermissions NewPermissions()
{
return DataPortal.Create<ScenarioPermissions>();
}
public static ScenarioPermissions GetUsersByScenario(Scenario scenario)
{
return DataPortal.FetchChild<ScenarioPermissions>(scenario);
}
private void Child_Fetch(Scenario obj)
{
using (var ctx = DbContextManager<DatabaseContext>.GetManager())
{
var context = ctx.DbContext;
var scenario = context.Scenarios.Where(s => s.Id == obj.Id).FirstOrDefault();
if (scenario != null)
{
foreach (var item in scenario.Users)
{
this.Add(ScenarioPermission.NewPermission(scenario.Id, item.Id));
}
}
}
}
}
public class ScenarioPermission : BusinessBase<ScenarioPermission>
{
private static readonly PropertyInfo<Guid> m_ScenarioID = RegisterProperty<Guid>(p => p.ScenarioID);
public Guid ScenarioID
{
get { return GetProperty(m_ScenarioID); }
private set { SetProperty(m_ScenarioID, value); }
}
private static readonly PropertyInfo<int> m_UserID = RegisterProperty<int>(p => p.UserID);
public int UserID
{
get { return GetProperty(m_UserID); }
private set { SetProperty(m_UserID, value); }
}
public static ScenarioPermission NewPermission(Scenario scenario, Model.Users.User user)
{
return NewPermission(scenario.Id, user.Id);
}
public static ScenarioPermission NewPermission(Guid scenarioID, int userID)
{
var newObj = DataPortal.CreateChild<ScenarioPermission>();
newObj.ScenarioID = scenarioID;
newObj.UserID = userID;
return newObj;
}
private ScenarioPermission() { /* Used for Factory Methods */}
private void Child_Insert(Scenario scenario)
{
DataPortal_Insert();
}
private void Child_DeleteSelf(Scenario scenario)
{
DataPortal_DeleteSelf();
}
private void Child_DeleteSelf()
{
DataPortal_DeleteSelf();
}
protected override void DataPortal_Insert()
{
using (var ctx = DbContextManager<DatabaseContext>.GetManager())
{
var context = ctx.DbContext;
var scenario = context.Scenarios.FirstOrDefault(s => s.Id == ScenarioID);
var user = context.Users.FirstOrDefault(u => u.Id == UserID);
if (scenario != null && user != null)
{
scenario.Users.Add(user);
context.SaveChanges();
}
}
}
protected override void DataPortal_DeleteSelf()
{
using (var ctx = DbContextManager<DatabaseContext>.GetManager())
{
var context = ctx.DbContext;
var scenario = context.Scenarios.FirstOrDefault(s => s.Id == ScenarioID);
var user = context.Users.FirstOrDefault(u => u.Id == UserID);
if (scenario != null && user != null)
{
if (scenario.Users.Contains(user))
{
scenario.Users.Remove(user);
context.SaveChanges();
}
}
}
}
public override bool Equals(object obj)
{
// If parameter is null return false.
if (obj == null)
{
return false;
}
// If parameter cannot be cast to ScenarioPermission return false.
ScenarioPermission p = obj as ScenarioPermission;
if ((System.Object)p == null)
{
return false;
}
// Return true if the fields match:
return (this.ScenarioID == p.ScenarioID) && (this.UserID == p.UserID);
}
}
I've just find the solution :
When I fetched the children of ScenariosPermissions, I created children instead of fetching existing... So, when I wanted to remove permissions, the existing objects was considered by CSLA as a NewObject, so it does not the Delete() ;-)
Correction :
public class ScenarioPermissions : BusinessListBase<ScenarioPermissions, ScenarioPermission>
{
public static ScenarioPermissions NewPermissions()
{
return DataPortal.Create<ScenarioPermissions>();
}
public static ScenarioPermissions GetUsersByScenario(Scenario scenario)
{
return DataPortal.FetchChild<ScenarioPermissions>(scenario);
}
private void Child_Fetch(Scenario obj)
{
RaiseListChangedEvents = false;
using (var ctx = DbContextManager<DatabaseContext>.GetManager())
{
var context = ctx.DbContext;
var scenario = context.Scenarios.Where(s => s.Id == obj.Id).FirstOrDefault();
if (scenario != null)
{
foreach (var item in scenario.Users)
{
this.Add(ScenarioPermission.GetPermission(scenario.Id, item.Id));
}
}
}
RaiseListChangedEvents = true;
}
}
public class ScenarioPermission : BusinessBase<ScenarioPermission>
{
public static ScenarioPermission GetPermission(Guid scenarioID, int userID)
{
return DataPortal.FetchChild<ScenarioPermission>(scenarioID, userID);
}
private void Child_Fetch(Guid scenarioID, int userID)
{
LoadProperty(m_ScenarioID, scenarioID);
LoadProperty(m_UserID, userID);
}
}
I have recently decided to use protobuf-net to serialize large plain text data files my application uses to see if there is any performance gain over parsing the plain text data.
Data Class:
[ProtoContract]
public class ClimateFile : BaseModel
{
#region Properties
[ProtoMember(1)]
public double Latitude { get { return GetValue(() => Latitude); } private set { SetValue(() => Latitude, value); } }
[ProtoMember(2)]
public double Longitude { get { return GetValue(() => Longitude); } private set { SetValue(() => Longitude, value); } }
[ProtoMember(3)]
public string Notes { get { return GetValue(() => Notes); } set { SetValue(() => Notes, value); } }
[ProtoMember(4)]
public DateTime MinDate { get { return GetValue(() => MinDate); } private set { SetValue(() => MinDate, value); } }
[ProtoMember(5)]
public DateTime MaxDate { get { return GetValue(() => MaxDate); } private set { SetValue(() => MaxDate, value); } }
[ProtoMember(6)]
public List<ClimateDailyData> DailyData { get { return GetValue(() => DailyData); } private set { SetValue(() => DailyData, value); } }
#endregion
#region Method
public static ClimateFile Load(string filePath)
{
try
{
var ext = Path.GetExtension(filePath).ToUpper();
if (ext == ".P51")
return new ClimateFile(filePath);
else if (ext == ".P51X")
{
ClimateFile climateFile;
using (var file = File.OpenRead(filePath))
{
climateFile = Serializer.Deserialize<ClimateFile>(file);
}
return climateFile;
}
}
catch (Exception e)
{
throw new InvalidDataException(String.Format("The file \"{0}\" could not be opened, {1}", filePath, ExceptionUtilities.JoinExceptionMessages(e)));
}
throw new ArgumentException("filePath was not a .P51 or .P51X file.");
}
public void LoadP51File(string filePath)
{
List<string[]> lines = GetFileLines(filePath);
Latitude = double.Parse(lines[0][0]);
Longitude = double.Parse(lines[0][1]);
for (int i = 2; i < lines[0].Length; ++i)
Notes += String.Format("{0} ", lines[0][i]);
MinDate = GetDate(lines[2][0]);
MaxDate = GetDate(lines[lines.Count - 1][0]);
// Parse daily data
lines.RemoveRange(0, 2);
var dailyData = lines.Select(row => new ClimateDailyData()
{
DataDate = GetDate(row[0]),
MaxTemperature = double.Parse(row[2]),
MinTemperature = double.Parse(row[3]),
Rainfall = double.Parse(row[4]),
Evaporation = double.Parse(row[5]),
SolarRadiation = double.Parse(row[6])
}).ToList();
DailyData = dailyData;
}
public void SaveP51XFile(string filePath)
{
using (var file = File.Create(filePath))
{
Serializer.Serialize<ClimateFile>(file, this);
}
}
public List<string[]> GetFileLines(string filePath)
{
var rows = new List<string[]>();
var cells = new List<string>();
var cell = new StringBuilder();
using (var fs = new BufferedStream(File.OpenRead(filePath)))
{
int buffer;
while ((buffer = fs.ReadByte()) != -1)
{
char nextChar = (char)buffer;
if (nextChar >= '!') // If the character is a non-whitespace printable character
{
cell.Append(nextChar);
continue;
}
if (nextChar == ' ' || nextChar == '\t')
{
if (cell.Length > 0)
{
cells.Add(cell.ToString());
cell.Clear();
}
continue;
}
if (nextChar == '\r' || nextChar == '\n')
{
if (cell.Length > 0)
{
cells.Add(cell.ToString());
cell.Clear();
}
if (cells.Count > 0)
{
rows.Add(cells.ToArray());
cells.Clear();
}
continue;
}
throw new InvalidDataException("The climate file contains unknown characters.");
}
if (cell.Length > 0)
cells.Add(cell.ToString());
if (cells.Count > 0)
rows.Add(cells.ToArray());
}
return rows;
}
public DateTime GetDate(string date)
{
return DateTime.ParseExact(date, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None);
}
public override void Dispose()
{
if (Disposed)
return;
if (DailyData != null)
foreach (ClimateDailyData dailyData in DailyData)
dailyData.Dispose();
base.Dispose();
}
#endregion
#region Initialization
public ClimateFile()
{
}
public ClimateFile(string filePath)
{
LoadP51File(filePath);
}
#endregion
}
Collection Data Class:
[ProtoContract]
public class ClimateDailyData : BaseModel
{
[ProtoMember(1)]
public DateTime DataDate { get { return GetValue(() => DataDate); } set { SetValue(() => DataDate, value); } }
[ProtoMember(2)]
public int JulianDay { get { return DataDate.DayOfYear; } }
[ProtoMember(3)]
public double MaxTemperature { get { return GetValue(() => MaxTemperature); } set { SetValue(() => MaxTemperature, value); } }
[ProtoMember(4)]
public double MinTemperature { get { return GetValue(() => MinTemperature); } set { SetValue(() => MinTemperature, value); } }
[ProtoMember(5)]
public double Rainfall { get { return GetValue(() => Rainfall); } set { SetValue(() => Rainfall, value); } }
[ProtoMember(6)]
public double Evaporation { get { return GetValue(() => Evaporation); } set { SetValue(() => Evaporation, value); } }
[ProtoMember(7)]
public double SolarRadiation { get { return GetValue(() => SolarRadiation); } set { SetValue(() => SolarRadiation, value); } }
}
Serialization Command:
public ICommand ImportP51
{
get
{
return new RelayCommand(delegate
{
OpenFileDialog openDialogue = new OpenFileDialog()
{
AddExtension = true,
CheckPathExists = true,
CheckFileExists = true,
DefaultExt = ".p51",
Filter = "Climate Files|*.p51",
InitialDirectory = DataPath,
Multiselect = false,
Title = "Select a File to Open"
};
if ((bool)openDialogue.ShowDialog())
{
string filePath = String.Empty;
try
{
filePath = openDialogue.FileName;
var climate = new Climate();
climate.FilePath = filePath;
var savePath = String.Format("{0}\\{1}.p51x", ClimateDataPath, Path.GetFileNameWithoutExtension(filePath));
climate.FileData.SaveP51XFile(savePath);
}
catch (Exception e)
{
MessageBox.Show(String.Format("The file \"{0}\" could not be opened, {1}", filePath, ExceptionUtilities.JoinExceptionMessages(e)), "Invalid File");
}
}
});
}
}
When executing ImportP51, I get the exception "Specified method is not supported", I am using protobuf-net V2 r594 which was released on the 12/10/2012 and am thinking of trying to use one of the previous versions if I cannot get it to work with this version. Can someone please tell me what I am doing wrong?
I've tried to reconstruct a working version of the code (since I don't have your BaseModel) which I've done by using automatically implemented properties and adding an initializer for the list (DailyData), and explicitly referencing r594 from google-code. The only error I get is:
Cannot apply changes to property ClimateDailyData.JulianDay
which makes sense, because it can't rightly deserialize data into a read-only property, so I removed the serialization marker from that one:
// [ProtoMember(2)] removed - serialized implicitly via DataData
public int JulianDay { get { return DataDate.DayOfYear; } }
After that it worked fine. Since I don't have your command framework, I have:
static class Program
{
static void Main()
{
var climateFile = new ClimateFile();
climateFile.InitSomeDataForSerialization();
climateFile.SaveP51XFile("foo.P51X");
var clone = ClimateFile.Load("foo.P51X");
}
}
where InitSomeDataForSerialization just sets some of the values (since they have private setters, I can't do that in Main):
public void InitSomeDataForSerialization()
{
Longitude = 10; Latitude = 4; Notes = "Test";
DailyData.Add(
new ClimateDailyData { DataDate = DateTime.Today, MinTemperature = 12, MaxTemperature = 35}
);
}
And... it works.
On a hunch, I checked what happens if you reference "CoreOnly" instead of "Full", but that then refuses to compile because Serializer.Serialize<T> and Serializer.Deserialize<T> don't exist.
I'm happy to help, but as far as I can tell, nothing is wrong.
Things I would suggest next:
show the full stack-trace of what happens in this exception, including any inner-exceptions (see the fix below)
please check exactly which file you referenced in the 594 zip (look at "What Files Do I Need.txt", but I'd guess the correct one for you is "Full/net30/..."; the nuget package configures the most appropriate files automatically)
please show a fully reproducible example, i.e. where I can press F5 and see the exact exception (I had to change the code in the example for it to compile, which means I am no longer testing the same thing)
Fix for correct exception wrapping:
catch (Exception e)
{
throw new InvalidDataException(String.Format("The file \"{0}\" could not be opened", filePath), e);
}