this below to sample code;
private ExampleStatus _status;
public ExampleStatus status
{
get
{
if (_status == null) _status = new ExampleStatus();
//if (_status.receivedData) _status.receivedData = false; //this line is incorrect !
return _status;
}
}
public class ExampleStatus
{
public int Id { get; set; }
public string Name { get; set; }
public bool receivedData { get; set; }
//I don't want to use this method
public void Clear()
{
Id = 0;
Name = string.Empty;
receivedData = false;
}
}
int stateType = 0;
void ContinuousLoop(ExampleStatus statusObj)
{
while (true)
{
//I don't want to use the options below
//statusObj.Clear();
//or
//statusObj = new ExampleStatus();
if (stateType == 0)
{
statusObj.Id = 0;
statusObj.Name = "Firs Status";
}
else if (stateType == 1)
{
statusObj.Id = 1;
statusObj.Name = "Second Status";
statusObj.receivedData = true;
}
else if (stateType == 2)
{
statusObj.Id = 2;
statusObj.Name = "Third Status";
}
}
}
void RunThread()
{
var t1 = new Thread(() =>
{
ContinuousLoop(status);
});
t1.Start();
}
Is it possible to set default values without a method or new instance, as shown in the example?
Actually that's why I'm asking this question:
I will use the class I have defined in many places. I will need to add a block of code, such as the Clear method, to every place I use it.
I'm also curious about one more thing. If I assign a new instance every time to reset my objects, does this cause problems in memory?
I know more or less how garbage collections work. However, they say that in practice it does not work as said in theory.
So if I add "IDisposable" to my Class, it would tell the garbage collector: Welcome, I'm a litter. Will you take me too?
I have an ObservavebleColection bound to a listView. Basically, this collection must keep up with every change in the server and receives updates in string format.
My code parses the string and adds elements to the collection, but I'm having trouble finding a way to remove elements. How can I update the collection when an element is removed or changed on the server?
Here's my code:
public static ObservableCollection<TransactionDetails> offerList = new ObservableCollection<TransactionDetails>();
public async static Task<ObservableCollection<TransactionDetails>> getOfferList()
{
// Start getting Offers
string Offer = await BedpAPI_V1.getOfferList();
string[] splitedResponse = Offer.Split(new[] { "####" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string response in splitedResponse) {
string[] splitedMessage = response.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
offer.TransactionID = Convert.ToInt32(splitedMessage[0]);
offer.Seller = splitedMessage[1];
offer.Cost = Convert.ToDouble(splitedMessage[2]);
offer.Duration = Convert.ToInt16(splitedMessage[3]);
offer.Delay = Convert.ToInt16(splitedMessage[4]);
offer.Capacity = Convert.ToDouble(splitedMessage[5]);
offer.Availability = Convert.ToDouble(splitedMessage[6]);
if (currentOffer <= offer.TransactionID)
{
offerList.Add(new TransactionDetails() { TransactionID = offer.TransactionID, Seller = offer.Seller, Cost = offer.Cost, Duration = offer.Duration, Delay = offer.Delay, Capacity = offer.Capacity, Availability = offer.Availability });
currentOffer++;
}
}
return offerList;
}
If your ListView bind with a ObservavebleColection<>, when you modify an element, you may fire a OnCollectionChanged event yourself.
Assume you modify an element using []:
public class MyCollection : ObservableCollection<MyClass>
{
public new MyClass this[int index]
{
get { return base[index]; }
set
{
base[index] = value;
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
}
UPDATE:
Firstly, you may want to bind your collection like:
myCollection = MyFunction();
MyListView.ItemsSource = myCollection;
If you change an item in your collection like:
myCollection[index] = someNewItem;
Then you could update your listview like:
MyListView.Refresh();
But it is recommended to use some dynamic binding.
I solved the problem by clearing the collection on every call before parsing splitedResponse - as Clear() was throwing an unheld exception, had to handle it inside a throw catch block:
try
{
offerList.Clear();
}
catch (Exception ex) {
offerList.Clear();
Console.WriteLine(ex.Message);
}
// The class for the search query
public class SearchQueries
{
List<data> list = new List<data>();
string response;
// The method that return the list after it is set
public List<data> GetData()
{
return list;
}
// The method that do the searching from the google API service
public async void SetData()
{
// The problem starts here, when i instantiate the search class in this class in other to get the value of the text in the autosuggestbox for my query, it crashes whenever i try to launch the page. it works fine whenever i give the address default data e.g string address = "London", the page open when i launch it and give me London related result whenever i type in the autosuggestbox.
Search search = new Search();
string address = search.Address;
list.Clear();
// Note the tutorial i used was getting the data from a local folder, but i'm trying to get mine from Google API
string dataUri = "https://maps.googleapis.com/maps/api/place/autocomplete/json?key=AIzaSyDBazIiBn2tTmqcSpkH65Xq5doTSuOo22A&input=" + address;
string Api = System.Uri.EscapeDataString(dataUri);
HttpClient client = new HttpClient();
client.Timeout = TimeSpan.FromMilliseconds(1000);
try
{
response = await client.GetStringAsync(Api);
for (uint i = 0; i < jsonarray.Count; i++)
{
string json_string_object = jsonarray.GetObjectAt(i)["description"].ToString();
list.Add(new data() { name = json_string_object });
}
}
catch (TimeoutException e)
{
ContentDialog myDlg = new ContentDialog()
{
PrimaryButtonText = "OK"
};
myDlg.Content = e.ToString();
}
}
// Method to get matched data
public IEnumerable<data> getmatchingCustomer(string query)
{
return list.Where(c => c.name.IndexOf(query, StringComparison.CurrentCultureIgnoreCase) > -1).OrderByDescending(c => c.name.StartsWith(query, StringComparison.CurrentCultureIgnoreCase));
}
// constructor for returning the SetData() method
public SearchQueries()
{
// It points to this method whenever the application crash, with the notification of infinite loop or infinite recursion
SetData();
}
}
// The Main Class of the page
public sealed partial class Search : Page
{
public string theaddress { get; set; }
SearchQueriess queries = new SearchQueriess();
public Search()
{
this.InitializeComponent();
myMap.Loaded += MyMap_Loaded;
theaddress = locationAddress.Text;
}
// The text change method of the autosuggest box.
private async void AutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
if (sender.Text.Length > 1)
{
var marchingData = queries.getmatchingCustomer(sender.Text);
sender.ItemsSource = marchingData.ToList();
}
else
{
sender.ItemsSource = new string[] { "No suggestion...." };
}
}
}
}
I have a Tag model in my application:
public class Tag
{
public Tag() { }
public Tag(string t)
{
Name = t;
Pictures = new List<Picture>();
}
public int Id { get; set; }
[MaxLength(96), Index(IsUnique = true)]
public string Name { get; set; }
public virtual List<Picture> Pictures { get; set; }
}
Is there any way to tell the framework to do ON DUPLICATE DO NOTHING, when a record with the same Name already exists? This always throws a Duplicate exception and I'd like it to just ignore it and move on.
Edit: I've changed the EF code across many threads to this:
async Task SaveQueue()
{
for (;;)
{
try
{
await Task.Delay(7500);
dbUploadProgress.Visibility = Visibility.Visible;
dbUploadProgress.Value = 0;
var q = new ObservableCollection<Picture>(manager.Queue.ToList().AsEnumerable());
manager.Queue.Clear();
var imgcount = q.Count();
for (int i = 0; i < imgcount; i++)
{
using (var pc = new PicsContext())
{
var tags = q[i].GetTags();
pc.Sites.Attach(q[i].Site); // I'm actually not sure how to use this.
var curUrl = q[i].Url;
if (pc.Pictures.FirstOrDefault(o => o.Url == curUrl) != null)
continue;
foreach (var t in tags)
{
var tag = pc.Tags.Where(o => o.Name == t).FirstOrDefault();
if (tag == null)
{
tag = new ViewModel.Tag(t);
}
q[i].Tags.Add(tag);
try
{
await pc.SaveChangesAsync();
}
catch { }
}
pc.Pictures.Add(q[i]);
try
{
await pc.SaveChangesAsync();
}
catch { }
dbUploadProgress.Value = (i + 1) / (double)imgcount;
}
}
q.Clear();
MainWindow.AddLog(string.Format("Saved {0} pictures.", imgcount));
dbUploadProgress.Visibility = Visibility.Collapsed;
await Task.Delay(1500);
}
catch { }
if (isStopped)
break;
}
}
The problem still exists, though.
Why don't you ran an dbContext.Get.Any(x=>x.Name==tag.Name) and skip adding the new tag based on it?
I think the problem is that your queue processes messages async, so you can have 2 threads trying to insert same tag because the check if exists logic ran before an insert has been made.
You can fix the problem by processing just 1 queue message at a time (having one worker/thread processing the queue).
Or another work around might be to isolate the tags saving in a try catch and handle the duplicate exception properly (reloading the tag from db and use that one when setting it on the new object).
I have the following code, which basically takes values from a database and populates a listview.
using (IDataReader reader = cmd.ExecuteReader())
{
lvwMyList.Items.Clear();
while (reader.Read())
{
ListViewItem lvi = lvwMyList.Items.Add(reader["Value1"].ToString());
lvi.SubItems.Add(reader["Value2"].ToString());
}
}
The problem that I have is that this is repeatedly executed at short intervals (every second) and results in the items in the listview continually disappearing and re-appearing. Is there some way to stop the listview from refreshing until it’s done with the updates? Something like below:
using (IDataReader reader = cmd.ExecuteReader())
{
lvwMyList.Items.Freeze(); // Stop the listview updating
lvwMyList.Items.Clear();
while (reader.Read())
{
ListViewItem lvi = lvwMyList.Items.Add(reader["Value1"].ToString());
lvi.SubItems.Add(reader["Value2"].ToString());
}
lvwMyList.Items.UnFreeze(); // Refresh the listview
}
Like this:
try
{
lvwMyList.BeginUpdate();
//bla bla bla
}
finally
{
lvwMyList.EndUpdate();
}
Make sure that you invoke lvwMyList.Items.Clear() after BeginUpdate if you want to clear the list before filling it.
This is my first time posting on StackOverflow, so pardon the messy code formatting below.
To prevent locking up the form while updating the ListView, you can use the method below that I've written to solve this issue.
Note: This method should not be used if you expect to populate the ListView with more than about 20,000 items. If you need to add more than 20k items to the ListView, consider running the ListView in virtual mode.
public static async void PopulateListView<T>(ListView listView, Func<T, ListViewItem> func,
IEnumerable<T> objects, IProgress<int> progress) where T : class, new()
{
if (listView != null && listView.IsHandleCreated)
{
var conQue = new ConcurrentQueue<ListViewItem>();
// Clear the list view and refresh it
if (listView.InvokeRequired)
{
listView.BeginInvoke(new MethodInvoker(() =>
{
listView.BeginUpdate();
listView.Items.Clear();
listView.Refresh();
listView.EndUpdate();
}));
}
else
{
listView.BeginUpdate();
listView.Items.Clear();
listView.Refresh();
listView.EndUpdate();
}
// Loop over the objects and call the function to generate the list view items
if (objects != null)
{
int objTotalCount = objects.Count();
foreach (T obj in objects)
{
await Task.Run(() =>
{
ListViewItem item = func.Invoke(obj);
if (item != null)
conQue.Enqueue(item);
if (progress != null)
{
double dProgress = ((double)conQue.Count / objTotalCount) * 100.0;
if(dProgress > 0)
progress.Report(dProgress > int.MaxValue ? int.MaxValue : (int)dProgress);
}
});
}
// Perform a mass-add of all the list view items we created
if (listView.InvokeRequired)
{
listView.BeginInvoke(new MethodInvoker(() =>
{
listView.BeginUpdate();
listView.Items.AddRange(conQue.ToArray());
listView.Sort();
listView.EndUpdate();
}));
}
else
{
listView.BeginUpdate();
listView.Items.AddRange(conQue.ToArray());
listView.Sort();
listView.EndUpdate();
}
}
}
if (progress != null)
progress.Report(100);
}
You don't have to provide an IProgress object, just use null and the method will work just as well.
Below is an example usage of the method.
First, define a class that contains the data for the ListViewItem.
public class TestListViewItemClass
{
public int TestInt { get; set; }
public string TestString { get; set; }
public DateTime TestDateTime { get; set; }
public TimeSpan TestTimeSpan { get; set; }
public decimal TestDecimal { get; set; }
}
Then, create a method that returns your data items. This method could query a database, call a web service API, or whatever, as long as it returns an IEnumerable of your class type.
public IEnumerable<TestListViewItemClass> GetItems()
{
for (int x = 0; x < 15000; x++)
{
yield return new TestListViewItemClass()
{
TestDateTime = DateTime.Now,
TestTimeSpan = TimeSpan.FromDays(x),
TestInt = new Random(DateTime.Now.Millisecond).Next(),
TestDecimal = (decimal)x + new Random(DateTime.Now.Millisecond).Next(),
TestString = "Test string " + x,
};
}
}
Finally, on the form where your ListView resides, you can populate the ListView. For demonstration purposes, I'm using the form's Load event to populate the ListView. More than likely, you'll want to do this elsewhere on the form.
I've included the function that generates a ListViewItem from an instance of my class, TestListViewItemClass. In a production scenario, you will likely want to define the function elsewhere.
private async void TestListViewForm_Load(object sender, EventArgs e)
{
var function = new Func<TestListViewItemClass, ListViewItem>((TestListViewItemClass x) =>
{
var item = new ListViewItem();
if (x != null)
{
item.Text = x.TestString;
item.SubItems.Add(x.TestDecimal.ToString("F4"));
item.SubItems.Add(x.TestDateTime.ToString("G"));
item.SubItems.Add(x.TestTimeSpan.ToString());
item.SubItems.Add(x.TestInt.ToString());
item.Tag = x;
return item;
}
return null;
});
PopulateListView<TestListViewItemClass>(this.listView1, function, GetItems(), progress);
}
In the above example, I created an IProgress object in the form's constructor like this:
progress = new Progress<int>(value =>
{
toolStripProgressBar1.Visible = true;
if (value >= 100)
{
toolStripProgressBar1.Visible = false;
toolStripProgressBar1.Value = 0;
}
else if (value > 0)
{
toolStripProgressBar1.Value = value;
}
});
I've used this method of populating a ListView many times in projects where we were populating up to 12,000 items in the ListView, and it is extremely fast. The main thing is you need to have your object fully built from the database before you even touch the ListView for updates.
Hopefully this is helpful.
I've included below an async version of the method, which calls the main method shown at the top of this post.
public static Task PopulateListViewAsync<T>(ListView listView, Func<T, ListViewItem> func,
IEnumerable<T> objects, IProgress<int> progress) where T : class, new()
{
return Task.Run(() => PopulateListView<T>(listView, func, objects, progress));
}
You can also try setting the visible or enabled properties to false during the update and see if you like those results any better.
Of course, reset the values to true when the update is done.
Another approach is to create a panel to overlay the listbox. Set it's left, right, height, and width properties the same as your listbox and set it's visible property to true during the update, false after you're done.