Not able to set "SelectedValue" in Combobox bound with enum - c#

I want to set default value (rather than first one) in combobox through SelectedItem/SelectedText/SelectedValue (from any one way).
I have tried to resolve it through many different ways. Like I have set enum to Key Value Pair. Tried to use "SelectedIndex". It is showing '-1' while debugging. In other "selected*" options, value is 'null'. I do not know what is happening. I have attached code. Please take a look and help me to resolve it. Thank you.
ComboBox cmbxType= new ComboBox();
cmbxType.FormattingEnabled = true;
cmbxType.DropDownStyle = ComboBoxStyle.DropDownList;
cmbxType.Margin = new Padding(3, 6, 3, 3);
cmbxType.Name = "cmbxType";
cmbxType.Size = new System.Drawing.Size(200, 28);
cmbxType.TabIndex = 1;
cmbxType.DataSource = Enum.GetValues(typeof(StateType));
cmbxType.SelectedIndexChanged += new System.EventHandler(cmbxType_SelectedIndexChanged);
cmbxType.ValueMember = (workflowRows).ToString();
cmbxType.SelectedValue = 2
PS: I am creating this combobox after creating form and the problematic case is with enum only.

According to this Stack Overflow question you can only set the selected item after the data bindings are assigned. If you select the item when the OnLoad event occures it should work. Below is a working example.
using System;
using System.Windows.Forms;
namespace WindowsFormsApp
{
static class Program
{
internal enum StateType
{
State1,
State2,
State3
}
internal class DemoForm : Form
{
ComboBox cmbxType = new ComboBox();
public DemoForm()
{
cmbxType.DataSource = Enum.GetValues(typeof(StateType));
Controls.Add(cmbxType);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
cmbxType.SelectedItem = StateType.State3;
}
}
[STAThread]
static void Main()
{
Application.Run(new DemoForm());
}
}
}

Related

C# - variable reference does not exist in the current context

I have this code in the main window class where I declare some values to put in a ListForTesting list and make the tests appear in a combobox. Later there is another combobox that depends on the first on which I present you the code down bellow:
It may be worth to mention that I am completely new to C#. Only coded in VBA. I'm a mechanical engineer, not software :)
Main Window code
public MainWindow()
{
InitializeComponent();
grid_projectConfig.Visibility = Visibility.Collapsed;
grid_projectOverview.Visibility = Visibility.Collapsed;
grid_test.Visibility = Visibility.Collapsed;
grid_reports.Visibility = Visibility.Collapsed;
//ListForTesting holds the hardcoded set of tests and manoeuvres
List<HelpClass.TestID> ListForTesting = new List<HelpClass.TestID>();
//TestObject holds the test name, ID and all the manoeuvres related to it
HelpClass.TestID TestObject = new HelpClass.TestID();
TestObject.testName = "Steady State";
TestObject.ID = 0;
//Manoeuvre holds the manoeuvre name and its ID
TestObject.Manoeuvres = new List<HelpClass.ManoeuvresID>();
HelpClass.ManoeuvresID Manoeuvre = new HelpClass.ManoeuvresID();
Manoeuvre.manName = "30 kph";
Manoeuvre.manID = 0;
//add the Manoeuvre to the TestObject
TestObject.Manoeuvres.Add(Manoeuvre);
//create new Manoeuvre
Manoeuvre = new HelpClass.ManoeuvresID();
Manoeuvre.manName = "50 kph";
Manoeuvre.manID = 1;
TestObject.Manoeuvres.Add(Manoeuvre);
//add the TestObject to the ListForTesting
ListForTesting.Add(TestObject);
//display the tests in a combobox
combobox_testType.ItemsSource = ListForTesting.Select(t => t.testName);
}
Second combobox code
public void combobox_testType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
combobox_testType.ItemsSource = ListForTesting[1].Manoeuvres.Select(t => t.manName);
}
this last line of code does not work because it tells me that it does not exist in the current context.
The problem is the scope of the variable ListForTesting: by declaring it inside your MainWindow constructor you limit its visibility to that method.To allow to access ListForTesting from another method in your class (i.e.: combobox_testType_SelectionChanged) you have to declare it as a class-level variable like so:
public class MainWindow : Window
{
private List<HelpClass.TestID> ListForTesting; // Variable declaration
public MainWindow()
{
// code
ListForTesting = new List<HelpClass.TestID>(); // Initialization
// code
}
}
the variable ListForTesting is in the scope of the constructor. You need to move the variable out of there for it to be accessible elsewhere in the class.
List<HelpClass.TestID> ListForTesting;
public MainWindow()
{
...
ListForTesting = new List<HelpClass.TestID>();
...
}

How to Give back a DataGridView in Winforms

