I'm working with windows phone 8 apps that getting data from restful service using json file and I getting problem to showing data I get from restful service into my listbox here is the code:
WebClient client = new WebClient();
client.DownloadStringCompleted += (s,e) =>
{
if(e.Error == null){
RootObject result = JsonConvert.DeserializeObject<RootObject>(e.Result);
CurrentDay = new ObservableCollection<Item>(result.results.items);
MessageBox.Show(CurrentDay[3].title.ToString());
}else{
MessageBox.Show("Sorry, try again at the next TechEd");
}
};
client.DownloadStringAsync(new Uri("http://places.nlp.nokia.com/places/v1/discover/explore?at=37.7851%2C-122.4047&cat=transport&tf=plain&pretty=true&app_id=xxxxx&app_code=xxxxx"));
the app_id and app_code sensored sorry :P
in that code i can't show the data into my listbox but when i using it showing the right data
MessageBox.Show(CurrentDay[3].title.ToString());
oh and I'm using mvvm light reference
I assume your ListBox has ItemsSource Property set to CurrentDay.
If that is true, the ListBox needs to know that the property was changed.
Since you are using ObservableCollection, the ListBox will notice chances to the current collection (e.g Add or Remove Items), but it can't know that a new ObservableCollection is assigned to the property unless you notify it.
To make it simple, I suggest you to Clear the CurrentDay collection and Add items to it, instead of creating a new ObservableCollection<Item>() each time:
CurrentDay.Clear();
foreach (var item in result.results.items)
CurrentDay.Add(item);
Make sure to initialize the collection in the constructor:
CurrentDay = new ObservableCollection<Item>();
Related
I have a windows form with a ComboBox DisplayBox. In my ViewModel I now have a Property BindingList<MyObject> ObjectBindingList that I want to bind to the DisplayBox.
When I load the form, the DisplayBox does not show any text.
The property DataSource is set and holds a List of MyObjects when checking in the debug modus after the data download.
The property items always has a count of zero.
My code works as following:
On startup I set the databindings in the form class to a still empty List ObjectBindingList.
displayBox.DataSource = ObjectBindingList;
The DisplayMember and ValueMember were set in the ComboBox Properties in the GUI Designer.
Asynchrously the controller downloads some data (MyDataObjects) async. Then sets the BindingList<MyObject> ObjectBindingList in the ViewModel to the downloaded Objects through adding them.
Since I don't see all of the relevant code, I can only assume what's happening.
Probably, you don't see the data in the ComboBox, because you are creating a new BindingList when loading the data. But the ComboBox is still attached to the old empty list.
You initialize the data source with an empty list like this:
// Property
BindingList<MyObject> ObjectBindingList { get; set; }
Somewhere else
// Initializes data source with an empty `BindingList<MyObject>`.
ObjectBindingList = new BindingList<MyObject>();
displayBox.DataSource = ObjectBindingList;
Later, you load the data and replace the list:
ObjectBindingList = LoadData();
Now, you have two lists: the initial empty list assigned to displayBox.DataSource and a new filled one assigned to the property ObjectBindingList. Note that displayBox.DataSource does not have a reference to the property itself, therefore it does not see the new value of the property.
For a BindingList<T> to work as intended, you must add the items with
var records = LoadData();
foreach (var data in records) {
ObjectBindingList.Add(data);
}
I.e., keep the original BindingList<MyObject> assigned to the data source.
See also: How can I improve performance of an AddRange method on a custom BindingList?
To avoid the problem, I would be advisasble to make the property read-only (using C# 9.0's Target-typed new expressions).
BindingList<MyObject> ObjectBindingList { get; } = new();
It seems like when trying to update the ComboBox from a different thread than the main forms thread, the update did not reach the control.
I am now using the Invoke Method together with a BindingSource Object in between the Binding List and the control.
private void SetBindingSourceDataSource( BindingList<MyObject> myBindingList)
{
if (InvokeRequired)
{
Invoke(new Action<BindingList<MyObject>>(SetBindingSourceDataSource), myBindingList);
}
else {
this.BindingSource.DataSource = myBindingList;
}
}
I am expeciall calling the above function on a PropertyChanged event, that I trigger at the end of every call of the download Function.
I'm fairly new to C# but understand basic concepts.
I'm currently working on a Uni assignment where I have to have multiple textboxes be entered as a single entry in a listbox, then save all entries to a text file. I also need to be able to load the text file and add new entries to the list.
I've figured out how to save data to a .txt file, as well as reloading the .txt file back into the listbox using
if (File.Exists("PersonalFile.txt"))
{
string[] line = File.ReadAllLines("PersonalFile.txt");
lbxStaffDetails.ItemsSource = line;
}
However, doing it this way I can't add new entries to the listbox due to the data binding, I get this error message System.InvalidOperationException: 'Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.'
Is there a way to remove the binding but keep the data in the listbox? Using lbxStaffDetails.ItemsSource = null; clears the listbox; or is there another way to read all lines of the .txt file to the listbox without using the file as a binding source?
Notes:
lbxStaffDetails is this listbox in question
PersonalFile.txt is the .txt holding the entries on new lines.
This is the first time I've bound data and files.
Edit:
Forgot to mention how I'm adding the data to the listbox so here's the code for that.
private void btnAddWaitingList_Click(object sender, RoutedEventArgs e)
{
_EmployeeID = tbxEmployeeID.Text;
_Name = tbxName.Text;
_PayRate = tbxPayRate.Text;
_Email = tbxEmail.Text;
string employeeDetails = _EmployeeID + "," + _Name + "," + _PayRate + "," + _Email;
lbxStaffDetails.Items.Add(employeeDetails);
}
As the code fires and gets to the bottom line it throws the error mentioned above.
Don't confuse data binding with simple value assignment. Data binding is a different concept, where a target binds to a data source using a Binding. A Binding will monitor target and source and delegates changes from one to the other. It's a bi-directional dynamic data link.
You can setup a Binding in XAML or C# (see Data binding overview in WPF).
You are not binding the ListBox to a file. You have read contents of a file to an array of strings. This array is then assigned to the ListBox.ItemsSource property.
Since you have populated the ListBox using the ItemsSource property, you are not allowed to modify its items using the Items property (InvalidOperationException).
You have to either assign the modified collection again to ListBox.ItemsSource (which will cause the complete ListBox to create all items again, which is bad for the performance) or make use of ObservableCollection.
It's a special collection that allows to be observed (Observer pattern). The observer gets notified by the observed collection via an event that the collection has changed (add/move/remove). Every ItemsControl is able to listen to this event and will automatically update itself.
MainWindow.xaml.cs
partial class MainWindow : Window
{
public ObservableCollection<string> StaffDetails { get; set; }
public MainWindow()
{
InitializeComponent();
// Set the DataContext to MainWindow for data binding (XAML version)
this.DataContext = this;
}
private void ReadFile()
{
if (!File.Exists("PersonalFile.txt"))
{
return;
}
string[] lines = File.ReadAllLines("PersonalFile.txt");
// Create a new ObservableCollection and initialize it with the array
this.StaffDetails = new ObservableCollection<string>(lines);
// You write to the file using this same collection directly,
// without accessing the ListBox
File.WriteAllLines("PersonalFile.txt", this.StaffDetails);
// Option 1: assignment (static data link)
this.lbxStaffDetails.ItemsSource = this.StaffDetails;
// Alternative option 2: C# data binding (dynamic data link)
var binding = new Binding(nameof(this.StaffDetails)) { Source = this };
this.lbxStaffDetails.SetBinding(ItemsControl.ItemsSourceProperty, binding);
// Alternative option 3 (recommended): XAML data binding (dynamic data link). See MainWindow.xaml
}
private void btnAddWaitingList_Click(object sender, RoutedEventArgs e)
{
_EmployeeID = tbxEmployeeID.Text;
_Name = tbxName.Text;
_PayRate = tbxPayRate.Text;
_Email = tbxEmail.Text;
var employeeDetails = $"{_EmployeeID},{_Name},{_PayRate},{_Email}";
// Modify the ObservableCollection.
// Since ListBox is observing this collection, it will automatically update itself
this.StaffDetails.Add(employeeDetails);
}
}
MainWindow.xaml
<Window>
<!-- Alternative option 3: XAML data binding (recommended) -->
<ListBox x:Name="lbxStaffDetails"
ItemsSource="{Binding StaffDetails}" />
</Window>
I'm working on a small program as part of my A Level Computing course that is designed to track orders. It is written in C# using the Windows Forms.
I am having an issue where I enter all the information for a new order and then press OK and it should update the ListView with the information. I have my ListView in Detail view with 4 columns but nothing ever gets added to the ListView. The section of code that should add the items to the ListView is being executed and is not throwing any errors or causing the program to crash but nothing is being added. Its weird because I am using the exact same method that I used in my little prototype mock up but for some reason now it is not working.
All the things I've found on here or on the internet seem to suggest its an issue with the View mode of the ListView and I've tried modifying this property to no avail.
Any ideas why this section of code is refusing to add anything to the ListView?
//Create an array to store the data to be added to the listbox
string[] orderDetails = { Convert.ToString(id + 1), rNameBox.Text, dateBox.Value.ToString(), orderBox.Text };
//DEBUGGING
Console.WriteLine(orderDetails[0]);
Console.WriteLine(orderDetails[1]);
Console.WriteLine(orderDetails[2]);
Console.WriteLine(orderDetails[3]);
//END DEBUGGING
//Add the order info to the ListView item on the main form
var listViewItem = new ListViewItem(orderDetails);
ths.listView1.Items.Add(listViewItem);
If you need any more information just say. Apologies if this is in the wrong format or something this is my first time here.
Your problem is that your ListViewItem contains a string array and it has no useful way of displaying it.
What you should be doing (there are a number of ways of doing this, but here's one) is creating a class, OrderDetail, with an Id, a Name, a Date, and so on. Give it a ToString() method (public override string ToString()) which returns what you want to display, e.g.:
public override string ToString()
{
return this.Name;
}
Create an instance of OrderDetail and set its properties. Create ListViewItem giving it the OrderDetail instance and add to the ListView. Repeat for as many OrderDetail instances you want.
Cheers -
Added: code which works:
int id = 12;
string rNameBoxText = "rName";
DateTime dateBoxValue = DateTime.Now;
string orderBoxText = "order";
string[] orderDetails = { Convert.ToString(id + 1), rNameBoxText, dateBoxValue.ToString(), orderBoxText };
//DEBUGGING
Console.WriteLine(orderDetails[0]);
Console.WriteLine(orderDetails[1]);
Console.WriteLine(orderDetails[2]);
Console.WriteLine(orderDetails[3]);
//END DEBUGGING
this.listView1.Columns.Clear();
this.listView1.Columns.Add("Id");
this.listView1.Columns.Add("rName");
this.listView1.Columns.Add("Date");
this.listView1.Columns.Add("Order");
this.listView1.View = View.Details;
//Add the order info to the ListView item on the main form
var listViewItem = new ListViewItem(orderDetails);
this.listView1.Items.Add(listViewItem);
I am worried about my application because the longer I use it, the more memory it consumes. I am using Silverlight-enabled WCF service to retrieve datas from the database.
Let me explain the application. There is DataGrid and a frame in MainPage. User enters some datas and after clicking Search button, service gets datas from database and fills the DataGrid. And after this, user can select row and application changes URI of the frame from the ViewModel like that:
// Sending selectedId as Query string
FrameURI = new Uri(
string.Format("/Views/PersonDetails.xaml?SelectedID={0}",
SelectedID,
UriKind.Relative);
I am getting datas of the person with the given ID in OnNavigatedTo event and calling a method which return object with the type of Person:
_id = this.NavigationContext.QueryString["SelectedID"];
if (_id != "")
{
Uri address = new Uri(Application.Current.Host.Source, "../UserServiceName.svc");
UserServiceNameClient client = new UserServiceNameClient("CustomBinding_UserServiceName", address.AbsolutePath);
client.GetPersonByIDCompleted += (sender, event) =>
{
if (e.Result.Name != null)
{
LayoutRoot.DataContext = (Person)e.Result;
}
};
client.GetPersonByIDAsync(_id);
}
But the problem is here. It seems that GC is not kicking in after selecting new id from the DataGrid. After changing selected row in DataGrid, memory of the application keeps growing up. And the storyboards/animations become laggy...
I have read some posts in web, some of them tell that, it is about event handlers. I have tried somethings, but didn't help.
Thanks.
I actually display on my Listbox this list of item that i retrive from XML . When I click on an Item i am going back to the same method and creating a new list to display with different items.
I am wondering why it's not clearing the previous list.
This is the code I use, I can't figure this out ..
if (e.Error == null)
{
// Retrieving the subfolders
XDocument xdoc = XDocument.Parse(e.Result, LoadOptions.None);
XNamespace aNamespace = XNamespace.Get("http://schemas.datacontract.org/2004/07/System.IO");
var folders = from query in xdoc.Descendants(aNamespace.GetName("DirectoryInfo"))
select new Folder
{
Name = (string)query.Element("OriginalPath"),
};
ObservableCollection<Folder> LFolders = new ObservableCollection<Folder>();
foreach (Folder f in folders)
{
LFolders.Add(f);
}
listBox1.ItemsSource = LFolders;
listBox1.SelectionChanged += new SelectionChangedEventHandler(listBox1_SelectionChanged);
}
Two suggestions:
Consider using the MVVM pattern and then storing and updating your ObservableCollection on the view model instead.
Set the SelectionChanged event in XAML instead of where you're setting it now. For every call to this method you're appending an additional event handler to your listBox1.
If you set the Itemssource to null before you set the new value, I believe that will work. Also, you can try making LFolders a class variable. When you begin the method, clear the collection and then add to it. THe observable collection that is bound to the listbox will take care of updating the listbox.