Cache class objects - c#

My project is WPF application.
I have a class for example Products having multiple properties(string , int, List<>). I am looking to cache this object in memory (not in file), and use it.
Also looking for event raised when cache object is updated similarly as HostFileChangeMonitor.
The reason why I am looking for above solution is:
I have to send current object to third party dll (which is on timer of 5 sec) and it is heavy object which hampering performance of GUI.
Hence by caching class object, I will monitor to call this heavy operation ONLY WHEN cache object is updated.
I already thought to save object properties value to txt file and use HostFileChangeMonitor to trigger event, but this will add one more IO operation.
Please share if any inputs?

Thanks all to view my question. Finally I got working code with time specific memory cache.
Posting it may be it is useful for someone like me. It is explained with an example.
private MemoryCache mc = new MemoryCache("CacheProvider"); // Creating memory cache object.
public MainWindow()
{
InitializeComponent();
}
// Method to get cache elements.
private void GetCache_Click(object sender, RoutedEventArgs e)
{
lstEmployeeID.Items.Clear();
lstEmployeeName.Items.Clear();
var emp = new Employee();
foreach (Employee emp1 in emp.GetEmployeeList())
{
var cacheObj = mc[emp1.EmployeeName] as Employee; // typecasting it class object.
if (cacheObj != null)
{
lstEmployeeID.Items.Add(cacheObj.EmployeeId);
lstEmployeeName.Items.Add(cacheObj.EmployeeName);
}
}
}
// Saving class object to cache.
private void SaveCache_Click(object sender, RoutedEventArgs e)
{
var emp = new Employee();
var policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10.0);
foreach (Employee emp1 in emp.GetEmployeeList())
{
mc.Add(emp1.EmployeeName, emp1, policy); // adding (key, objectItem, CachingPolicy)
}
}

Related

Measure the time a person has gazed at multiple objects