So, I have a project in which I allow editing of a DatagridView in a separate Form. I pass in the DatagridView object and its parent container to the constructor of the new Form.
This works well and I can edit the grid that way. But when I try to give it back by changing its parent back to the original form, I get this error :
Cannot convert type 'System.Windows.Forms.MenuItem' to 'System.Windows.Forms.Control'
Now both MenuItem, and Manual Entry directly inherit from Form.
Here is my code that takes the DataGridView from the original form (which works correctly)
public partial class ManualEntry : Form
{
private Data d;
DataGridView DataView;
MenuItem mi;
public ManualEntry(DataGridView ExcelDisplay, Data d, MenuItem menuItem)
{
InitializeComponent();
//Take the Datagridview from the MenuItem.
DataView = ExcelDisplay;
DataView.Parent = this;
mi = menuItem;
this.d = d;
this.DataView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.DataView.Location = new System.Drawing.Point(15, 76);
this.DataView.Size = new System.Drawing.Size(237, 211);
this.DataView.TabIndex = 5;
this.DataView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataView_CellContentClick);
}
Now here is me trying to give it back. and of course it produces the error above.
private void FinishButton_Click(object sender, EventArgs e)
{
//move the datagridview back to the original form and give its old size,shape, and position back.
DataView.Parent = mi;
this.DataView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.DataView.Location = new System.Drawing.Point(12, 167);
this.DataView.Name = "ExcelDisplay";
this.DataView.Size = new System.Drawing.Size(250, 256);
this.DataView.TabIndex = 7;
this.Close();
}
I have also tried casting which does not work either.
DataView.Parent = (System.Windows.Forms.Control)mi;
Update
This shows that MenuItem is a Form as well.
public partial class MenuItem : Form
{
This shows that MenuItem is a Form as well.
Well, you have not convinced the compiler. You can tell from the error message that it thinks that your "mi" variable is a System.Windows.Forms.MenuItem. Do not use .NET class names for your own types, that just makes your life harder to troubleshoot bugs like this. Don't use variable names like "d" either. Choosing good names is a Very Important programmer's job.
The proper way is to preserve the control's Parent property so you can set it back. Roughly:
public partial class ManualEntry : Form
{
private Data DataViewData;
private DataGridView DataView;
private Point DataViewLocation;
private Control DataViewParent;
public ManualEntry(DataGridView ExcelDisplay, Data data)
{
InitializeComponent();
this.DataViewData = data;
this.DataView = ExcelDisplay;
this.DataViewLocation = ExcelDisplay.Location;
this.DataViewParent = ExcelDisplay.Parent;
this.DataView.Parent = this;
// etc...
}
protected override void OnFormClosing(FormClosingEventArgs e) {
base.OnFormClosing(e);
if (!e.Cancel) {
DataView.Parent = this.DataViewParent;
DataView.Location = this.DataViewLocation;
// etc..
}
}
}

How to get the devexpress lookupedit display text from the corresponding edit value

Hai all,
I want to get lookupedit display text when am giving correspond edit value.
example:
if am giving
LookupEdit1.Editvalue="3";
then it should show display text of Editvalue="3"
please help
//code
cmbChemical.Properties.DataSource = _lab.selectChemicals();
cmbChemical.Properties.DisplayMember = "labitem_Name";
cmbChemical.Properties.ValueMember = "labItem_ID";
cmbChemical.Properties.BestFitMode = BestFitMode.BestFit;
cmbChemical.Properties.SearchMode = SearchMode.AutoComplete;
cmbChemical.Properties.Columns.Add(new LookUpColumnInfo("labitem_Name", 100, "Chemicals"));
cmbChemical.Properties.AutoSearchColumnIndex = 1;
You can't, at least not in the way you're trying. The LookUpEdit, as the name implies, looks up its values in a DataSource, eg. a collection of objects. Therefore, to display the value 3 you need to have a list of objects that contains this value and set it as a DataSource for the control.
List<string> values = new List<string>();
values.Add("3");
lookUpEdit.Properties.DataSource = values;
lookUpEdit.EditValue = "3";
Maybe if you specify what are you trying to do, we can help you achieve that.
I think you don't have to specify display member or value member to get your needed behaviour. Following code give me a form with the lookupedit correctly showing "4", and i can choose other values from the list too.
using System.Collections.Generic;
using System.Windows.Forms;
using DevExpress.XtraEditors;
public class Form1 : Form
{
public Form1()
{
var lookUpEdit1 = new LookUpEdit();
Controls.Add(lookUpEdit1);
var source = new List<string>();
for (var i = 0; i < 10;i++ )
source.Add(i.ToString());
lookUpEdit1.Properties.DataSource = source;
lookUpEdit1.EditValue = "4";
}
}
Maybe you get wrong results because you set display member and value member of the control.
This code worked for me.
private void lookUpEdit1_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
MessageBox.Show((e.OriginalSource as SLTextBox).Text);
}
}

