C# Combobox not displaying items - c#

I am trying to populate a combobox in C#, but for some reason, the items do not appear.
public List<string> items
{
set
{
combobox.Items.Clear();
foreach(string s in value)
{
combobox.Items.Add(s);
}
combobox.Update();
}
}
This seems like incredibly straightforward code. I simply cannot see what is wrong.
It is being called like this:
private void StoreNames(List<string> names)
{
if (selectionForm.InvokeRequired)
selectionForm.Invoke((MethodInvoker)delegate { selectionForm.items = names; });
else
selectionForm.items = names;
}
Interestingly, it seems to work when InvokeRequired returns true, but does not work when it returns false.
EDIT:
I discovered that selectionForm.IsHandleCreated is currently false. This is causing InvokeRequired to return false, but is also why calling the setter regularly isn't working. I don't have any idea why IsHandleCreated is set to false. The Form has been Show()n.

Not sure why your code isn't working - I tried it and it works just fine.
However, below is some more straightforward code which also works - you may find that doing it this way instead makes your problem go away. This does presume that there is not other reason why you need to go through that property - that is quite an unusual way of doing things.
public void StoreNames(List<string> input)
{
if (comboBox1.InvokeRequired)
comboBox1.Invoke((MethodInvoker)delegate {
StoreNames(input);
});
else
{
comboBox1.Items.Clear();
comboBox1.Items.AddRange(input.ToArray());
}
}
Here we just pass the list straight to the items.AddRange() method on the comboBox.
I suspect this won't work for you - something else is going on, but I have tried it both from a backgroundworker (where InvokeRequired is true) and from the main UI thread.

Is it a typo that you refer to both combobox and combobox1? Perhaps that is your error.

Do you mean "not appear" as in you can see them when the list displays, or as in you can't even scroll to them?
Combobox has a lot of properties that can affect what you see. Try a bigger value for combobox.MaxDropDownItems.

My other answer in this thread is really just showing the way to doing this if you can get at the code providing you with the list. Since it sounds like you cannot, I'm providing this answer.
It sounds like the key problem is that when the property is called the combobox has not yet been initialized. The best answer for that is that make sure that this does not happen within the calling code.
If you can't do that then you should wait for the property to be set before you use it to populate the combobox.
I would do this be having a private list which gets set in the property setter. Within the form load event i would then put some code (possibly within a background worker) that will wait until the private list is not null and then assign it to the combobox.
Have a look at this post by Jon Skeet here where he discusses how to correctly wait for a variable to be set by another thread. You will want to be careful when doing this - threading issues can be nasty.

Related

In WPF two-way binding, how can you check if it was a UI element or ViewModel that triggered the binding change?

I'm not sure what keywords to search for...lost in a sea of Google.
I have a two-way databinding specified between a visual element (slider bar) and a numeric value in my ViewModel. I want to differentiate between when a value change is user-initiated vs ViewModel-based, so that I can selectively trigger an event elsewhere in my application. How can I do this in the code-behind of the XAML file?
Update 2015-02-26: In reply to Amit's question, WHY I need this capability is that I actually have more than one visual element set up for 2-way databinding to the same ViewModel source, so not differentiating leads to an infinite loop (stack overflow) in callbacks to dependent code that itself has the ability update the same values.
Aside - shouldn't there be reputation points for the first time one appropriately ues "stack overflow" on SO?
Your best bet is not to have two different behaviors. You need to fire the same notifications and recalculate the same dependent properties either way. But I've run into cases where, say, sometimes I want to fire off an animation and sometimes I don't, so different behaviors can be necessary.
If you really do need two different behaviors, I would just make two different properties (or a property and a method). Bind one property to the UI, and use the other when you're setting the value programmatically. Give each one the side effects it needs to have.
Not only does this keep things simple, it also means you can write unit tests for both sets of behaviors.
I think the short answer is: not really.
When you bind to a ViewModel property from your XAML element, ultimately the WPF binding system will call the property setter in the ViewModel. Once inside the setter method you have no context as to how you got there. You could possibly check the stack to see where you came from but that would be very brittle code and presumably quite slow as well.
If the property was only being set by either the XAML binding or by the ViewModel, then you could set some kind of Boolean flag in your ViewModel like so:
bool _isBeingSetByVM;
public int Number
{
get { return _number; }
set
{
if (_isBeingSetByVM)
{
// ViewModel has set the property
// Do whatever you need to do...
_isBeingSetByVM = false;
}
if (_number != value)
{
_number = value;
OnPropertyChanged("Number"); // generate PropertyChanged event
}
}
}
int _number;
void SomeMethodInVM()
{
_isBeingSetByVM = true;
Number = 42;
}
But again, this is very brittle code that is hard to maintain. As #Amit says in his comment, the better question might be why you need to do this.