I'm trying to create an UWP app that measure's the time a person has gazed at multiple objects. There are around 300 objects and they all need to measure the time and display that in a text file. I've succesfully coded this for just one object, but I do not know how I am able to do this with multiple ones. I saw this post How to create 300 stopwatches in C# more efficiently? and the answer to that helped me quite a lot, but the code does not implement well with my code. So I like the idea of creating a list of objects and then when the person has gazed in object [o] then the corresponding stopwatch will start when the eyes have entered the object, and stop when the eyes have left the object. Problem is as I mentioned already, the solution does not work well with the code I am working with. This is the code that I used that works for just one element.
public sealed partial class BlankPage1 : Page
{
private GazeElement gazeButtonControl;
private GazePointer gazePointer;
public BlankPage1()
{
this.InitializeComponent();
Stopwatch Timer = new Stopwatch();
gazePointer = GazeInput.GetGazePointer(null);
gazeButtonControl = GazeInput.GetGazeElement(GazeBlock);
gazeButtonControl = new GazeElement();
GazeInput.SetGazeElement(GazeBlock, gazeButtonControl);
gazeButtonControl.StateChanged += GazeButtonControl_StateChanged;
void GazeButtonControl_StateChanged(object sender, StateChangedEventArgs ea)
{
if (ea.PointerState == PointerState.Enter)
{
Timer.Start();
}
if (ea.PointerState == PointerState.Exit)
{
Timer.Stop();
CreateStatistics();
}
}
void CreateStatistics()
{
File.WriteAllText(#"C:\Users\Vincent Korpelshoek\AppData\Local\Packages\app.a264e06e2-5084-4424-80a9-bee5f5fbb6b6_8wekyb3d8bbwe\LocalState\Resultaten.txt", Timer.Elapsed.ToString(););
}
}
}
The "GazeBlock" is the name of the first object that has been created in the XAML file. So long story short, I'd like to implement this solution:
static Dictionary<object, Stopwatch> stopwatchesByObject;
static void Main(string[] args)
{
List<object> objects = new List<object>();
// now you have to fill the objects list...
stopwatchesByObject = new Dictionary<object, Stopwatch>();
foreach (var o in objects)
{
stopwatchesByObject.Add(o, new Stopwatch());
}
}
// Call this method when the user starts gazing at object o
static void StartGazingAt(object o)
{
stopwatchesByObject[o].Start();
}
// Call this method when the user stops gazing at object o
static void StopGazingAt(object o)
{
stopwatchesByObject[o].Stop();
}
static void CreateStatistics()
{
StringBuilder sb = new StringBuilder();
foreach (var entry in stopwatchesByObject)
{
sb.AppendLine($"Gazed at {entry.Key.ToString()} for {entry.Value.Elapsed.TotalSeconds} seconds.");
}
File.WriteAllText("c:\\temp\\statictics.txt", sb.ToString());
}
But I do not know how to 'merge' these two together so the solution not only works for just one object, but for around 300 of them. If anyone knows how to help me to make this work, thank you!
Vincent
It seems that for each object you create, you need to add it to the dictionary (along with a new Stopwatch), then add the GazeButtonControl_StateChanged event handler to it (you could add this same event handler to all of the controls), then in that event handler you would reference the correct stopwatch by using the sender argument: stopwatchesByObject[sender].Start();
This may not be exactly correct, but here's what I think you'd need to do to merge the two pieces of code:
public sealed partial class BlankPage1 : Page
{
private GazeElement gazeButtonControl;
private GazePointer gazePointer;
static Dictionary<object, Stopwatch> stopwatchesByObject;
public BlankPage1()
{
this.InitializeComponent();
gazePointer = GazeInput.GetGazePointer(null);
gazeButtonControl = GazeInput.GetGazeElement(GazeBlock);
gazeButtonControl = new GazeElement();
GazeInput.SetGazeElement(GazeBlock, gazeButtonControl);
gazeButtonControl.StateChanged += GazeButtonControl_StateChanged;
// Add the object to our dictionary along with a new stopwatch
stopwatchesByObject.Add(gazeButtonControl, new Stopwatch());
private void GazeButtonControl_StateChanged(object sender, StateChangedEventArgs ea)
{
// Use the sender argument to choose the correct timer
if (ea.PointerState == PointerState.Enter)
{
if (stopwatchesByObject.ContainsKey(sender))
{
stopwatchesByObject[sender].Start();
}
}
else if (ea.PointerState == PointerState.Exit)
{
if (stopwatchesByObject.ContainsKey(sender))
{
stopwatchesByObject[sender].Stop();
CreateStatistics();
}
}
}
private void CreateStatistics()
{
StringBuilder sb = new StringBuilder();
foreach (var entry in stopwatchesByObject)
{
sb.AppendLine($"Gazed at {entry.Key} for {entry.Value.Elapsed.TotalSeconds} seconds.");
}
File.WriteAllText("c:\\temp\\statictics.txt", sb.ToString());
}
}
}
#Vincent perhaps it would be worth looking at this in a different way.
With eye tracking the user can only look at one location on the screen at any point in time, so unless your objects are layered overtop of each other in 2D space or potentially aligned in the line of sight in 3D space, you may only be interested in timing the length of time the users gaze point stays in the current topmost object. One stopwatche might be sufficient to keep track of the time from OnEnter to OnExit for the active object.
If on the OnExit you add the duration of time for that particular gaze interaction to lastGazedObject's cumulative time count, you probably do not need to (or want to) manage 300 stopwatches and can likely just reuse the same stopwatch each time the user's gaze enters an object then leaves the object. As it leaves one object the very next gaze point will either fall on another object or on empty space with no object.
Have you taken a look at this sample ?
It has many of the pieces for determining how long the gaze remains in a single object, with some additional logic to track the lastGazedObject you might be able to accomplish what you are after without managing a whole bunch of stopwatches or timers.
However, even if the scenario that you are trying to solve for does approach the problem like a ray cast that could be intersecting more than one object at a time (due to overlay or alignment in space) it should still be easy to have one long running stop watch and just keep track of a flag property for each object of UserIsGazingAt along with when the GazeAtStarted, then calculate the duration as soon as the gaze moves away from the object and add the duration to the objects total duration.
HTH

Reload Data every time I navigate to Page

I have this Windows Phone Page where I load data through the standard ViewModel scope.
public Profile()
{
InitializeComponent();
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.PersonalizedViewModel.IsDataLoaded)
{
App.PersonalizedViewModel.LoadData();
}
}
This works fine. However when I navigate to this page from some other page the data is still the same. I mean the LoadData() method should recheck updated data right? Please suggest.
EDIT:
My PersonalizedViewModelClass:
public class PersonalizationViewModel: INotifyPropertyChanged
{
public PersonalizationViewModel()
{
this.favorites = new ObservableCollection<ItemViewModel>();
this.Bar = new ObservableCollection<Bars>();
}
public ObservableCollection<ItemViewModel> favorites { get; private set; }
public ObservableCollection<Bars> Bar { get; private set; }
private string _sampleProperty = "Sample Runtime Property Value";
public string SampleProperty
{
get
{
return _sampleProperty;
}
set
{
if (value != _sampleProperty)
{
_sampleProperty = value;
NotifyPropertyChanged("SampleProperty");
}
}
}
public bool IsDataLoaded
{
get;
private set;
}
/// <summary>
/// Creates and adds a few ItemViewModel objects into the Items collection.
/// </summary>
public async void LoadData()
{
favorites.Clear();
try
{
var query = ParseObject.GetQuery("Favorite")
.WhereEqualTo("user", ParseUser.CurrentUser.Username);
IEnumerable<ParseObject> results = await query.FindAsync();
this.favorites.Clear();
foreach (ParseObject result in results)
{
string venue = result.Get<string>("venue");
string address = result.Get<string>("address");
string likes = result.Get<string>("likes");
string price = result.Get<string>("price");
string contact = result.Get<string>("contact");
this.favorites.Add(new ItemViewModel { LineOne=venue, LineTwo=address, LineThree=likes, Rating="", Hours="", Contact=contact, Price=price, Latitude="", Longitude="" });
}
if (favorites.Count == 0)
{
// emailPanorama.DefaultItem = emailPanorama.Items[1];
MessageBox.Show("You do not have any saved cafes. Long press a cafe in main menu to save it.");
}
}
catch (Exception exc)
{
MessageBox.Show("Data could not be fetched!", "Error", MessageBoxButton.OK);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Implementation of PersonalizedViewModel:
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
await App.PersonalizedViewModel.LoadData();
user_tb.Text = ParseUser.CurrentUser.Username;
if (NavigationContext.QueryString.ContainsKey("item"))
{
var index = NavigationContext.QueryString["item"];
var indexParsed = int.Parse(index);
mypivot.SelectedIndex = indexParsed;
}
if (NavigationService.BackStack.Any())
{
var length = NavigationService.BackStack.Count() - 1;
var i = 0;
while (i < length)
{
NavigationService.RemoveBackEntry();
i++;
}
}
}
I don't see the problem, however, I think you need to narrow in on the problem.
First off, you are calling LoadData from 2 places. 1 from MainPage_Load and 1 from OnNavigatedTo. In MainPage_Load it is conditional and in OnNavigatedTo it is always being called. I suggest that you get to a single path through the code instead of 2 so that you don't get different experiences. I personally recommend (without knowing all the details) that you call load data from OnNavigatedTo instead of MainPage_Load. If you want to do it conditionally that is fine but if you are loading the data from memory, it really is unnecessary as you won't improve performance anymore than a few milliseconds. Also, if you are not loading from memory, you may not want to load it conditionally because the underlying data may have changed. In either case, the choice to load data or not should be moved out of the view and into the data layer (but that is for another post).
Once you have a single path chosen (i.e. calling LoadData from MainPage_Load or OnNavigatedTo) you should use your debugger. Put a break point in LoadData method and if it is being called appropriately, then your problem is more specific than your posted question. Here are some questions to think about (you may want to start from the last question and work your way backward)
Questions:
Is LoadData being called appropriately?
Does ParseObject have the correct data?
Is the ParseUser...UserName set properly?
Is the foreach being executed the proper # of times (i.e. does the result of your query have the right # of items?)
Couple Code Tips completely unrelated to this problem:
Single Path through code. Don't call LoadData from more than one place.
Don't call favorites.clear() twice in the same method. (it is called twice in LoadData)
Consistent naming. favorites is lowercase but Bar is upper case.
User proper data types. On your ItemViewModel you have Hours, Latitude, and Longitude. You have them as strings. These clearly are not strings. Also, you should not set them to empty. Empty means they have been set to a value. Emtpy is a valid value. Null means not set. To keep your objects clean and accurate you want to be accurate in how you set things and then deal appropriately with the impact. If you really really want them to be initialized to empty strings, then at least do it in the constructor of ItemViewModel so that every caller doesn't have to know how to initialize every property. I guarantee this is leading to buggy code if you continue using this practice.
Please take the comments as constructive criticism not criticism. I know many people don't like to hear these things but the teams I lead write bugs until they start following these types of guidelines.
Good luck,
Tom
Instead of defining this
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
into constructor i.e. Profile I would suggest remove this code from Constructor and add it into your OnNavigatedTo. so the data will load after navigation
Your OnNavigatedTo Method looks like follows
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
Might be your problem will solve.
Edit
Try this query
var results = (from find in ParseObject.GetQuery("Favorite").WhereEqualTo("user", ParseUser.CurrentUser.Username) select find);
Tried this:
var query = from favorite in ParseObject.GetQuery("Favorite")
where favorite.Get<string>("user") == ParseUser.CurrentUser.Username
select favorite;
IEnumerable<ParseObject> results = await query.FindAsync();
I had a similar Problem.All u want to do here is generate a new instance of the Page.U can do this in two Ways.
One Way is by forcing a GUID along with Page Navigation URI that will create a New Instance of the Page and your Load Data() will work.
NavigationService.Navigate(new Uri(String.Format("/MainPage.xaml?item={0}", Guid.NewGuid().ToString()), UriKind.RelativeOrAbsolute));
The Second Way to implement that Part of your Page in a User Control .Like create a User Control for Load Data() and put it in constructor.It will generate a new Instance everytime you load the Page.
If the problem persists in the front end,you can try this.
1.have you mentioned the below attribute in your xaml page?
<UserControl Loaded="MainPage_Loaded">
So that every time the page loads the data will get loaded on to the page.
2.The data must exist, if you have no problem in the code behind as it is a WPF application and not a web page.
Hope you find it useful.
Two changes required..
Remove the this.Loaded from OnNavigatedTo. That may not be required.
Second move the LoadData to OnNavigatedTo method
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
// this.Loaded += new RoutedEventHandler(MainPage_Loaded);
if (!App.PersonalizedViewModel.IsDataLoaded)
{
App.PersonalizedViewModel.LoadData();
}
}
For the purpose of debugging, you can remove the line if (!App.PersonalizedViewModel.IsDataLoaded) and try.

How to manage two list object reference that are pointing to same collection?

At run time my program assign 2 properties with same collection.
I took two properties so that if changing to collection will be done by one property and second will hold the same collection as it is. But behind the scene both are pointing to same, i can not hold the collection with no changes to one property.
I require this to wok this ok and cancel button so that if no changes one prperty will take care or this, and if changes done the other property wil take care of this.
How can i manage this?
like this
private void btnOK_Click(object sender, EventArgs e)
{
Program.currOrder.OrderItems[Program.editIndex].AppliedCustomization = lstBtn;//objFreecusatomization.AllAppliedItems;
this.DialogResult = System.Windows.Forms.DialogResult.OK;
}
private void btnCancel_Click(object sender, EventArgs e)
{
Program.currOrder.OrderItems[Program.editIndex].AppliedCustomization = actualBtnLIst;
this.DialogResult = DialogResult.Cancel;
}
these are the 2 properties which are being assined from some other program
public List<btnObject> lstBtn;
public List<btnObject> actualBtnLIst { get; set; }
from other program this is how it is set
frmPrepare.actualBtnLIst = frmPrepare.lstBtn = Program.currOrder.OrderItems[currIdx].AppliedCustomization;
There are tow options either when creating actual list, get all the items from the original list and fill it up into the new list, Suppose in a for loop(Transferring the value of all the properties one by one), you can also use reflection for the same.
Other is if the object is serialize then first serialize the original list and then deserialize it back so that the it is copies by value and not by reference.
For the second option code will go something like this:
using (var memoryStream = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, <Your Original List Object>);
memoryStream.Position = 0;
<You actual List Object> = binaryFormatter.Deserialize(memoryStream);
}
It's hard to tell what you're asking, but if you're trying to keep a copy of the original list you will need to make a copy instead of assigning the reference.
frmPrepare.lstBtn = Program.currOrder.OrderItems[currIdx].AppliedCustomization;
frmPrepare.actualBtnLIst = frmPrepare.lstBtn.ToList();
// ToList will create a copy of each item reference in the collection.