Binding a ListBox's SelectedItem in the presence of BindingNavigator

I'm trying to bind a ListBox's SelectedItem data to a property. The following code is an example:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace BindingFailure
{
static class Program
{
class OuterObject
{
public string selected { get; set; }
public List<string> strings { get; set; }
}
public static void Main()
{
List<OuterObject> objs = new List<OuterObject>()
{
new OuterObject(), new OuterObject()
};
objs[0].strings = new List<string> { "one", "two", "three" };
objs[1].strings = new List<string> { "four", "five", "six" };
Form form = new Form();
BindingSource obs = new BindingSource(objs, null),
ibs = new BindingSource(obs, "strings");
BindingNavigator nav = new BindingNavigator(obs);
ListBox lbox = new ListBox();
lbox.DataSource = ibs;
lbox.DataBindings.Add(new Binding("SelectedItem", obs, "selected"));
form.Controls.Add(nav);
form.Controls.Add(lbox);
lbox.Location = new System.Drawing.Point(30, 30);
Application.Run(form);
}
}
}
If you just select an item, move forward, select an item and then exit, it works as expected. But if you switch back and forth between the two outer objects with the navigator, the selected item seems to be overwritten with an incorrect value. It appears that every time the BindingNavigator moves to an element, the ListBox is told to move to the first item in its collection and thus overwrites whatever value used to be in the variable bound to its SelectedItem.
Ideas on how to fix this? Thanks in advance.
EDIT: Here is an archive of the example project, including a debug binary.
http://www.mediafire.com/?dzmqmz0mynj
EDIT: Here is the helper function based on the accepted answer:
public static void Bind(ListControl list, BindingSource outersource, string dataMember)
{
Binding bindSel = new Binding("SelectedItem", outersource, dataMember);
list.DataBindings.Add(bindSel);
outersource.CurrentChanged += delegate
{
list.BeginInvoke(new MethodInvoker(bindSel.ReadValue));
};
}
It happens because SelectedItem update happens before listbox is updated. So on the first stage listbox cannot "accept" value from different form record since it contains no such record and then it cannot restore selection after listbox items are repopulated.
The solution (one of) is to force SelectedItem binding to reapply after current form record is changed. First we give the binding a name:
//lbox.DataBindings.Add(new Binding("SelectedIndex", obs, "Index"));
var selItemBinding = new Binding("SelectedItem", obs, "selected");
lbox.DataBindings.Add(selItemBinding);
Than we have to reapply binding (notice BeginInvoke is essential to apply binding after listbox is repopulated):
obs.CurrentChanged += delegate
{
form.BeginInvoke(new MethodInvoker(selItemBinding.ReadValue));
};
You could also create simple helper method that will do all this tricks in one call.

ComboBox items.count doesn't match DataSource