c# ArgumentOutOfRangeException

I Have this piece of code:
private List<...> LayPrices;
public Decimal BestLayOdds
{
get
{
if (LayPrices.Count > 0)
{
return LayPrices[0].dOdds;
}
return 1000.0M;
}
}
The Problem is that sometimes the List has items, but it does not enter inside the 'if' statement.
Check the images below of a debug session:
How is that even possible?
But if I force it to return the first item, on the last return statement, I get an ArgumentOutOfRangeException even though the list has elements. Check the nest image:
Is there any problem with my code or it is just a stupid bug?
Update:
The LayPrices List is only instantiated on the class Constructor: LayPrices = new List<PriceStruct>();.
It is only getting filled with items on one method, whith the following code:
LayPrices.Clear();
foreach (PriceSize priceSize in exchangePrices.availableToLay)
{
PriceStruct lay = new PriceStruct();
lay.dOdds = (Decimal)priceSize.price;
lay.dAmount = (Decimal)priceSize.size;
LayPrices.Add(lay);
}
Concurrency issues and threading were my first clue, so I did put a lock(LayPrices) and the problem still persisted:
So I think it is not a concurrency issue.
Put Debug.Assert(LayPrices.Count > 0) in the getter before the if statement and you'll see that the List is in fact empty.
The only reasonable explanation is that you are populating the list either in some other thread and you have a race condition or in a property getter that only gets fired by the debugger (you could also be populating the list in a catch clause up the callstack but I imagine you would have figured that out by yourself)
In order to get a better answer please include all code that populates your list. No only the code you think should run, but all the properties, constructors or methods that add or remove items from the list.
I found the problem.
It was indeed concurrency issues, even though I don't use threads explicitly, I use events and I thought event handling was synchronized (It is synchronized right?).
If I add locks everywhere I read or add to the list, the problem disappears.

WPF ObservableCollection : possible to modify one particular property on all items at once?