New instance every time?

In the following code, which is better? To call add page from within CardPanelDesigner_AddPage? Or use the Func TransactionFunction??
Basically I want to know if doing the inner func will create a "new function" every time :S I don't even know what I'm asking.
Is there an overhead to doing the inner function or should I use the addpage?
private object AddPage(IDesignerHost Host, object Sender)
{
return null;
}
private void CardPanelDesigner_AddPage(object sender, EventArgs e)
{
IDesignerHost DesignerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
if (DesignerHost != null)
{
Func<IDesignerHost, object, object> TransactionFunction = (Host, Param) =>
{
return null;
};
TransactionInfo("Add Page", DesignerHost, AddPage); //Add page? OR TransactionFunction? :S
}
}
Yes, TransactionFunction will create a new object each time CardPanelDesigner_AddPage is called. The performance overhead of this however will likely be negligible. You should do whatever reads best to you (and your team).

Instantiating a passed form of unknown type

I have forms in my application that display a DataGrid bound to a BindingSource. When I double-click on a row I display a detail form.
I have almost 50 of these "browse" forms with their accompanying detail form. I would like to reduce the number of forms (and code) by creating a base browse form and passing the appropriate BindingSource to it. I have this working. However, when I double-click on a row, I want to instantiate the detail form related to the passed BindingSource.
For example, If the user is browsing the Customer table, then a Customer Detail form will be opened, but if he is browsing the Job table, then the Job Detail form will open.
I can pass a generic detail form as a parameter, but how do I cast that passed form to one of the correct type so I can instantiate it?
(I am trying to avoid a large switch statement that cycles through to select the correct passed form. Surely there is a more elegant way to achieve this?)
[EDIT]
My browse form code is instantiated thus:
public BaseBrowse(BindingSource dataClass, DevExpress.XtraEditors.XtraForm crudForm)
{
InitializeComponent();
bs = dataClass;
crud = ((CRUDEquipment)(crudForm));
}
My double-click event is thus:
private void gvw_DoubleClick(object sender, EventArgs e)
{
Int32 nID = Convert.ToInt32(gvw.GetFocusedRowCellValue("ID"));
((CRUDEquipment)(crud)).intID = nID;
((CRUDEquipment)(crud)).Show();
}
I need a way to replace the "CRUDEquipment" with whatever form I need.
Maybe one of these will help
public void Instantiate<T>()
{
var myObject = Activator.CreateInstance<T>();
// Do something with myObject
}
public void Instantiate(Type t)
{
var myObject = Activator.CreateInstance(t);
// Do something with myObject
}
public void Instantiate(string typeName)
{
var detailType = Type.GetType(typeName);
if (detailType == null)
{
throw new InvalidOperationException("Nice try, but type {0} doesn't compute :)");
}
var myObject = Activator.CreateInstance(detailType);
// Do something with myObject
}

Categories