I have a ComboBox that is bound to a DataSource. I want to dynamically add items to the ComboBox based on certain conditions. So what I've done is add the options to a new list, and then change the DataSource of the ComboBox like so:
cbo.DataSource = null;
cbo.DataSource = cbos;
cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
Then, I check cbo.Items.Count, and it has not incremented - it does not equal the count of the DataSource. Any ideas what I can do here?
Note this is WinForms and not ASP.NET.
Did you check the Count immediately or at a later time? There is the possibility that the ComboBox does not actually update it's contents until there is an operation such as a UI refresh and hence the count will be off until that time.
On case where this may happen is if you update the DataSource before the Handle is created for the ComboBox. I dug through the code a bit on reflector and it appears the items will not be updated in this case until the ComboBox is actually created and rendered.
If anyone experiences this problem on a dynamically added combobox, the answer is to ensure that you add the combobox to the controls of a container in the form.
By adding "this.Controls.Add(cbo);" to the code before setting the datasource, the problem goes away.
I've found the cause...
I took out the cbo.Datasource = null line.. and added a cbo.Invalidate() at the end. This has solved the problem.
Thanks all for the advice.
cbo.DataSource = null;
cbo.DataSource = cbos;
cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
Now before setting cbo.SelectedValue, or relying on Items to be up-to-date, call
cbo.CreateControl ;
and Items will be re-calculated.
The problem is that SelectedValue/SelectedIndex, which are WinForms properties, only accept the values that are legal according to the Items list, but that one is built only after GUI interaction, i.e. after instantiating a "real" Windows GUI combo box, i.e. after obtaining a Windows handle for the combobox.
CreateControl forces the creation of the Windows handle, no matter what.
ComboBox cbNew = new ComboBox();
cbNew.Name = "cbLine" + (i+1);
cbNew.Size = cbLine1.Size;
cbNew.Location = new Point(cbLine1.Location.X, cbLine1.Location.Y + 26*i);
cbNew.Enabled = false;
cbNew.DropDownStyle = ComboBoxStyle.DropDownList;
cbNew.DataSource = DBLayer.GetTeams(lineName).Tables[0];
cbNew.DisplayMember = "teamdesc";
cbNew.ValueMember = "id";
Console.WriteLine("ComboBox {0}, itemcount={1}", cbNew.Name, cbNew.Items.Count);
// The output displays itemcount = 0 for run-time created controls
// and >0 for controls created at design-time
gbLines.Controls.Add(cbNew);
TO
ComboBox cbNew = new ComboBox();
cbNew.Name = "cbLine" + (i+1);
cbNew.Size = cbLine1.Size;
cbNew.Location = new Point(cbLine1.Location.X, cbLine1.Location.Y + 26*i);
cbNew.Enabled = false;
cbNew.DropDownStyle = ComboBoxStyle.DropDownList;
Console.WriteLine("ComboBox {0}, itemcount={1}", cbNew.Name, cbNew.Items.Count);
// The output displays itemcount = 0 for run-time created controls
// and >0 for controls created at design-time
gbLines.Controls.Add(cbNew);
cbNew.DataSource = DBLayer.GetTeams(lineName).Tables[0];
cbNew.DisplayMember = "teamdesc";
cbNew.ValueMember = "id";
The DataSource, DisplayMember and ValueMember property must be set after the control has been added to its container.
By adding "this.Controls.Add(cbo);" to the code before setting the datasource, the problem goes away.
//Create dynamic combobox and add to Panel
ComboBox ddCombo = new ComboBox();
controls = new Control[1] { ddCombo };
panel.Controls.AddRange(controls);
//After creating add to table layout
tableLayoutPanel.Controls.Add(panel, 0, 0);
ddCombo .Name = "ddName";
ddCombo .Width = 200;
ddCombo .Location = new Point(x, y); ddCombo .DataSource = ds;//or any List
ddCombo .SelectedIndex = ddCombo .Items.Count - 1;
Just to clarify are you calling the count() method
After calling the databind() method
This code produces 2 in the message box for me, can you try it and see how it behaves for you?
You can paste it into a console application, and add a reference to System.Windows.Forms and System.Drawing.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
namespace SO887803
{
static class Program
{
[STAThread]
static void Main()
{
Application.Run(new MainForm());
}
}
public partial class MainForm : Form
{
private Button _Button;
private ComboBox _ComboBox;
public MainForm()
{
_Button = new Button();
_Button.Text = "Test";
_Button.Location = new Point(8, 8);
_Button.Click += _Button_Click;
Controls.Add(_Button);
_ComboBox = new ComboBox();
_ComboBox.Location = new Point(8, 40);
Controls.Add(_ComboBox);
}
private void _Button_Click(object sender, EventArgs e)
{
List<Item> items = new List<Item>();
items.Add(new Item("A", "a"));
items.Add(new Item("B", "b"));
_ComboBox.DataSource = null;
_ComboBox.DataSource = items;
_ComboBox.DisplayMember = "Title";
_ComboBox.ValueMember = "Value";
MessageBox.Show("count: " + _ComboBox.Items.Count);
}
public class Item
{
public String Title { get; set; }
public String Value { get; set; }
public Item(String title, String value)
{
Title = title;
Value = value;
}
}
}
}
comboBox1.DataSource=somelist;
int c1=comboBox1.DataSource.Count; // still zero
BindingContext dummy = this.comboBox1.BindingContext;// Force update NOW!
int c2=comboBox1.DataSource.Count; // now it equals somelist.Count
I had the same problem (Im working with VS 2005).
What you need to do is set the DataSource to null, clear the items, reassign the datasource , display and value members.
Eg
cbo.DataSource = null;
cbo.Items.Clear();
cbo.DataSource = cbos;
cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
Old thread, but I tried some of these solutions, along with suspending/resuming the bindingcontext, binding to and resetting a binding source, and just plain reloading the form. None worked to update my control with the newly bound data at the time of my .datasource setting (my items.count was empty, just like the OP).
Then I realized that my combobox was on a tabpage that was getting removed at the start of the code, and later re-added (after my databinding). The binding event did not occur until the tabpage was re-added.
Seems obvious in retrospect, but it was very difficult to detect at runtime, due to the order of calls and inability to see when things were changing.
Try this code.
cbo.BindingContext = new BindingContext();
cbo.DataSource = null;
cbo.DataSource = cbos;
cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
Maybe your ComboBox`s BindingContext is null.
Ba salam,
you can simply refresh the UI by preformLayout() function;
Example:
comboBox1.performLayout();
regards
mohsen s
please try this:
cbo.Parent = <your panel control>;
cbo.DataSource = null;
cbo.DataSource = cbos; cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
MessageBox.Show(string.Format("itemcount is {0}", cbo.Items.Count);
I think your question sames like I met today.

Categories

Resources