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);
Related
I have a problem with Xamarin.Forms whereby the View is not refreshing as I would expect it to.
I have bound a View to a ViewModel, and I have a series of methods to perform various functions.
On the successful completion of a function, I want it to execute my LoadResults() method.
The LoadResults() method works fine when I load the view initially. However, when I execute any other method (DeleteScan(id) method shown below) it should re-fire the LoadResults() method and reload the page.
I know it is entering the LoadResults() method as I've put a break point in there and stepped through it. But by the end of it, it doesn't reload the view.
I also know the view can refresh, as I have other simple methods which are simply updating properties in the VM and those changes are reflecting in the UI.
So for whatever reason, LoadResults() is not reloading the page.
Any ideas what I've done wrong here?
View Model Constructor and Properties
public class ResultsProcessViewModel : INotifyPropertyChanged
{
public ICommand AddTimingCommand { get; set; }
public ICommand AddScanCommand { get; set; }
public ICommand InsertTimingCommand { get; set; }
public ICommand InsertScanCommand { get; set; }
public ICommand DeleteTimingCommand { get; set; }
public ICommand DeleteScanCommand { get; set; }
public ICommand PublishCommand { get; set; }
public ICommand LoadResultsCommand { get; set; }
public ICommand CancelMissingFinisherCommand { get; set; }
public ICommand CancelMissingTimingCommand { get; set; }
public int RaceId { get; set; }
public DateTime RaceDate { get; set; }
//public ResultsViewModel(Race race)
public ResultsProcessViewModel(Race race)
{
AddTimingCommand = new Command<string>(AddTiming);
InsertTimingCommand = new Command(InsertTiming);
AddScanCommand = new Command<string>(AddScan);
InsertScanCommand = new Command(InsertScan);
DeleteTimingCommand = new Command<int>(DeleteTiming);
DeleteScanCommand = new Command<int>(DeleteScan);
PublishCommand = new Command(Publish);
LoadResultsCommand = new Command<int>(LoadResults);
CancelMissingFinisherCommand = new Command(CancelMissingFinisher);
CancelMissingTimingCommand = new Command(CancelMissingTiming);
Invalid = false;
PublishStatus = race.ResultStatus;
Published = false;
PublishVisibility = false;
AddTimingVisibility = false;
AddScanVisibility = false;
AddVisibility = true;
IsBusy = false;
RaceId = race.Id;
RaceDate = race.RaceDate;
RaceStartTime = Convert.ToDateTime(race.RaceStartTime);
Scans = ScansAPI.GetScans(RaceId);
Timings = TimingsAPI.GetTimings(RaceId);
Entries = EntriesAPI.GetEntries(RaceId);
LoadResults(RaceId);
}
ObservableCollection<GroupedResultModel> _grouped;
public ObservableCollection<GroupedResultModel> grouped
{
get { return _grouped; }
set
{
if (_grouped == value)
return;
_grouped = value;
OnPropertyChanged("Grouped");
}
}
DateTime _raceStartTime;
public DateTime RaceStartTime
{
get { return _raceStartTime; }
set
{
if (_raceStartTime == value)
return;
_raceStartTime = value;
OnPropertyChanged("RaceStartTime");
}
}
int _timingPosition;
public int TimingPosition
{
get { return _timingPosition; }
set
{
if (_timingPosition == value)
return;
_timingPosition = value;
OnPropertyChanged("TimingPosition");
}
}
int _addScanTimingId;
public int AddScanTimingId
{
get { return _addScanTimingId; }
set
{
if (_addScanTimingId == value)
return;
_addScanTimingId = value;
OnPropertyChanged("AddScanTimingId");
}
}
int _addTimingScanId;
public int AddTimingScanId
{
get { return _addTimingScanId; }
set
{
if (_addTimingScanId == value)
return;
_addTimingScanId = value;
OnPropertyChanged("AddTimingScanId");
}
}
int _scanPosition;
public int ScanPosition
{
get { return _scanPosition; }
set
{
if (_scanPosition == value)
return;
_scanPosition = value;
OnPropertyChanged("ScanPosition");
}
}
bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set
{
if (_isBusy == value)
return;
_isBusy = value;
OnPropertyChanged("IsBusy");
}
}
bool _published;
public bool Published
{
get { return _published; }
set
{
if (_published == value)
return;
_published = value;
OnPropertyChanged("Published");
}
}
bool _publishVisibility;
public bool PublishVisibility
{
get { return _publishVisibility; }
set
{
if (_publishVisibility == value)
return;
_publishVisibility = value;
OnPropertyChanged("PublishVisibility");
}
}
bool _error;
public bool Error
{
get { return _error; }
set
{
if (_error == value)
return;
_error = value;
OnPropertyChanged("Error");
}
}
bool _addVisibility;
public bool AddVisibility
{
get { return _addVisibility; }
set
{
if (_addVisibility == value)
return;
_addVisibility = value;
OnPropertyChanged("AddVisibility");
}
}
bool _addTimingVisibility;
public bool AddTimingVisibility
{
get { return _addTimingVisibility; }
set
{
if (_addTimingVisibility == value)
return;
_addTimingVisibility = value;
OnPropertyChanged("AddTimingVisibility");
}
}
bool _addScanVisibility;
public bool AddScanVisibility
{
get { return _addScanVisibility; }
set
{
if (_addScanVisibility == value)
return;
_addScanVisibility = value;
OnPropertyChanged("AddScanVisibility");
}
}
ObservableCollection<Result> _results;
public ObservableCollection<Result> Results
{
get
{
return _results;
}
set
{
if (_results != value)
{
_results = value;
OnPropertyChanged("Results");
}
}
}
ObservableCollection<Scan> _scans;
public ObservableCollection<Scan> Scans
{
get
{
return _scans;
}
set
{
if (_scans != value)
{
_scans = value;
OnPropertyChanged("Scans");
}
}
}
ObservableCollection<Timing> _timings;
public ObservableCollection<Timing> Timings
{
get
{
return _timings;
}
set
{
if (_timings != value)
{
_timings = value;
OnPropertyChanged("Timings");
}
}
}
ObservableCollection<RaceEntry> _entries;
public ObservableCollection<RaceEntry> Entries
{
get
{
return _entries;
}
set
{
if (_entries != value)
{
_entries = value;
OnPropertyChanged("Entries");
}
}
}
bool _invalid;
public bool Invalid
{
get { return _invalid; }
set
{
if (_invalid == value)
return;
_invalid = value;
OnPropertyChanged("Invalid");
}
}
bool _resultsInvalid;
public bool ResultsInvalid
{
get { return _resultsInvalid; }
set
{
if (_resultsInvalid == value)
return;
_resultsInvalid = value;
OnPropertyChanged("ResultsInvalid");
}
}
bool _insertScanVisibility;
public bool InsertScanVisibility
{
get { return _insertScanVisibility; }
set
{
if (_insertScanVisibility == value)
return;
_insertScanVisibility = value;
OnPropertyChanged("InsertScanVisibility");
}
}
string _validationError;
public string ValidationError
{
get { return _validationError; }
set
{
if (_validationError == value)
return;
_validationError = value;
OnPropertyChanged("ValidationError");
}
}
string _resultsValidationError;
public string ResultsValidationError
{
get { return _resultsValidationError; }
set
{
if (_resultsValidationError == value)
return;
_resultsValidationError = value;
OnPropertyChanged("ResultsValidationError");
}
}
string _missingBib;
public string MissingBib
{
get { return _missingBib; }
set
{
if (_missingBib == value)
return;
_missingBib = value;
OnPropertyChanged("MissingBib");
}
}
string _errorMessage;
public string ErrorMessage
{
get { return _errorMessage; }
set
{
if (_errorMessage == value)
return;
_errorMessage = value;
OnPropertyChanged("ErrorMessage");
}
}
public Race SelectedRace { get; set; }
private bool _raceCountZero;
public bool RaceCountZero
{
get { return _raceCountZero; }
set
{
if (_raceCountZero == value)
return;
_raceCountZero = value;
OnPropertyChanged("RaceCountZero");
}
}
string _aboveBelow;
public string AboveBelow
{
get { return _aboveBelow; }
set
{
if (_aboveBelow == value)
return;
_aboveBelow = value;
OnPropertyChanged("AboveBelow");
}
}
string _aboveBelowPosition;
public string AboveBelowPosition
{
get { return _aboveBelowPosition; }
set
{
if (_aboveBelowPosition == value)
return;
_aboveBelowPosition = value;
OnPropertyChanged("AboveBelowPosition");
}
}
string _publishStatus;
public string PublishStatus
{
get { return _publishStatus; }
set
{
if (_publishStatus == value)
return;
_publishStatus = value;
OnPropertyChanged("PublishStatus");
}
}
string _newBatchCode;
public string NewBatchCode
{
get { return _newBatchCode; }
set
{
if (_newBatchCode == value)
return;
_newBatchCode = value;
OnPropertyChanged("NewBatchCode");
}
}
string _addHH;
public string AddHH
{
get { return _addHH; }
set
{
if (_addHH == value)
return;
_addHH = value;
OnPropertyChanged("AddHH");
}
}
string _addMM;
public string AddMM
{
get { return _addMM; }
set
{
if (_addMM == value)
return;
_addMM = value;
OnPropertyChanged("AddMM");
}
}
string _addSS;
public string AddSS
{
get { return _addSS; }
set
{
if (_addSS == value)
return;
_addSS = value;
OnPropertyChanged("AddSS");
}
}
string _scanBatchCode;
public string ScanBatchCode
{
get { return _scanBatchCode; }
set
{
if (_scanBatchCode == value)
return;
_scanBatchCode = value;
OnPropertyChanged("ScanBatchCode");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
DeleteScan method
void DeleteScan(int scanid)
{
//Do stuff when deleting a scan. It needs to do all this in the observable collection. Then when we submit, we'll update all scans, timings etc with whats in the collection
Task.Run(() =>
{
try
{
Device.BeginInvokeOnMainThread(() => IsBusy = true);
var IsThereConnection = GlobalFunctions.CheckForInternetConnection();
if (IsThereConnection == false)
throw new Exception("You cannot delete a scan whilst you are offline");
//We are good to go
else
{
var deletescan = ScansAPI.DeleteScan(scanid);
if (deletescan.Code != "NoContent")
throw new Exception("Error deleting scan");
}
}
catch (Exception ex)
{
Device.BeginInvokeOnMainThread(() =>
{
ValidationError = ex.Message;
Invalid = true;
});
return;
}
finally
{
var newscans = ScansAPI.GetScans(RaceId);
var sortednewscans = new ObservableCollection<Scan>(newscans.OrderBy(c => c.Position));
Scans = sortednewscans;
Device.BeginInvokeOnMainThread(() => Published = false);
Device.BeginInvokeOnMainThread(() => LoadResults(RaceId));
Device.BeginInvokeOnMainThread(() => AddScanVisibility = false);
Device.BeginInvokeOnMainThread(() => IsBusy = false);
}
});
}
LoadResults Method
void LoadResults(int raceid)
{
var results = new ObservableCollection<Result>();
//Start with the timings
foreach (Timing timing in Timings)
{
var result = new Result();
//Basic details
result.RaceId = RaceId;
result.RaceDate = RaceDate;
result.Status = "Processing";
result.BackgroundColour = "White";
result.ScanTrashVisibility = true;
result.TimingTrashVisibility = true;
//Timing Data
result.TimingId = timing.Id;
result.TimingPosition = timing.Position;
result.TimingStatus = timing.Status;
result.StartTime = timing.StartTime;
result.EndTime = timing.EndTime;
result.TimingBatchCode = timing.BatchCode;
result.TimingBatchPosition = timing.BatchCode + timing.Position.ToString();
var elapsed = result.EndTime - result.StartTime;
string elapsedhours = elapsed.Hours.ToString();
string elapsedminutes = elapsed.Minutes.ToString();
string elapsedseconds = elapsed.Seconds.ToString();
string elapsedmillis;
if (elapsed.Milliseconds.ToString().Length > 2)
{
elapsedmillis = elapsed.Milliseconds.ToString().Substring(0, 2);
}
else
{
elapsedmillis = elapsed.Milliseconds.ToString();
}
if (elapsedhours.Length == 1) { elapsedhours = "0" + elapsedhours; }
if (elapsedminutes.Length == 1) { elapsedminutes = "0" + elapsedminutes; }
if (elapsedseconds.Length == 1) { elapsedseconds = "0" + elapsedseconds; }
if (elapsedmillis.Length == 1) { elapsedmillis = "0" + elapsedmillis; }
if((elapsedhours == "00"))
{
result.Elapsed = elapsedminutes + ":" + elapsedseconds + "." + elapsedmillis;
}
else
{
result.Elapsed = elapsedhours + ":" + elapsedminutes + ":" + elapsedseconds + "." + elapsedmillis;
}
results.Add(result);
}
//Add in the scans
foreach (Result result1 in results)
{
var scan = Scans.Where(p => p.BatchCode == result1.TimingBatchCode)
.FirstOrDefault(p => p.Position == result1.TimingPosition);
if (scan != null)
{
result1.ScanId = scan.Id;
result1.ScanPosition = scan.Position;
result1.ScanStatus = scan.Status;
result1.ScanBibNumber = scan.BibNumber;
result1.ScanBatchCode = scan.BatchCode;
result1.ScanBatchPosition = scan.BatchCode + scan.Position.ToString();
}
else
{
result1.ScanId = 0;
result1.ScanPosition = 0;
result1.ScanStatus = 99;
result1.ScanBibNumber = "UNKNOWN";
result1.AddScanButtonVisibility = true;
result1.ScanBatchCode = result1.TimingBatchCode;
}
}
//Add any scans which there are no times for
var notimescans = new ObservableCollection<Scan>();
foreach (Scan scan in Scans)
{
var checkscan = results.FirstOrDefault(s => s.ScanId == scan.Id);
if (checkscan == null)
{
var newresult = new Result();
newresult.RaceId = RaceId;
newresult.RaceDate = RaceDate;
newresult.Status = "Processing";
newresult.ScanId = scan.Id;
newresult.ScanPosition = scan.Position;
newresult.ScanStatus = scan.Status;
newresult.ScanBibNumber = scan.BibNumber;
newresult.ScanBatchCode = scan.BatchCode;
newresult.ScanBatchPosition = scan.BatchCode + scan.Position.ToString();
newresult.ScanTrashVisibility = true;
newresult.AddTimingButtonVisibility = true;
newresult.TimingId = 0;
newresult.TimingPosition = 99999;
newresult.TimingStatus = 99;
newresult.Elapsed = "N/A";
results.Add(newresult);
}
}
//Then add in the entries
foreach (Result result2 in results)
{
var entry = Entries.FirstOrDefault(p => p.BibNumber == result2.ScanBibNumber);
if (entry != null)
{
result2.EntryId = entry.Id;
result2.FirstName = entry.FirstName;
result2.LastName = entry.LastName;
result2.FormattedName = entry.FirstName + " " + entry.LastName.ToUpper();
result2.Gender = entry.Gender;
result2.DateOfBirth = entry.DateOfBirth;
result2.Club = entry.Club;
result2.Team = entry.Team;
result2.EntryBibNumber = entry.BibNumber;
if (result2.Club == null)
{
result2.FormattedClub = "";
}
else
{
result2.FormattedClub = entry.Club.ToUpper();
}
}
else
{
result2.EntryId = 0;
result2.FirstName = "Unknown";
result2.LastName = "ATHLETE";
result2.FormattedName = entry.FirstName + " " + entry.LastName.ToUpper();
result2.Gender = "Unknown";
result2.DateOfBirth = DateTime.Now;
result2.Club = "";
result2.Team = "";
result2.EntryBibNumber = result2.ScanBibNumber + " (Unrecognised)";
}
if(result2.ScanBatchCode == "NULLBATCH")
{
result2.ScanBatchCode = "Default";
}
if (result2.TimingBatchCode == "NULLBATCH")
{
result2.TimingBatchCode = "Default";
}
}
if(Scans.Count() != Timings.Count())
{
ResultsInvalid = true;
ResultsValidationError = "Your scan count and timing count's don't match. Please continue processing your results until these match and you will then be able to publish.";
}
else
{
Invalid = false;
PublishVisibility = true;
}
var sortedresults = new ObservableCollection<Result>(results.OrderBy(c => c.Elapsed));
int newposition = 1;
foreach (Result sortedresult in sortedresults)
{
sortedresult.OverallPosition = newposition;
newposition = newposition + 1;
}
//Create batches
grouped = new ObservableCollection<GroupedResultModel>();
foreach (Result result in results)
{
GroupedResultModel resultGroup = new GroupedResultModel();
var groupcheck = grouped.FirstOrDefault(b => b.BatchCode == result.ScanBatchCode);
if (groupcheck == null)
{
resultGroup.BatchCode = result.ScanBatchCode;
var BatchOfResults = results.Where(r => r.ScanBatchCode == resultGroup.BatchCode).OrderBy(r => r.Elapsed);
int batchposition = 1;
foreach (Result batchedresult in BatchOfResults)
{
batchedresult.OverallPosition = batchposition;
resultGroup.Add(batchedresult);
batchposition = batchposition + 1;
}
grouped.Add(resultGroup);
}
}
Results = sortedresults;
OnPropertyChanged("Invalid");
}
I have a pdf file as Byte[] and I'm using iTextSharp to modify the file and embed a specific details in it.
in the List I have min. 25K objects, and I need to generate 25K pdf files.
I'm using Parallel.ForEach but it takes 16.40 mins to be done in Total.
I used ToLookUp method like this:
var valuesToLookupWith = Recipients.ToLookup(item => item.ID);
List<int> Ids = Recipients.Select(item => item.ID).ToList();
Partitioner<int> partitioner = Partitioner.Create(Ids, EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitioner, new ParallelOptions { MaxDegreeOfParallelism = 6 } ,(id) =>
{
var item = valuesToLookupWith[id].ToList().FirstOrDefault();
item.Attachment = AttachmentEngine.GeneratePdfFromPdfFile((fileAsByteArray,id, "www.xyz.ca"));
...
});
and I used ForEach and also it takes approx. > 25 minutes.
foreach (int id in Ids)
{
var item = valuesToLookupWith[id].ToList().FirstOrDefault();
item.Attachment = AttachmentEngine.GeneratePdfFromPdfFile(fileAsByteArray,id, "www.xyz.ca");
...
}
any suggested way to speedup the process please?
FYI I'm not writing anything on the disk, all is done in memory as Byte[] and then I'm writing the values back to the Db.
and also all the time spent - mentioned in the question is only the time spent for Parallel.ForEach / ForEach statements.
Db calls is not an issue for me at all, I'm making only two calls to the Db , one when I load list of recipients from it and another call when writing values back to the Db
public static byte[] GeneratePdfFromPdfFile(byte[] file, int id, string landingPage)
{
try
{
using (var ms = new MemoryStream())
{
//Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
var doc = new iTextSharp.text.Document();
//Create a writer that's bound to our PDF abstraction and our stream
var writer = PdfWriter.GetInstance(doc, ms);
//Open the document for writing
doc.Open();
PdfContentByte cb = writer.DirectContent;
// doc.NewPage();
//var srHtml = new StringReader(source);
////parse html code to xml
//iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml);
PdfReader reader = new PdfReader(file);
for (int pageNumber = 1; pageNumber < reader.NumberOfPages + 1; pageNumber++)
{
doc.SetPageSize(reader.GetPageSizeWithRotation(1));
doc.NewPage();
//Insert to Destination on the first page
PdfImportedPage page = writer.GetImportedPage(reader, pageNumber);
int rotation = reader.GetPageRotation(pageNumber);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(pageNumber).Height);
}
else
{
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
}
// Add a new page to the pdf file
doc.NewPage();
// set pdf open action to open the link embedded in the file.
string _embeddedURL = "http://" + landingPage + "/Default.aspx?code=" + GetCampaignRecipientCode(id) + "&m=" + eventCode18;
PdfAction act = new PdfAction(_embeddedURL);
writer.SetOpenAction(act);
doc.Close();
return ms.ToArray();
}
}
catch { return null; }
}
Recipient Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CampaignLauncherLibrary
{
public class CampaignRecipientLib
{
private int _id;
private int _crid;
private string _crcode;
private int _cmpId;
private string _cmpStatus;
private string _email;
private string _firstName;
private string _lastName;
private string _language;
private string _cmpDefaultlanguage;
private bool _isdoubleBarrle;
private DateTime? _scheduled;
private string _offset;
private string _emailTo;
private string _emailFrom;
private string _emailBody;
private string _emailSubject;
private byte[] _emailAttachment;
private string _emailReplyTo;
private string _attachmentName;
private bool _readytobesent;
private bool _pickupready;
private TimeSpan _Toffset;
private int? _cmprIDnextRecipient;
private string _CampaignGroupCode;
private bool _Reschedule;
private List<int> _Campaigns;
private List<int> _SentCampaigns;
private bool _restrictToWorkHours;
private TimeSpan? _whStart;
private TimeSpan? _whEnd;
private string _emailName;
public CampaignRecipientLib()
{
}
public CampaignRecipientLib(CampaignRecipientLib _recipient)
{
ID = _recipient.ID;
CampaignId = _recipient.CampaignId;
CampaignStatus = _recipient.CampaignStatus;
CMPRID = _recipient.CMPRID;
CMPRCode = Guid.NewGuid().ToString("N");
Email = _recipient.Email;
FirstName = _recipient.FirstName;
LastName = _recipient.LastName;
Language = _recipient.Language;
DefaultLanguage = _recipient.DefaultLanguage;
IsdoubleBarrle = _recipient.IsdoubleBarrle;
Scheduled = _recipient.Scheduled;
Offset = _recipient.Offset;
EmailTo = _recipient.EmailTo;
EmailFrom = _recipient.EmailFrom;
EmailBody = _recipient.EmailBody;
EmailSubject = _recipient.EmailSubject;
EmailAttachment = _recipient.EmailAttachment;
EmailReplyTo = _recipient.EmailReplyTo;
AttachmentName = _recipient.AttachmentName;
ReadyTobeSent = _recipient.ReadyTobeSent;
PickupReady = _recipient.PickupReady;
IDnextRecipient = _recipient.IDnextRecipient;
CampaignGroupCode = _recipient.CampaignGroupCode;
Reschedule = _recipient.Reschedule;
Campaigns = _recipient.Campaigns;
SentCampaigns = _recipient.SentCampaigns;
EmailName = _recipient.EmailName;
Toffset = _recipient.Toffset;
}
public void AssingRandomCampaign()
{
int result = 0;
List<int> cmp = _Campaigns;
List<int> sentcmp = _SentCampaigns;
if (cmp.Where(x => !sentcmp.Distinct().Contains(x)).ToList().Count > 0)
{
cmp = cmp.Where(x => !sentcmp.Distinct().Contains(x)).ToList();
result = cmp.Shuffle().Take(1).ToList()[0];
}
else
{
int N = 0;
if (sentcmp.Count == 2) N = 1;
else if (sentcmp.Count == 3) N = 2;
else N = sentcmp.Count % 2 == 0 ? 2 : 3;
List<int> lastN = sentcmp.Skip(Math.Max(0, sentcmp.Count) - N).ToList();
cmp = cmp.Where(predicate: x => !lastN.Contains(x)).ToList();
sentcmp = sentcmp.Where(predicate: x => cmp.Contains(x)).ToList();
List<int> grpOccurrences = sentcmp.GroupBy(i => i).OrderByDescending(item => item.Count()).SelectMany(i => i).Distinct().ToList();
result = grpOccurrences.Shuffle().PickRandom(1).ToList()[0];
}
if (result > 0)
{
_SentCampaigns.Add(result);
CampaignId = result;
}
}
public bool reAdjustScheduleDate()
{
try
{
Scheduled = Utilities.FixDate(Scheduled.Value, RestrictToWorkHours, Offset, WhStart, WhEnd);
}
catch (Exception ex)
{
return false;
}
return true;
}
public TimeSpan Toffset
{
get { return _Toffset; }
set { _Toffset = value; }
}
public string EmailName
{
get { return _emailName; }
set { _emailName = value; }
}
public int? IDnextRecipient
{
get { return _cmprIDnextRecipient; }
set { _cmprIDnextRecipient = value; }
}
public string CampaignGroupCode
{
get { return _CampaignGroupCode; }
set { _CampaignGroupCode = value; }
}
public bool RestrictToWorkHours
{
get { return _restrictToWorkHours; }
set { _restrictToWorkHours = value; }
}
public TimeSpan? WhStart
{
get { return _whStart; }
set { _whStart = value; }
}
public TimeSpan? WhEnd
{
get { return _whEnd; }
set { _whEnd = value; }
}
public bool Reschedule
{
get { return _Reschedule; }
set { _Reschedule = value; }
}
public List<int> Campaigns
{
get { return _Campaigns; }
set { _Campaigns = value; }
}
public List<int> SentCampaigns
{
get { return _SentCampaigns; }
set { _SentCampaigns = value; }
}
public int ID
{
get { return _id; }
set { _id = value; }
}
public int CMPRID
{
get { return _crid; }
set { _crid = value; }
}
public string CMPRCode
{
get { return _crcode; }
set { _crcode = value; }
}
public int CampaignId
{
get { return _cmpId; }
set { _cmpId = value; }
}
public string CampaignStatus
{
get { return _cmpStatus; }
set { _cmpStatus = value; }
}
public string Email
{
get { return _email; }
set { _email = value; }
}
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
public string Language
{
get { return _language; }
set { _language = value; }
}
public string DefaultLanguage
{
get { return _cmpDefaultlanguage; }
set { _cmpDefaultlanguage = value; }
}
public bool IsdoubleBarrle
{
get { return _isdoubleBarrle; }
set { _isdoubleBarrle = value; }
}
public DateTime? Scheduled
{
get { return _scheduled; }
set { _scheduled = value; }
}
public string EmailTo
{
get { return _emailTo; }
set { _emailTo = value; }
}
public string Offset
{
get { return _offset; }
set { _offset = value; }
}
public string EmailFrom
{
get { return _emailFrom; }
set { _emailFrom = value; }
}
public string EmailBody
{
get { return _emailBody; }
set { _emailBody = value; }
}
public string EmailSubject
{
get { return _emailSubject; }
set { _emailSubject = value; }
}
public byte[] EmailAttachment
{
get { return _emailAttachment; }
set { _emailAttachment = value; }
}
public string EmailReplyTo
{
get { return _emailReplyTo; }
set { _emailReplyTo = value; }
}
public string AttachmentName
{
get { return _attachmentName; }
set { _attachmentName = value; }
}
public bool ReadyTobeSent
{
get { return _readytobesent; }
set { _readytobesent = value; }
}
public bool PickupReady
{
get { return _pickupready; }
set { _pickupready = value; }
}
}
}
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;
}
I am trying to build a combo list for a program to fill the combobox with a list of applications. it keeps throwing up "Cannot bind to the new display member. Parameter name: newDisplayMember"
private void BuildComboList()
{
Applicant defaultApplicant = new Applicant();
applicationList = defaultApplicant.GetList();
applicantList.DataSource = applicationList;
applicantList.DisplayMember = "DisplayName";
applicantList.ValueMember = "DisplayValue";
}
Applicant Class
public class Applicant
{
//Members
private int applicant_ID;
private string applicant_fname;
private string applicant_lname;
private string applicant_phone;
private string applicant_address1;
private string applicant_address2;
private string applicant_city;
private string applicant_state;
private string applicant_zip;
private string applicant_email;
//properties
public int Applicant_ID
{
get { return applicant_ID; }
set { applicant_ID = value; }
}
public string Applicant_fname
{
get { return applicant_fname; }
set { applicant_fname = value; }
}
public string Applicant_lname
{
get { return applicant_lname; }
set { applicant_lname = value; }
}
public string Applicant_phone
{
get { return applicant_phone; }
set { applicant_phone = value; }
}
public string Applicant_address1
{
get { return applicant_address1; }
set { applicant_address1 = value; }
}
public string Applicant_address2
{
get { return applicant_address2; }
set { applicant_address2 = value; }
}
public string Applicant_city
{
get { return applicant_city; }
set { applicant_city = value; }
}
public string Applicant_state
{
get { return applicant_state; }
set { applicant_state = value; }
}
public string Applicant_zip
{
get { return applicant_zip; }
set { applicant_zip = value; }
}
public string Applicant_email
{
get { return applicant_email; }
set { applicant_email = value; }
}
//Constructors
private void DefaultValues()
{
applicant_ID = 0;
applicant_fname = "";
applicant_lname = "";
applicant_phone = "";
applicant_address1 = "";
applicant_address2 = "";
applicant_city = "";
applicant_state = "";
applicant_zip = "";
applicant_email = "";
}
private void Rec2Members(ApplicantRecord record)//defined in ApplicantDL
{
applicant_ID = record.applicant_ID;
applicant_fname = record.applicant_fname;
applicant_lname = record.applicant_lname;
applicant_phone = record.applicant_phone;
applicant_address1 = record.applicant_address1;
applicant_address2 = record.applicant_address2;
applicant_city = record.applicant_city;
applicant_state = record.applicant_state;
applicant_zip = record.applicant_zip;
applicant_email = record.applicant_email;
}
public ApplicantRecord ToRecord()
{
ApplicantRecord record = new ApplicantRecord();
record.applicant_ID = applicant_ID;
record.applicant_fname = applicant_fname;
record.applicant_lname = applicant_lname;
record.applicant_phone = applicant_phone;
record.applicant_address1 = applicant_address1;
record.applicant_address2 = applicant_address2;
record.applicant_city = applicant_city;
record.applicant_state = applicant_state;
record.applicant_zip = applicant_zip;
record.applicant_email = applicant_email;
return record;
}
public List<ApplicantRecord> GetList()
{
return Approval_Form.ApplicantRecord.ApplicantDL.GetList();
}
public void Insert()
{
applicant_ID = Approval_Form.ApplicantRecord.ApplicantDL.Insert(applicant_fname, applicant_lname, applicant_phone, applicant_address1, applicant_address2, applicant_city, applicant_state, applicant_zip, applicant_email);
}
public void Select(int applicant_ID)
{
ApplicantRecord record = Approval_Form.ApplicantRecord.ApplicantDL.Select(applicant_ID);
Rec2Members(record);
}
public void Update()
{
if (applicant_ID != 0)
{
Approval_Form.ApplicantRecord.ApplicantDL.Update(applicant_ID, applicant_fname, applicant_lname, applicant_phone, applicant_address1, applicant_address2, applicant_city, applicant_state, applicant_zip, applicant_email);
}
}
}
I think it should be:
private void BuildComboList()
{
Applicant defaultApplicant = new Applicant();
applicationList = defaultApplicant.GetList();
applicantList.DataSource = applicationList;
applicantList.DisplayMember = "Applicant_fname";
applicantList.ValueMember = "Applicant_ID";
}
You can change the applicant class further as follows:
Add two properties.
public string DisplayName
{
get { return (applicant_fname + " " + applicant_lname; }
}
public string DisplayValue
{
get { return (applicant_ID.ToString(); }
}
Keep data binding as:
private void BuildComboList()
{
Applicant defaultApplicant = new Applicant();
applicationList = defaultApplicant.GetList();
applicantList.DataSource = applicationList;
applicantList.DisplayMember = "DisplayName";
applicantList.ValueMember = "DisplayValue";
}
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);
}