I'm using lazy load for "relationship" properties and struggling when saving object because when I check to see if everything is OK before saving, the properties I'm checking get loaded from the db, losing the object's "saving" status.
Consider this pseudo-code:
public class Project
{
private int _ProjectId;
private string _ProjectName;
private ProjectType _ProjectType;
public int ProjectId
{
get { return _ProjectId; }
set { _ProjectId = value; }
}
public string ProjectName
{
get { return _ProjectName; }
set { _ProjectName = value; }
}
public ProjectType ProjectType
{
get
{
if (_ProjectId != 0 && _ProjectType == null)
{
... load _Projectype from db here
}
return _ProjectType;
}
set
{
_ProjectType = value;
}
}
public Project Save()
{
if(this.ProjectType != null) // <<-- if the _projectId is != 0 (typically during updates or delete operations, the prop is loaded from the db!!!
adpt.Save(this);
}
}
When the control is inside the class, I can of course reference the private member to avoid dynamic loading, but what if someone use the object from the outside? A simple test "if(Prj.ProjectType != null)" will inadvertently load the property.
It seems I need a state to inhibit the loading during saving operation and I was wondering if there is a pattern out there to help me.
Many thanks, Antonio
Related
I've created a new configuration file Special.config:
<?xml version="1.0" encoding="utf-8"?>
<SpecialConfig xmlns:config="urn:telerik:sitefinity:configuration" xmlns:type="urn:telerik:sitefinity:configuration:type" config:version="10.0.6401.0">
<UnicornSettings HornSize="#{HornSize}" HoofColor="#{HoofColor}" />
</SpecialConfig>
Then followed the documentation to set up a pair of classes (and register the config in the Global.asax.cs) file:
public class SpecialConfig : ConfigSection
{
public UnicornSettingsElement UnicornSettings
{
get
{
return (UnicornSettingsElement)this["UnicornSettings"];
}
set
{
this["UnicornSettings"] = value;
}
}
}
public class UnicornSettingsElement : ConfigElement
{
public UnicornSettingsElement(ConfigElement parent) : base(parent)
{
}
public String HornSize
{
get
{
return (String)this["HornSize"];
}
set
{
this["HornSize"] = value;
}
}
public String HoofColor
{
get
{
return (String)this["HoofColor"];
}
set
{
this["HoofColor"] = value;
}
}
}
But even after explicitly instantiating SpecialConfig.UnicornSettings, it's still null:
UnicornSettings config = Config.Get<UnicornSettings>();
config.UnicornSettings = new UnicornSettingsElement(config);
config.UnicornSettings.HornSize = HornSize; //<-- config.UnicornSettings is null
config.UnicornSettings.HoofColor = HoofColor;
ConfigManager manager = ConfigManager.GetManager();
manager.SaveSection(config);
I have no idea how to overcome this particular exception where the reference is null immediately after being set. Anyone see what I'm missing?
Update
After further fiddling, I think there's something wrong with the getter or setter on the SpecialConfig.UnicornSettings... I'm not sure what that could be though.
DISCLAIMER
I understand what a null reference exception is, and generally speaking how to identify and overcome a null reference exception. This is not a duplicate of a particular C# question whose answer is a very non-specific book of information. This is a particular and precise case involving a specific framework that warrants its own question.
Forgot the ConfigurationProperties. I'm guessing these are necessary for the way the getter/setter accesses properties:
public class SpecialConfig : ConfigSection
{
[ConfigurationProperty("UnicornSettings")]
public UnicornSettingsElement UnicornSettings
{
get
{
return (UnicornSettingsElement)this["UnicornSettings"];
}
set
{
this["UnicornSettings"] = value;
}
}
}
public class UnicornSettingsElement : ConfigElement
{
public UnicornSettingsElement(ConfigElement parent) : base(parent)
{
}
[ConfigurationProperty("HornSize", IsRequired = true)]
public String HornSize
{
get
{
return (String)this["HornSize"];
}
set
{
this["HornSize"] = value;
}
}
[ConfigurationProperty("HoofColor", IsRequired = true)]
public String HoofColor
{
get
{
return (String)this["HoofColor"];
}
set
{
this["HoofColor"] = value;
}
}
}
This may be trivial. But I could not able to get my heads over this.
public class Manager
{
public int ID { get; set; }
public List<Employee> Employees { get; set; }
public bool IsAllEmpEngaged { get; set; }
public void UpdateIsAllEmpEngaged()
{
IsAllEmpEngaged = Employees.All(emp => emp.IsEngagedwithWork == true);
}
}
public class Employee
{
public int ID { get; set; }
public bool IsEngagedwithWork { get; set; }
}
So, Whenever, the IsEngagedwithWork of Employee is setted with some value, I want to check whether all the Employees under aManager is Engaged with work or not and update the value of IsAllEmpEngaged of the respective Manager.
I just want to call UpdateIsAllEmpEngaged on changes in property IsEngagedwithWork of Employee. How can I achieve this?
Any other ways are also welcome.
Note: I tried with a having an event on Employee and attach Action from the Manager that will callback if any changes in Employee property. But I will be having hundreds of List<Manager>. I dont want to add event for each and every instance of Employee class. Any easy way?
Update:
I am working with WPF MVVM approach, I cannot use direct get with LinQ as it will not notify the UI. I have to set the property manually for change so that it will Notify the UI.
Also, In actual case, the IsEngagedwithWork will be updated in UI for the property IsEngagedwithWork.
Simple solution is add ManagerId as well to the Employee model class and after your line of code that sets IsEngagedwithWork of the employee instance (say emp), do the below thing
Manager mngr = managers.Select(m => m.ID == emp.ManagerId).FirstOrDefault();
if(mngr != null)
mngr.IsAllEmpEngaged = mngr.IsAllEmpEngaged && emp.IsEngagedwithWork;
I'd use the getter of the property like that
public bool IsAllEmpEngaged {
get {
return (Employees != null) &&
Employees.All(e => e.IsEngagedwithWork)
}
}
and you add the following method for the Manager Class
public void NotifyChanged() { OnPropertyChanged(() => IsAllEmpEngaged }
then you call it from the Employee Class (assuming you have the managers' list or an equivalent way)
private int _ID;
private bool _IsEngagedwithWork;
public int ID {
get { return _ID};
set {
_ID = value;
OnPropertyChanged(()=>ID );
notifyMe = managerList.FirstOrDefualt(m => m.ID == _ID);
if (notifyMe != null) { notifyMe.NotifyChanged()}
}
}
public bool IsEngagedwithWork {
get { return _IsEngagedwithWork ;}
set {
_IsEngagedwithWork = value;
OnPropertyChanged(()=>IsEngagedwithWork );
notifyMe = managerList.FirstOrDefualt(m => m.ID == _ID);
if (notifyMe != null) { notifyMe.NotifyChanged()}
}
}
What i would do :
make IsAllEmpEngaged private
make the collection Empoyess private and add a function that add a new employee:
Add a function that adds a new employee.
And now two choiches :
1) after the employee is added, iterate the collection and update the IsAllEmpEngaged property
public void AddNewEmployee(Employee employee){
this.Employees.Add(employee);
bool all = true;
foreach(Employee emp in this.Employees){
if (!emp.IsEngagedwithWork){
all = false;
break;
}
}
this.IsAllEmpEngaged = all;
}
2)
start with IsAllEmpEngaged = true; when the class is inited and the collection is empty
when the employee is added, update the IsAllEmpEngaged property but keeping count of the last choice (this works only if you don't remove employess)
public void AddNewEmployee(Employee employee){
this.Employees.Add(employee);
this.IsAllEmpEngaged = this.IsAllEmpEngaged && employee.IsEngagedwithWork
}
I can't say that this is any better, but surely this is a simple and easy way.
Why not just make IsAllEmpEngaged a method? You don't even need the set property accessor, so a method should suffice.
public bool IsAllEmpEngaged()
{
if (Employees == null)
{
// throw error
}
return Employees.All(e => e.IsEngagedwithWork);
}
Maybe it work's when you pass your Manager as parameter to Employee and then call your Method if IsEngagedWithWork is set to true.
public class Employee
{
private Manager _parentManager;
public Employee(Manager parentManager)
{
_parentManager=parentManager;
}
public int ID { get; set; }
private bool _isEngangedWithWork;
public bool IsEngagedwithWork
{
get{ return _isEngangedWithWork; }
set
{
_isEngangedWithWork=value;
if(_isEngangedWithWork)
_parentManager.UpdateIsAllEmpEngaged();
}
}
}
I'm currently working on a solution that has a set of composite ViewModels that are mapped from domain models coming back from a set of data access services.
So far I've had a good amount of success with implementing INotifyPropertyChanged on the base ViewModel object and notifying the UI of changes to the property objects via property changed events.
Here's an example of a view model:
public class DisplayDataModel : INotifyPropertyChanged{
private DateTime _lastRefreshTime;
public DateTime LastRefreshTime {
get { return _lastRefreshTime; }
set {
_lastRefreshTime = value;
this.NotifyPropertyChanged(lddm => lddm.LastRefreshTime, PropertyChanged);
}
}
private string _lineStatus;
public string LineStatus {
get { return _lineStatus; }
set {
if (_lineStatus != value) {
_lineStatus = value;
this.NotifyPropertyChanged(lddm => lddm.LineStatus, PropertyChanged);
}
}
}
private ProductionBrickModel _productionBrick;
public ProductionBrickModel ProductionBrick {
get { return _productionBrick;}
set {
if (_productionBrick != value) {
_productionBrick = value;
this.NotifyPropertyChanged(lddm => lddm.ProductionBrick, PropertyChanged);
}
}
}
}
public class ProductionBrickModel{
public int? Set { get; set; }
public int? Theoretical { get; set; }
public int? Actual { get; set; }
public string LineName { get; set; }
public TimeSpan? ShiftOverage { get; set; }
public SolidColorBrush ShiftOverageBrush {
get {
if (ShiftOverage.HasValue && ShiftOverage.Value.Milliseconds < 0) {
return Application.Current.FindResource("IndicatorRedBrush") as SolidColorBrush;
}
return Application.Current.FindResource("IndicatorWhiteBrush") as SolidColorBrush;
}
}
public string ShiftOverageString { get { return ShiftOverage.HasValue ? ShiftOverage.Value.ToShortTimeSpanString() : ""; } }
}
So currently I'm firing notification events on the base model and not the production brick property, mostly because the production brick properties will be changing almost every refresh anyways.
Recently I've started cranking refresh times down to around 350ms and I'm seeing situations where the ShiftOverageBrush is changing to white for a split second even though the values are still negative.
My question is by going through and implementing INotifyPropertyChanged on the object types that make up the base view model will I gain any performance, or even possibly solve this issue? Or is this coming from something else entirely that I'm not understanding?
There are two obvious sources of inefficieny in your code:
1) ShiftOverageBrush is using FindResource every time it's called. Why not cache the brushes?
private SolidColorBrush _redBrush;
private SolidColorBrush IndicatorRedBrush
{
get{ return _redBrush ?? (_redBrush =
Application.Current.FindResource("IndicatorRedBrush") as SolidColorBrush));
}
... same for white brush
public SolidColorBrush ShiftOverageBrush {
get {
if (ShiftOverage.HasValue && ShiftOverage.Value.Milliseconds < 0) {
return IndicatorRedBrush;
}
return IndicatorWhiteBrush;
}
}
2) Using a lambda expression for NotifyPropertyChanged is convenient but is pretty slow since it uses reflection. If you're cranking up the update rate, then replace the lambdas with strings.
As is well known, CM doesn't support passing a object of complex type through NavigationService like MVVM Light. So I searched for a workaround and did it like this.
There are two viewmodels: MainPageViewModel and SubPageViewModel.
I first defined 3 classes, namely GlobalData, SnapshotCache and StockSnapshot. StockSnapshot is the type of which the object I want to pass between the 2 viewmodels.
public class SnapshotCache : Dictionary<string, StockSnapshot>
{
public StockSnapshot GetFromCache(string key)
{
if (ContainsKey(key))
return this[key];
return null;
}
}
public class GlobalData
{
private GlobalData()
{
}
private static GlobalData _current;
public static GlobalData Current
{
get
{
if (_current == null)
_current = new GlobalData();
return _current;
}
set { _current = value; }
}
private SnapshotCache _cachedStops;
public SnapshotCache Snapshots
{
get
{
if (_cachedStops == null)
_cachedStops = new SnapshotCache();
return _cachedStops;
}
}
}
public class StockSnapshot
{
public string Symbol { get; set; }
public string Message { get; set; }
}
Next, I call the navigation service on MainPageViewModel like this:
StockSnapshot snap = new StockSnapshot {Symbol="1", Message = "The SampleText is here again!" };
GlobalData.Current.Snapshots[snap.Symbol] = snap;
NavigationService.UriFor<SubPageViewModel>().WithParam(p=>p.Symbol,snap.Symbol).Navigate();
And on SubPageViewModel I've got this:
private string _symbol;
public string Symbol
{
get { return _symbol; }
set
{
_symbol = value;
NotifyOfPropertyChange(() => Symbol);
}
}
public StockSnapshot Snapshot
{
get { return GlobalData.Current.Snapshots[Symbol]; }
}
And that's where the problem lies. When I run the program, I find out that it always runs to the getter of Snapshot first, when Symbol hasn't been initialized yet. So later I've tried adding some extra code to eliminate the ArgumentNullException so that it can run to the setter of Symbol and then everything goes fine except that the UI doesn't get updated anyway.
Could anyone tell me where I've got wrong?
Thx in advance!!
Why not just use:
private string _symbol;
public string Symbol
{
get { return _symbol;}
set
{
_symbol = value;
NotifyOfPropertyChange(() => Symbol);
NotifyOfPropertyChange(() => Snapshot);
}
}
public StockSnapshot Snapshot
{
get { return Symbol!=null? GlobalData.Current.Snapshots[Symbol]:null; }
}
In this case you don't try and get the data from GlobalData when Symbol is null (sensible approach anyway!) and when "Symbol" is set you call NotifyOfPropertyChange() on Snapshot to force a re-get of the property.
Which control approach can i use to quickly provide visual editing of my List collection.
The in-memory collection I have is below.
My requirements are basically to:
provide a means on my winform form, to allow add/view/edit of the List of ConfigFileDTO information, BUT
Only the "PATH" field of the ConfigFileDTO needs to be made a available to the user, therefore the use could:
add a new PATH to the list,
delete PATHs, hence deleting the ConfigFileDTO from the list,
and edit the list, allowing one of the PATH's in the list to be changed.
My code
private static List<ConfigFileDTO> files;
public class ConfigFileDTO
{
private string filename, content_type, path;
private int file_size;
private DateTime updated_at;
public ConfigFileDTO() { }
public int FileSize {
get { return this.file_size; }
set { this.file_size = value; }
}
public string ContentType {
get { return this.content_type; }
set { this.content_type = value; }
}
public string Filename {
get { return this.filename; }
set { this.filename = value; }
}
public DateTime UpdatedAt {
get { return this.updated_at; }
set { this.updated_at = value; }
}
public string Path {
get { return this.path; }
set { this.path = value; }
}
}
Thanks
If you only want the Path column to be manipulated, then it is usually better to simply set up the column bindings (for things like DataGridView) manually; however, you can also use things like [Browsable(false)] (removes a property from display) and [ReadOnly(true)] (treat a property as read-only even if it has a setter) to control how properties (/columns) are handled.
If you want to control how new instances are created, inherit from BindingList<T> and override AddNewCore().