i try to use effective caching but i face to face a problem. For example; i have 5 user they have used my app. user1,2,3,4 only fill grid by searcing(Caching is run!!!). on the other hand user5 adding new row. i want to refresh my cach data when adding new row. i read Multi threading to do that
code>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
using System.Collections;
namespace WebApp.Caching.Threading
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
FillCache();
}
void FillCache()
{
using (var myCtx = new DataClasses1DataContext())
{
if (!(FlyAntCache.Exists("test")))
{
List<Table_1> toolStoreList = myCtx.Table_1s.ToList();
FlyAntCache.Add(toolStoreList, "test");
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
WaitCallback method1 = new WaitCallback(ControlAllChanging);
bool isQueued = ThreadPool.QueueUserWorkItem(method1, new ManualResetEvent(false));
}
protected void ControlAllChanging(object state)
{
if (FlyAntCache.Exists("test"))
{
using (var myCtx = new DataClasses1DataContext())
{
List<Table_1> list;
list = myCtx.Table_1s.ToList();
List<Table_1> listCache = FlyAntCache.Get<List<Table_1>>("test");
bool IsIntersect = list.Except(listCache).Count() > 0;
if (IsIntersect)
{
FlyAntCache.Clear("test");
FillCache();
}
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
// Search
using (var myCtx = new DataClasses1DataContext())
{
var Qry = myCtx.Table_1s.
FromCache<Table_1>("test").
AsQueryable().Where(t => t.ad == TextBox1.Text.Trim());
GridView1.DataSource = Qry;
GridView1.DataBind();
}
}
}
}
My Scenario:
LOOK please :http://i53.tinypic.com/20pdc41.png
i really control if another user change my data, i must refresh my cache. is there any sensitivity to CAPTURE any new changing update new row save. for example :
1) i must capture new update . this mechanizm must run when changes occurs
2) i must capture new save. this mechanizm must run when new row adds
I'm still not quite sure what you're asking. My best guess is it sounds like you're trying to let a cache know when its data is stale.
Most caching implementations have this built in. Basically, you can expire a cache item (usually be removing it from the cache) when it has been updated.
For example, if you're just using the plain old built in caching that comes with ASP.net:
private static Cache Cache;
public void AddItem(string data)
{
//Do a database call to add the data
//This will force clients to requery the source when GetItems is called again.
Cache.Remove("test");
}
public List<string> GetItems()
{
//Attempt to get the data from cache
List<string> data = Cache.Get("test") as string;
//Check to see if we got it from cache
if (data == null)
{
//We didn't get it from cache, so load it from
// wherever it comes from.
data = "From database or something";
//Put it in cache for the next user
Cache["test"] = data;
}
return data;
}
UPDATE I updated the code sample to return a list of strings instead of just a string. This should make it more obvious what is happening.
To reiterate, the GetItems() call retrieves a list of strings. If that list is in cache, the cached list is returned. Otherwise, the list is retrieved and cached / returned.
The AddItem method explicitly removes the list from the cache, forcing the requery of the data source.
Not sure but are you looking for events? You could set up events in your caching mechanism to fire when an update occurs.
Here is a googled example
Related
I'm using the clipboard class from Win API (Windows.ApplicationModel.DataTransfer.Clipboard). When I try to copy multiple items one by one to the clipboard history, it gets overwritten by the recent item. I want to store every item I copy onto the clipboard history. My clipboard history is enabled and I tried using all of the set methods from clipboard including the SetText method from (System.Windows.Clipboard) and all of which overwrites instead of adding to history.
private void UpdateClipboardOnProfileDropDownClosed(object sender, EventArgs e)
{
Clipboard.ClearHistory();
using (var db = new LiteDatabase(Path.Combine(documents, "Auto Paste Clipboard", "data.db")))
{
var collection = db.GetCollection<ClipboardProfile>("clipboard");
var clipboard = collection.FindOne(x => x.Profile == ProfileComboBox.Text);
clipboard.Clipboard.Reverse();
MessageBox.Show(clipboard.Clipboard.Count.ToString());
foreach (var item in clipboard.Clipboard)
{
DataPackage data = new DataPackage
{
RequestedOperation = DataPackageOperation.Copy
};
data.SetText(item);
Clipboard.SetContent(data);
}
}
}
It takes some delays for Clipboard history to save the current item. Therefore, you could try to add a delay when an item is added.
Please check the following code as a sample:
private async void Button_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if(Clipboard.IsHistoryEnabled())
{
List<string> lists=new List<string>{ "1","2","3","4","5","6","7","8","9","10"};
foreach(var item in lists)
{
DataPackage dataPackage = new DataPackage();
dataPackage.SetText(item);
Clipboard.SetContent(dataPackage);
await Task.Delay(250);
}
}
}
Note, if these items are not all added, you could increase the delay time.
My domain model is large tree structure that is modified by application. I would like to implement search in BackgroundWorker (separate thread to not block the UI).
Currently tree structure is implemented with ObservableCollection, that cannot be enumerated while it is modified, so my search will fail if user modifies tree while I am searching through it.
What is elegant solution for this problem? My requirements: do not block user from doing anything (operation should be async), search on separate thread (to speed things up).
Here is one way I can think of that you can achieve what you need:
When writing, use lock, create a copy of the collection, add to the copy and then re-assign the collection to the copy.
Here is some code so you can test the above method. Create a form with a ListBox and a Button. While the list is being searched on a thread, you can add items to the list using the button.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
namespace WindowsForms {
public partial class Form1 : Form {
object key = new object();
private List<string> items;
public Form1() {
InitializeComponent();
items = new List<string>();
for( int i = 0; i < 100000; i++ ) {
this.items.Add( i.ToString() );
}
this.listBox1.DataSource = this.items;
}
private void Read() {
foreach( var thisItem in this.items ) {
if (thisItem.ToString() == "100000" ) {
MessageBox.Show( "Found" );
}
else {
Thread.Sleep( 100 );
}
}
}
private void buttonStation2_Click(object sender, EventArgs e) {
lock( this.key ) {
var copy = new List<string>( this.items );
copy.Add( "1000001" );
this.items = copy;
}
}
private void Form1_Shown(object sender, EventArgs e) {
Thread reader = new Thread( Read );
reader.Start();
}
}
}
You may also want to make the collection variable volatile so a cached version is not used and you always get the latest when reading. However, you really need to know what the volatile keyword does before using it so that is why I did not use it in my code and left it up to you to decide. Also, other SO users may chime in and offer their advice using volatile in the comments to this answer if they wish.
private volatile List<string> items;
I have spent few days searching everywhere for a solution to this.
This is for C# with Visual Studio 2013 (ya, I am a newbie):
two textboxes (Last name and First Name) and a listbox with 5 names (Higgins M, Higgins J, King J, Tran A, Dempsey S). I set listbox property as sorted.
if I select Higgins J in listbox, then the word Higgins should appear in Last Name textbox and J should appear in First Name textbox.
if I type Higgins in Last Name textbox, Higgins J should be the selected item in listbox (Higgins J will be selected before Higgins M). If I type M in the First Name textbox, the selected item should change from Higgins J to Higgins M.
but....here are the problems that made me decide to create an account here:
If I type Hi or Hig instead of Higgins, it has to stay that way, it does not become Higgins in the textbox. Only the index/highlight in listbox is changed, not the entry in textbox (whatever I type in the textbox stays). I suspect the events that I use are the reason I cannot get this done. Textbox_textchanged and listbox_selectedindexchanged. So whatever I do in one event will automatically triggers the other. I have tried changing the events, but so far the result simply worse. Using: if (LastName_textbox.Text = "") did not help either.
How do I combine Last Name and First Name as one index?
I apologise if this question has appeared or sounded ambiguous. I suppose I do not know how to phrase the search to get something similar to my problem and English is not my first language. Any help is very much appreciated .Thanks.
Here is part of the codes:
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Project
{
public partial class frmContact : Form
{
//declare file to save all contacts
private string fileName = Directory.GetCurrentDirectory() + "\\Contacts.txt";
//create temporary file for updating and deleting contacts
private string newContacts = Directory.GetCurrentDirectory() + "\\newContacts.txt";
public frmContact()
{
InitializeComponent();
}
private void frmContact_Load(object sender, EventArgs e)
{
//create Contacts.txt if it does not exist
if (!File.Exists(fileName))
{
File.Create(fileName).Close();
MessageBox.Show("New " + fileName +" Has Been Created");
tbLast.Select();
}
//if file already exists
else
{
StreamReader readOb = new StreamReader(fileName);
using (readOb)
{
while (!readOb.EndOfStream)
{
string rdLine = readOb.ReadLine(); //read data in file by line
string[] tmpArr = rdLine.Split(',');
lbContact.Items.Add(tmpArr[0] + "," + tmpArr[1]);
}
tbLast.Select();
}
}
}
private void lbContact_SelectedIndexChanged(object sender, EventArgs e)
{
//show details of contact selected in listbox
string findNames = lbContact.GetItemText(lbContact.SelectedItem);
StreamReader obRead = new StreamReader(fileName);
using (obRead)
{
while (!obRead.EndOfStream)
{
string rdLine = obRead.ReadLine();
if (rdLine.StartsWith(findNames))
{
string[] tmpArr = rdLine.Split(',');
tbLast.Text = tmpArr[0];
tbFirst.Text = tmpArr[1].Trim();
tbAddr.Text = tmpArr[2].Trim();
tbSub.Text = tmpArr[3].Trim();
tbPost.Text = tmpArr[4].Trim();
tbEmail.Text = tmpArr[5].Trim();
tbPhone.Text = tmpArr[6].Trim();
tbMob.Text = tmpArr[7].Trim();
}
}
lbContact.SelectedIndex = lbContact.FindString(findNames);
}
}
private void tbLast_TextChanged(object sender, EventArgs e)
{
lbContact.SelectedItem = lbContact.FindString(tbLast.Text);
}
A simple (but kind of ugly solution) would consist in using a boolean value to inform your lbContact_SelectedIndexChanged method that the index was manually changed thanks to the code. A class member would do the job, something like:
private bool fromCode;
private void lbContact_SelectedIndexChanged(object sender, EventArgs e)
{
if (fromCode)
return;
// Do the job
}
private void tbLast_TextChanged(object sender, EventArgs e)
{
fromCode = true;
lbContact.SetSelected(lbContact.FindString(tbLast.Text), true);
fromCode = false;
}
[Personal remark]
I would also create a Contact struct/class to store your information along with a collection in your form so that you only have to access your file twice:
At loading, so that you can populate your collection
At closing, so that you can save the changes to your file
[Update]
My last remark can be not relevant as I do not have the context in which you are developing your application, that's why I said it was a personal point of view, you don't have to do it.
[Update 2]
What you can do to avoid access your file each time your lbContact_SelectedIndexChanged event is called:
Create a structure or a class to store your contacts information (firstname, lastname, adress, ...)
Create a collection (as a class member of your form) that will contain the contacts (like a List<Contact>)
In your frmContact_Load method, fill this collection with the data contained in the file instead of populating your listbox
So that in your lbContact_SelectedIndexChanged method you will search inside the collection instead of opening your file
Your Add() and Delete() operations must also modify the collection and not the file anymore
Remember to save your collection back to your file at application closing
Hope it helped.
I found the solution (for whoever encounters similar problem), the answer is in the textbox.focused :) and combined with listbox.setselected from Tim.
private void tbLast_TextChanged(object sender, EventArgs e)
{
if (tbLast.Focused && tbLast.Text != "")
{
if (lbContact.FindString(tbLast.Text) > -1)
{
lbContact.SetSelected(lbContact.FindString(tbLast.Text), true);
}
}
}
private void lbContact_SelectedIndexChanged(object sender, EventArgs e)
{
//show details of contact selected in listbox
string findNames = lbContact.GetItemText(lbContact.SelectedItem);
StreamReader obRead = new StreamReader(fileName);
using (obRead)
{
while (!obRead.EndOfStream)
{
string rdLine = obRead.ReadLine();
if (rdLine.StartsWith(findNames))
{
string[] tmpArr = rdLine.Split(',');
if (!tbLast.Focused)
{
tbLast.Text = tmpArr[0];
tbFirst.Text = tmpArr[1].Trim();
tbAddr.Text = tmpArr[2].Trim();
tbSub.Text = tmpArr[3].Trim();
tbPost.Text = tmpArr[4].Trim();
tbEmail.Text = tmpArr[5].Trim();
tbPhone.Text = tmpArr[6].Trim();
tbMob.Text = tmpArr[7].Trim();
}
}
}
lbContact.SelectedIndex = lbContact.FindString(findNames);
}
}
I am currently working on Windows Store App in c#.
Now,
I am having a list box 'Listbox1' which gets its items on a button click event from a text box 'tasks', and have selected Items delete property on other button click event.
private void add_Click(object sender, RoutedEventArgs e)
{
string t;
t = tasks.Text;
if (t != "")
{
Listbox1.Items.Add(t);
}
else
{
var a = new MessageDialog("Please Enter the Task First");
a.Commands.Add(new UICommand("Ok"));
a.ShowAsync();
}
tasks.Text = "";
}
private void del_Click(object sender, RoutedEventArgs e)
{
for (int p = 0; p < Listbox1.SelectedItems.Count; p++)
{
Listbox1.Items.Remove(Listbox1.SelectedItems[p].ToString());
p--;
}
}
Now I want to save this list into local application storage, after user complete the changes (on a button click event perhaps).
And also to send all Listbox Items to another page(s).
I am not much a coder, I design things.
Please guide me by sample or reference.
Thank you in advance :)
If you have already stored the data to local storage, you could just read it in the OnNavigatedTo override of the other page. Otherwise, use the navigation parameter: http://social.msdn.microsoft.com/Forums/windowsapps/en-US/8cb42356-82bc-4d77-9bbc-ae186990cfd5/passing-parameters-during-navigation-in-windows-8
Edit: I am not sure whether you also need some information about local storage. This is easy: Windows.Storage.ApplicationData.Current.LocalSettings has a property called Values, which is a Dictionary you can write your settings to. Have a look at http://msdn.microsoft.com/en-us/library/windows/apps/hh700361.aspx
Edit: Try something like this code to store your list.
// Try to get the old stuff from local storage.
object oldData = null;
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
bool isFound = settings.Values.TryGetValue("List", out oldData);
// Save a list to local storage. (You cannot store the list directly, because it is not
// serialisable, so we use the detours via an array.)
List<string> newData = new List<string>(new string[] { "test", "blah", "blubb" });
settings.Values["List"] = newData.ToArray();
// Test whether the saved list contains the expected data.
Debug.Assert(!isFound || Enumerable.SequenceEqual((string[]) oldData, newData));
Note, this is only demo code for testing - it does not make real sense...
Edit: One advice: Do not persist the list in your click handlers as this will become extremely slow as the list grows. I would load and save the list in the Navigation handlers, i.e. add something like
protected override void OnNavigatedTo(NavigationEventArgs e) {
base.OnNavigatedTo(e);
if (this.ListBox1.ItemsSource == null) {
object list;
if (ApplicationData.Current.LocalSettings.Values.TryGetValue("List", out list)) {
this.ListBox1.ItemsSource = new List<string>((string[]) list);
} else {
this.ListBox1.ItemsSource = new List<string>();
}
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e) {
if (this.ListBox1.ItemsSource != null) {
ApplicationData.Current.LocalSettings.Values["List"] = this.ListBox1.ItemsSource.ToArray();
}
base.OnNavigatedFrom(e);
}
Here is very nice simple example on SQLite DataBase Use in winRT app Development. Look at it and you will know how you can store your Data on the Local Machine. I learned Basic code from this example.
http://blogs.msdn.com/b/robertgreen/archive/2012/11/13/using-sqlite-in-windows-store-apps.aspx
Now, for ease of navigation let me suggest you a flow for this portion of your app.
take one ObservableCollection<> of string and store values of
that textBox into this ObservationCollection with onClick() and then
refer that ObservableCollection<String> to the ItemsList of the
listBox.
now at the time you need to send your Data to the next page, make one parameterised constructor of next page and pass that ObservableCollection<String> as it's parameter.
Now you can access those Data in your constructor and can use as however you want.
Hope this will help..
I'm beginner with C# and wp7 platform and I have some problem with good idea to get request from web service.
I made webservice in PHP (nusoap - WSDL) and everything is working fine in "normal" using.
Now I have ObservableCollection saved in IsolatedStorage with I load when Page is open (List of watched stacks exchange). Then I want to refresh data for every item from web service.
I don't know whether this is a good idea.
Code:
private GPWWebservicePortTypeClient client = new GPWWebservicePortTypeClient();
private ObservableCollection<WebServiceClass.ItemGetValues> StoredStock =
new ObservableCollection<WebServiceClass.ItemGetValues>();
public const string _fileName = "listaObserwowanych.xml";
public Page()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(Page_Loaded);
client.GetLastValueCompleted +=
new EventHandler<GetLastValueCompletedEventArgs>(client_GetLastValueCompleted);
foreach (var itemGetValuese in App.ViewModel.Items)
{
client.GetLastValueAsync(itemGetValuese.name);
}
var o =
Observable.FromEvent<GetLastValueCompletedEventArgs(client,"GetLastValueCompleted")
.Subscribe(setList);
}
void client_GetLastValueCompleted(object sender, GetLastValueCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(Convert.ToString(e.Error));
}
else
{
ObservableCollection<WebServiceClass.ItemGetValues> ListValues =
(ObservableCollection<WebServiceClass.ItemGetValues>)
JsonConvert.DeserializeObject(e.Result,
typeof(ObservableCollection<WebServiceClass.ItemGetValues>));
StoredStock.Add(ListValues[0]);
}
}
private void setList(IEvent<GetLastValueCompletedEventArgs> ex)
{
List.ItemsSource = StoredStock;
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
App.ViewModel.LoadData();
List.ItemsSource = App.ViewModel.Items;
}
Like u see I use RX to call method client_GetLastValueCompleted add store result to auxiliary variable (StoredStock). Then refresh List in setList method, but that method is client_GetLastValueCompleted what is not soo good idea, becouse I need to run that method only when all of runned GetLastValueAsync in foreach is completed.
Second problem: becouse of async web service method StoredStock sometime have different order than App.ViewModel.Items .
Any good idea how to do that in right way?
Best regards,
Lukas
You're really mixing up a number of ways to call web services and Rx. You really need to decide on a single way and stick to it.
If you're going to use Rx, then you'll have something like this:
public Page()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
App.ViewModel.LoadData();
var storedStock =
new ObservableCollection<WebServiceClass.ItemGetValues>();
List.ItemsSource = storedStock;
var values =
Observable.Using<WebServiceClass.ItemGetValues, GPWWebservicePortTypeClient>
(() => new GPWWebservicePortTypeClient(), ws =>
{
var clientGetLastValue = Observable
.FromAsyncPattern<string, GetLastValueResponse>
(ws.BeginGetLastValue, ws.EndGetLastValue);
Func<string, WebServiceClass.ItemGetValues> deserializeFirst = r =>
((List<WebServiceClass.ItemGetValues>)JsonConvert
.DeserializeObject(r,
typeof(List<WebServiceClass.ItemGetValues>)))
.First();
return
from item in App.ViewModel.Items
from e in clientGetLastValue(item)
select deserializeFirst(e.Result);
});
values.Subscribe(storedStock.Add);
}
You'll have to get the right method call names for your web service client, but the code should roughly be right. Let me know how you go.
I corrected the code above. Should have returned the query inside the Using call rather than assign it to values.
I corrected the call to FromAsyncPattern to use the correct method names and return type from the actual web service reference class sent via email.
It should look like this:
Observable.FromAsyncPattern<string, GetLastValueResponse>
(ws.BeginGetLastValue, ws.EndGetLastValue);
If you're a beginner with C#, try to avoid RX for the time being. It is a cool technology, but if you use it without clear understanding of what is going on, it will bring more problems than solve.
Use a simple event, and when each async item arrives, locate and update the correspondent one in the stored list.