I got an ObservableCollection (Zone class contains a IsFiltered boolean property) on which several items got theirs IsFiltered property set to true.
For a few cases, I need to unilateraly remove all filters (i.e. set IsFiltered prop to false for all ObservableCollection items).
Is there a way to achieve this the way ObservableCollection.Single(LINQ request) do it, or do I have to loop on my ObservableCollection to set this prop to false on all items?
Thanks for your answer !
You'll have to loop but at least restrict your loop to the objects that need resetting:
foreach(var zone in zones.Where(z => z.IsFiltered))
{
zone.IsFiltered = false;
}
As other answers/comments have mentioned, avoid Linq for the update. See Jon Skeet's answer https://stackoverflow.com/a/1160989/1202600 - Linq is for querying, not updating.
I am not sure if this is what you are looking for, but Lists in C# got ForEach method which kind of does what you want, so:
myObservableCollection.ToList().ForEach(x => x.MyFlag = false);
Posting my thoughts (since you haven't accepted any answer as yet - please consider if you have moved on)
There is no other way than iterating through 'ObservableCollection'. You may find APIs (linq) to do that for you, but in the end it has to iterate through all objects to update their state.
If your collection is updated by other threads then you need to consider thread safety also (it will through exception if other thread updates while you are iterating to update IsFiltered)
Other point is updating a property doesn't reflect in binded UI unless that property raises 'NotifyPropertyChanged' event. So your object should have something like below:
public bool IsFiltered{
get { return _isFiltered; }
set {
if (_isFiltered == value) return; //no need to modify and trigger UI update
_isFiltered = value;
}

How can I iterate through a BindingSource items in Compact Framework c#

I hope there is somewhere a guru that can help me out on this.
I am creating a custom control for a windows ce mobile device. I created a property so that the user can bind any source to my control. I need to iterate through the source and get the item value for the display member path.
I declare my source and then create the property. In the construct I have an event registered if the source change so that I can start painting my object again. This is my first time working with binding source from this angle. Am I missing something or using it wrong? Here is some code snippets
private BindingSource _bindingCollection;
public object DataSource
{
set { _bindingCollection.DataSource = value; }
}
public string DisplayMemberPath { get; set; }
ctor()
{
_bindingCollection.DataSourceChanged += _bindingCollection_DataSourceChanged;
}
void _bindingCollection_DataSourceChanged(object sender, EventArgs e)
{
foreach (var item in _bindingCollection)
{
//I am stuck here on getting the value from the item that is
// specified by DisplayMemberPath to paint my objects on the control
//I can only paint on the control and cannot add any controls to it.
//So here a method is called with the value as a parameter and the
//Graphics object will draw the string
}
}
Thanks in advanced.
Regards
Riaan
EDIT:
Dude I know you use on paint method to paint, this is an example of what I want to do. I create everything from scratch, the entire control is drawn from code and I override all the needed events. Maybe set the _bindingCollection.DataMember in the DisplayMemberPath? Will that then give the item when iterating through the source? Will test now and post answer if it works. Please no more comments or answers telling me to use on paint or something like that. Concentrate on question of getting the display member value from the collection :)
Edit: Found the answer
Ok sorry this was actually a really stupid question that I asked while being busy with a lot of things. This was actually easy to get the property value.
for (int index = 0; index < _bindingCollection.Count; index++)
{
var propertyValue = _bindingCollection[index].GetType().GetProperty(DisplayMemberPath ).GetValue(_bindingCollection[index], null);
// Can do anthing now with the value here or just create a
//method of returning this value with this line of code on top.
}
The question can be deleted if someone needs to delete it. I will leave it here if there is anyone else to much in a hurry for this solution and do not know how to get it. These are just code snippets and not in anyway methods that can be used.
I am just marking the question as answered. Read my edits to see my stupid thinking mistake and why it was easy.
I will leave the post for people that may go and think the same as me and struggle unneccarily unless someone feels the question must be deleted you can go right ahead.

Stack overflow exception without infinite loop (as far as I can tell)

I have a stack overflow error, and I'm fairly sure I don't have any kind of infinite recursion (at least I've stared at the error for a few hours now and I can't imagine how its looping infinitely).
Here is the code:
public decimal? Amount
{
get
{
if (!string.IsNullOrEmpty(_savedWork.Amount))
return decimal.Parse(_savedWork.Amount);
else
return null;
}
set
{
if (value.HasValue)
{
_savedWork.Amount = value.Value.ToString();
Percent = null;
}
else
_savedWork.Amount = "";
OnPropertyChanged("Amount");
}
}
#Note I have a string housed in a nullable decimal, that's why I'm converting it. Please don't make me go into why I'm doing this.
the line savedWork.Amount = value.Value.ToString() is where I get the error.
Basically I'm thinking that my stack is just too small (or my code is too big I suppose). I basically run this code twice, and it works when in one form, but not when I make another form and place it in there, so I think the difference between these 2 forms is tipping the stack.
Is there a way to identify what I'm doing wrong? I want to find out what part of the code is taking up a too much or is persisting too long etc.
I've done some research about how the stack/heap work and I know about PerfMon.exe, but as far as I know it only works for the heap. Is there a similar tool that I can use for the stacks my program is running?
I found this post about 2 tools called windbg and cdb but I can't find much about how to install/use them. Are these tools the right way to go?
Alternatively if there is an infinite loop or something that would be great.
Edit
here is the code requested for the Amount Property (its autogenerated by EntityFramework) as I said in the comments, the step into doesn't even reach here. I really do think my stack limit is just being reached.
public global::System.String Amount
{
get
{
return _Amount;
}
set
{
OnAmountChanging(value);
ReportPropertyChanging("Amount");
_Amount = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Amount");
OnAmountChanged();
}
}
Final Edit
Ok so Meta-Knight's answer showed me that I did indeed have an infinite loop. I had an event handler subscribed to the PropertyChanged event of the DisplayTypeOfInvestment (the class that the Amount Property belongs to). The handler looked like this:
void DisplayTypeOfInvestmentList_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
_typeOfInvestmentFormSavedWork.TypeOfInvestment.Clear();
foreach (DisplayInvestmentFund d in _displayInvestmentFundList)
{
_typeOfInvestmentFormSavedWork.TypeOfInvestment.Add(d.SavedWork);
}
OnPropertyChanged("TypeOfInvestmentFormSavedWork");
}
The TypeOfInvestmentFormSavedWork is a completely different class that contains in it it's own version of the SavedWork class that we see that is used an the Amount property. The point of this method was to update this TypeOfInvestmentFormSavedWork property to the new value of _savedWork when the Amount property changes. For some reason this is triggering the DisplayTypeOfInvestment viewmodel's PropertyChanged. I didnt figure it out but I changed the method to look like this:
void DisplayTypeOfInvestmentList_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Amount" || e.PropertyName == "Percent")
{
_savedWork.TypeOfInvestment.Clear();
foreach (DisplayInvestmentFund d in _displayInvestmentFundList)
{
_savedWork.TypeOfInvestment.Add(d.SavedWork);
}
OnPropertyChanged("CurrentWork");
}
}
The if statement stops the weird properties being changed in the DisplayInvestmentFund when the Add method is called.
I realise this answer doesnt make much sense, but for me to explain this in full detail would take a very long time. I also realise that this probably means my code is bad. I'm not sure what to do about that. Thanks for the help guys.
My guess is that you're assigning to Amount in one of the event handlers that OnPropertyChanged calls.
Another possibility is that you have code in the setter of SavedWork.Amount that calls YourClass.Amount again.
But why don't you just debug it? Just step through the code in the Visual Studio debugger.
The stack trace should also be useful. With endless recursion you typically get a repeating sequence of methods. If my guess is correct the repeated part will be something like:
MyClass.set_Amount
MyClass.OnPropertyChanged
OtherClass.myClass_amount_changed
Is the class of which Amount member of the same type as _savedWork?
Because there could be this loop:
1) You assign a value to Amount
2) Before the value is set, you assign a value to _savedWork.Amount
3) Before the value of _savedWork.Amount is set, the line is triggered again
4) Before the value of _savedWork._savedWork.Amount is set...
5) Before the value of _savedWork._savedWork._savedWork.Amount is set...
And this goes to infinity and beyond.
There must be a recursive call to the Amount setter somehow. You could debug it by "stepping into" the properties instead of stepping over. If you set VS so that it doesn't step into properties, you can still put a breakpoint inside your setters to simulate a "step into". As for VS not stepping into .edmx files, as CodeInChaos mentioned, maybe the class is tagged with a DebuggerStepThrough attribute.
Is _savedWork an object of the same type as the Amount property you listed? Because that will give you a stack overflow error! In that case, you need to find a way to talk about Amount without invoking the getter and setter.

Categories

Resources