My code is looping through operations and is adding feedback to a listview control. Previously, my code has been working OK, but something has changed today...
The listview control starts off like this:
...but after I issue a call to Update() or Refresh(), rather than show the items that I have added, it renders like this:
At this point, the control is still enabled and visible. In fact the only interaction my code has with it is to add new items and Update().
To add items, I'm using the following:
lvwDrawings.Items.Add(new ListViewItem(new string[]
{
drawing.PartNo,
drawing.Revision.ToString(),
drawing.Issue,
drawing.DrgTypeText,
errorStatus !=null ? errorStatus : drawing.Status,
drawing.Filepath
}));
In case I'd introduced some problem here, I tested with the simpler lvwDrawings.Items.Add("test");, but the result was the same. If I do a QuickWatch, the control correctly tells me that it contains x items...
OK, I've found the problem - for some unknown reason, where I'd previously had lvwDrawings.Items.Clear() to clear the list between different runs, I somehow ended up with lvwDrawings.Clear(). This clears not only the items in the listview, but also the columns.
It's curious on two counts: I would have though that when I tried to add a ListViewItem with specific columns that it would have objected when there weren't any columns, and also, what on earth did I think I was doing when I made the change(??!).
Moderately interesting diversion:
I discovered the problem by creating a second listview below the first, and working through until I hit the problem. As part of that process, I added columns in the design, one of which I called Path, to which the designer didn't object.
However, in the code, references to methods of the static class Path (e.g. Path.GetDirectoryName()) resulted in an error - 'ColumnHeader Path does not have a method 'xxx'' or similar. Clearly, it assumed that when I referred to Path, I was referring to the column within the listview.
Furthermore, when I went to rename the column (to 'FullPath'), it renamed all references to Path in the code, eg. FullPath.GetDirectoryName()....
Related
I need to change Visibility of all items in listbox in code based on changing some filters. I tried to loop the items using
myListbox.ContainerFromIndex(i)
but only first a few didn't return null. The answer why I quickly found here:
Why ItemContainerGenerator.ContainerFromIndex() returns null and how to avoid this behavior?
Turning off virtualization doesn't look like respectable solution to me, also I don't feel well about scrolling every item to view before calling ContainerFromIndex, even if it could probably work.
I'm not very clever from the rest of topics dealing with bindings and dependency properties etc, maybe also because majority of them are written in xaml and not in code. But I'm pretty sure the answer should be there. I'm very new to c# and I didn't find any clear-cut solution to such a basic problem.
I will prepare something like this array of Visibilities
Visibility[] visibilities=new Visibility[100]
...
and I want myListBox with 100 items to use these values. Either automatically with some c# magic or in a cycle as I used to do in Win32.
Based on the comment of Depechie, I made a research targeted on collections and created a functional code. Here is what I did:
Instead of adding items directly to listbox by
lbGames.Items.Add(...)
I created two collections:
List<object> gameList=new List<object>();
ObservableCollection<object> filteredGameList = new ObservableCollection<object>();
Adding items this way:
gameList.Add(...); or filteredGameList.Add(...)
While gameList is holding all items (stack panels), filteredGameList is holding only those I want visible. I had some problems with using only one big collection using its Visibility property, maybe my mistake, maybe not.
Withouth ObservableCollection I wasn't able to redraw listbox, that was problem with another List<> holding filtered data. When I filter data, I first clear filteredGameList and then I add all items I want visible, never changing Visibility property. ObservableCollection always tells listbox when items change.
On the application init, I attach listbox to this filteredGamesList.
lbGames.ItemsSource = filteredGameList;
Now everything works fine.
I'll try to explain best I can.
I have a ListView in visual studio c# form, with a function to populate it. When I recently tried to update that ListView by adding a column, it just showed only previous columns populated. Then, for an even greater surprise. When I changed function text in order to populate "old" columns a bit differently just to make sure it works (like, adding string "test string" to a column populating string) nothing happened - it just stayed the old way. After that, I completely erased population function body, leaving nothing inside brackets - and listview was still populated with data, like it called the original version of function, even though I had just erased it completely. Left me puzzled. Failed to google anything similar. More funny stuff - i put a MessageBox into function body just to make sure that "new" function is called at all. And yes, MessageBox is being displayed so it actually accepts that change of function. Code to show it:
private void populateMissionList()
{
this.listView1.Items.Clear();
List<MisijaDTO> misije = MisijaDAO.ocitajSve();
foreach (MisijaDTO mission in misije)
{
string idmisije = "" + mission.Id;
ListViewItem stavka = new ListViewItem(idmisije);
stavka.SubItems.Add(mission.Naziv); // "old" column
stavka.SubItems.Add(mission.Datum + " test string"); //"old" column, but won't show newly added "test string"
if (mission.Uspjesna){
stavka.SubItems.Add("Uspješna"); // "new" column, won't be shown...
MessageBox.Show("282 true"); //... but this text box is shown
}
else {stavka.SubItems.Add("Neuspješna");MessageBox.Show("282 false");}
listView1.Items.Add(stavka);
}
}
My best guess why this happened - I have previously cut that listView from the form, pasted it onto another form (which I used as a backup), and later copied it from backup form and pasted it back onto original form. I suppose ListView somehow got stuck with the old function definition, but I wasn't able to solve it. Tried to: rename ListView, rename population function, clean solution, rebuild solution, close and reopen Visual Studio... nothing helped. It's not database problem either, because it will read new database imports into ListView, but limited to "old" set of columns like it won't recognize ListView that I pasted back. ListView name remaine same after cut/paste/copy/paste, so I guess that's not issue either.
If you need some more information, I'd be glad to provide.
Look in the .designer.cs file where the Column Collection is populated. You probably need to add another column into that....
I owe A BIG apologie to anyone who spent their precious time reading this topic. There isn't any bug or something, but I overlooked some piece of code that was related to my function and that populated list the old way separately. Seems everything works just fine right now.
Good side of this is that I signed up for Stack Overflow finally :)
I've got two clear LongListSelectors - without any modification, just dragged from toolbox and changed name.
I'm using code below to fill them (one of them needs to be sorted):
closestList.ItemsSource = spots;
allList.ItemsSource = spots.OrderBy(x => x.name).ToList();
The first list is working fine, but the second one is empty - there is no error. When I change the second line to: allList.ItemsSource = spots; it's working fine.
What is wrong with that sort?
At the moment that you're writing the code that you have, spots is empty and contains no items. When you define the source of the data as a reference to spots it is capable of recognizing when items are added (if spots is an observable collection, which it does appear to be) which means that in the future, when items get added to spots, the UI will be updated.
Your second snippet isn't setting the data source as a reference to spots, but rather as a copy of the collection at that instant in time. At that instant in time it's empty, and since the act of copying it has now divorced that data source from spots it will never be notified when items are added to spots, so it stays empty.
So I have a dropdown menu in a ribbon with contents that can be changed while it is being used. Outlook is also happy to let me 'add' or 'insert' items into it, as long as I do not add more than 1 item.
If I try to, I'll be told that the index is out of bounds rather than expanding the upper bounds for me.
I find that if I insert it into the collection in the designer portion of the code, it will work fine, but designer code is only run once, unless I Dispose the ribbon and re-create it.
Any ideas regarding how I can get this working
Try this. This should work for you.
RibbonDropDownItem item
= Globals.Factory.GetRibbonFactory().CreateRibbonDropDownItem();
item.Label = "First Name";
this.cbRecent.Items.Add(item);
Try the following directly inside the Ribbon Class:
RibbonDropDownItem item = this.Factory.CreateRibbonDropDownItem();
item.Label = "Text";
combo.Items.Add(item);
jeds, your approach doesn't work with "new". You have to use the "Globals.Factory.GetRibbonFactory().CreateRibbonDropDownItem()". Otherwise, you are right and your approach works great with a RibbonGallery.
That approach also works great with a DropDown. I'm still often conflicted about which one to use...
However, other than those 2 objects (Dropdown and RibbonGallery), I believe drventure is correct. You simply have to stub out the objects ahead of time and use them as needed.
You can also use the XML Ribbon, but that creates an even bigger set of headaches (at least for my use cases).
Try using a Ribbon Gallery. I have been able to modify them during run-time with as little as
foreach (string s in list)
{
RibbonDropDownItem item = new RibbonDropDownItem();
item.Label = s;
rGallery.Items.Add(item);
}
where rGallery is a RibbonGallery.
Generally speaking, VSTO wants you to completely describe the UI elements you need one time, the very first time you're asked for them (via GetCustomUI).
I've run into similar probs before with vsto and about the only reasonable way around it I've found was to prepopulate (via the designer) all the elements you might need (so let's say 10 items in your drop down list).
Then, programmatically HIDE or SHOW those items and update their captions and other properties as necessary while your addin runs.
That way, you never have to dynamically add or remove anything.
Ok, I'm utterly confused by this situation, so bear with me.
In my application, if you click on a button I have an editor form open
dgEditor = new fmDataGridFieldEditor();
dgEditor.ShowDialog();
This works fine, and my form shows up and operates correctly. The form has a data grid in it with some specified fields. Now, if I then change data in one of the columns of the datagrid (a column that is just meant for numbers) and then change the sorting order by clicking on the column header, my form crashes. with an ArgumentException error that says "Object must be of type Int32" on the dgEditor.ShowDialog(); line.
I don't understand what is going on or even how to start debugging this. This doesn't happen when I modify existing rows, or if the rows I enter are already sorted (e.g. 0,1,2 is fine but 0,1, 0 causes the crash).
Furthermore, I have visual studio 2010 setup to break on all exceptions, not just unhandled ones, but I'm getting an exception in the same place.
Finally, I tied the data grid's ColumnSortModeChanged event to show a message box, but even when the sorts don't crash the form, the message box doesn't show.
I'm at a loss on how to proceed with this.
The debugger shows the last line of code that you wrote. Which is the ShowDialog() call. If you look at Debug + Windows + Call stack then you see the methods in the .NET framework that are involved. Scroll the window up if necessary to see them all. DataGridView has a lot of built-in functionality, the source code isn't readily available although you can get it from the Reference Source. Not that this will help much, there's rather a lot of it.
Clearly there's some invalid data in one or more rows. Looks like a leading space, only guessing here without sitting in front of your machine. Implement the CellValidating event so the user cannot enter an improperly formatted number.
I just had this happen to me in VB. What I discovered was that when I copied the values from a textbox into the grid I didn't do a cast to int. Being VB I assumed it would cast implicitly, but the cell value is, I guess, an object, so it happily took a string. Everything looked right and worked right, until I happened to sort on that column. Maybe this will help someone else.
ShowDialog will throw an error if you are trying to create a PictureBox dynamically on the TableLayoutPanel. It does not allow two PictureBox elements to add a similar index on the Table or you could have a error if your are using MemorySTream and not closing it properly.