Displaying multiple columns on LookupEdit of Devexpress - c#

I have a DataSource bound to a LookUpEdit. For example I have 2 columns FirstName and LastName and I want to set DisplayMember property to these two columns.
I found that I should subscribe to lookUp_CustomDisplayText() and edit display text property like this:
private void lookUpCompanyPerson_CustomDisplayText(object sender, CustomDisplayTextEventArgs e)
{
LookUpEdit edit = sender as LookUpEdit;
if (e.DisplayText != "")
{
e.DisplayText = e.DisplayText + " " + (string)e.Value;
}
}
but I did not understand what e.Value is and I want to display another column for selected row, not the valuemember of selected row.
This is how I bind the datasource to lookupedit:
private void populateComboBoxForCompanyPerson()
{
lookUpCompanyPerson.Properties.ForceInitialize();
bs = new BindingSource(myDataSet, "CompanyPerson");
lookUpCompanyPerson.Properties.DataSource = bs;
lookUpCompanyPerson.Properties.DisplayMember = "CompanyName";
lookUpCompanyPerson.Properties.ValueMember = "PersonID";
this.lookUpCompanyPerson.Properties.Columns.Add(new LookUpColumnInfo("PersonID"));
this.lookUpCompanyPerson.Properties.Columns["PersonID"].Visible = false;
this.lookUpCompanyPerson.Properties.Columns.Add(new LookUpColumnInfo("FirstName"));
this.lookUpCompanyPerson.Properties.Columns.Add(new LookUpColumnInfo("LastName"));
this.lookUpCompanyPerson.Properties.Columns.Add(new LookUpColumnInfo("CompanyName"));
}
And this is what my datasource looks like:

I've changed Ian O'Brien's code a little bit and it works:
private void lookUpCompanyPerson_CustomDisplayText(object sender, CustomDisplayTextEventArgs e)
{
RepositoryItemLookUpEdit props;
if (sender is LookUpEdit)
props = (sender as LookUpEdit).Properties;
else
props = sender as RepositoryItemLookUpEdit;
if (props != null && (e.Value is int))
{
DataRowView row = props.GetDataSourceRowByKeyValue(e.Value) as DataRowView;
if (row != null)
{
e.DisplayText = String.Format("{0} {1}", row["FirstName"], row["LastName"]);
}
}
}

From the DevExpress documentation:
e.Value gets or sets editor's current value.
e.DisplayText gets or sets an editor's display text
The lookup editor's value is obtained from the data source field specified by the RepositoryItemLookUpEditBase.ValueMember property. The GetDataSourceRowByKeyValue method searches for the specified value within this field and returns an object representing the first found record.
The GetDataSourceRowByKeyValue method's return value depends upon the type of the underlying data source. If the data source is a System.Data.DataTable or a System.Data.DataView, this method returns a System.Data.DataRowView object. If the data source is a custom list of items, the appropriate list item is returned.
You want to set the e.Value to the value that you want to display in the control.
private void lookUpCompanyPerson_CustomDisplayText(object sender, CustomDisplayTextEventArgs e)
{
RepositoryItemLookUpEdit props
if (sender is LookUpEdit)
props = (sender as LookUpEdit).Properties;
else
props = sender as RepositoryItemLookUpEdit;
if (props != null && (e.Value is int))
{
object row = props.GetDataSourceRowByKeyValue(e.Value);
if (row != null)
{
e.Value = String.Format("{0} {1}", (DataRowView)row["FirstName"], (DataRowView)row["LastName"]);
e.Handled = true;
}
}
}
Finally, here are some useful pages with more documentation:
BaseEdit.CustomDisplayText Event
RepositoryItemLookUpEdit.GetDataSourceRowByKeyValue Method

i have use it, just like this;
cmb_tip.Properties.DataSource = _dt;
cmb_tip.Properties.ValueMember = "Value";
cmb_tip.Properties.DisplayMember = "Type";
cmb_tip.Properties.PopulateColumns();
cmb_tip.Properties.Columns["Value"].Visible = false;

This is how it works with LookupEditControl in Version 15.2.7 and a Class:
private void lookUpEditPatients_CustomDisplayText(object sender, DevExpress.XtraEditors.Controls.CustomDisplayTextEventArgs e)
{
var edit = sender as LookUpEdit;
var props = edit.Properties;
var pat = (Patients4ComboBoxVm) props?.GetDataSourceRowByKeyValue(e.Value);
if (pat != null)
{
e.DisplayText = pat.Nachname + ", " + pat.Vorname + "; " + pat.Geburtsdatum + "; " + pat.Versicherungsnummer;
}
}

Related

How to rebind datasource to a winform DataGridView Combobox column?

I have a DataGridView in winform with 2 combo box columns: 1) Companies, 2) Accounts.
I want to update the accounts combo box according to the selected company.
I have this code:
void recipientsDataGrid_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
try
{
ComboBox cb = e.Control as ComboBox;
if (cb != null)
{
cb.SelectedValueChanged -= new EventHandler(companyCombobox_SelectedValueChanged);
cb.SelectedValueChanged += new EventHandler(companyCombobox_SelectedValueChanged);
}
}
catch (Exception ex)
{
}
}
private void companyCombobox_SelectedValueChanged(object sender, EventArgs e)
{
try
{
var currentCell = recipientsDataGrid.CurrentCellAddress;
if (currentCell.X == 3)
{
var sendingCB = sender as DataGridViewComboBoxEditingControl;
int companyId = sendingCB.SelectedValue.ToInt();
DataTable dtAccounts = m_CustomersFunctions.GetCompanyAccounts(companyId);
DataGridViewComboBoxCell cboAccounts = (DataGridViewComboBoxCell)recipientsDataGrid.Rows[currentCell.Y].Cells["Account"];
cboAccounts.ValueMember = "account_id";
cboAccounts.DisplayMember = "AccountName";
cboAccounts.DataSource = dtAccounts;
int defaultAccountId = (from row in dtAccounts.AsEnumerable()
where row.Field<string>("AccountName").EndsWith("*")
select row.Field<int>("account_id")).FirstOrDefault();
if (defaultAccountId > 0)
cboAccounts.Value = defaultAccountId;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
It works fine in the first time I select a company, but when I change the company and try to update the data source for the accounts combo box I'm getting an error:
I tried to add the items manualy and not with a DataSource, and I got the same error.
How can I fix it ?
please...
Try to clear the value of accounts cell before rebind it, like this:
private void companyCombobox_SelectedValueChanged(object sender, EventArgs e)
{
try
{
var currentCell = recipientsDataGrid.CurrentCellAddress;
if (currentCell.X == 3)
{
var sendingCB = sender as DataGridViewComboBoxEditingControl;
int companyId = sendingCB.SelectedValue.ToInt();
DataTable dtAccounts = m_CustomersFunctions.GetCompanyAccounts(companyId);
DataGridViewComboBoxCell cboAccounts = (DataGridViewComboBoxCell)recipientsDataGrid.Rows[currentCell.Y].Cells["Account"];
cboAccounts.Value = null; //Add this code
cboAccounts.ValueMember = "account_id";
cboAccounts.DisplayMember = "AccountName";
cboAccounts.DataSource = dtAccounts;
int defaultAccountId = (from row in dtAccounts.AsEnumerable()
where row.Field<string>("AccountName").EndsWith("*")
select row.Field<int>("account_id")).FirstOrDefault();
if (defaultAccountId > 0)
cboAccounts.Value = defaultAccountId;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I had the same problem in vb.net .
Not sure if my solution is good, but it works for me.
Briefly: I create a new temporary "DataGridViewComboBoxCell" object, I assign the "DataSource" and the "Value" (which must belong to "DataSource" !!! otherwise the error "value is not valid" comes out) and assign the new object to correct cell in my "DataGridView" main object, like this:
Dim oDataGridViewComboBox As New DataGridViewComboBox With {
.DataSource = MyDataSource
.Value = MyCorrectValueContainedInDataSource
}
oMyDataGridView.Rows(iLineOfComboBox).Cells("ComboBoxColumnName") = oDataGridViewComboBox
The error "value is not valid" is thrown because the ComboBox value is not included among those present in "DataSource".
P.S.: Sorry, I don't know C# ... but the problem is the same, and I have found this post during a search of solution.

How to edit databound combobox in c#

In my winForm application I have added databound combobox column in a datagridview. User needs to be able to select an item from dropdown list or write in the combobox. But it wouldn't let me write in the combobox as datasource is set. This is my code:
var entityModel= new AdminEntities();
var filterPractice = (from b in entityModel.FILTER where b.PRACTICE != null select b.PRACTICE).Distinct().OrderBy(y => y);
dgvCboColumn(filterPractice, "PRACTICE");
private void dgvCboColumn(dynamic item, string colName)
{
int i = dgvLoadTable.Columns[colName].Index;
DataGridViewComboBoxColumn dgvCol = new DataGridViewComboBoxColumn();
dgvCol.DataSource=item;
dgvCol.DataPropertyName = colName;
dgvLoadTable.Columns.Insert(i, dgvCol);
dgvLoadTable.Columns[i].HeaderText = dgvLoadTable.Columns[i + 1].HeaderText;
dgvLoadTable.Columns[i + 1].Visible = false;
dgvLoadTable.Columns.RemoveAt(i + 1);
}
private void HandleEditShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
var cbo = e.Control as ComboBox;
if (cbo == null)
{
return;
}
cbo.DropDownStyle = ComboBoxStyle.DropDown;
cbo.Validating -= HandleComboBoxValidating;
cbo.Validating += HandleComboBoxValidating;
}
private void HandleComboBoxValidating(object sender, CancelEventArgs e)
{
var combo = sender as DataGridViewComboBoxEditingControl;
if (combo == null)
{
return;
}
if (!combo.Items.Contains(combo.Text))
{
var comboColumn = this.dgvLoadTable.Columns[this.dgvLoadTable.CurrentCell.ColumnIndex] as DataGridViewComboBoxColumn;
combo.Items.Add(combo.Text);
comboColumn.Items.Add(combo.Text);
this.dgvLoadTable.CurrentCell.Value = combo.Text;
}
}
Can anyone tell me how can I make the combobox editable, please?
you can manually get the items frm datasource using Oledb or Ado recordset nd fill de comboBox manually by using for loops.. so basically you can also edit the items..

Replace value of datagridview column while setting data Source [duplicate]

There is datagridview in a form that shows content of table of database, one column of table type is boolean, so in datagridview shows true/false, but i want to customize it to show Yes/No.
which way you suggest?
When it comes to custom formatting, two possible solutions comes in my mind.
1.Handle CellFormatting event and format your own.
void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex == yourcolumnIndex)
{
if (e.Value is bool)
{
bool value = (bool)e.Value;
e.Value = (value) ? "Yes" : "No";
e.FormattingApplied = true;
}
}
}
2.Use Custom Formatter
public class BoolFormatter : ICustomFormatter, IFormatProvider
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
{
return this;
}
return null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (arg == null)
{
return string.Empty;
}
bool value = (bool)arg;
switch (format ?? string.Empty)
{
case "YesNo":
{
return (value) ? "Yes" : "No";
}
case "OnOff":
{
return (value) ? "On" : "Off";
}
default:
{
return value.ToString();//true/false
}
}
}
}
Then use it like this, and handle CellFormatting event to make it work
dataGridView1.Columns[1].DefaultCellStyle.FormatProvider = new BoolFormatter();
dataGridView1.Columns[1].DefaultCellStyle.Format = "YesNo";
void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.CellStyle.FormatProvider is ICustomFormatter)
{
e.Value = (e.CellStyle.FormatProvider.GetFormat(typeof(ICustomFormatter)) as ICustomFormatter).Format(e.CellStyle.Format, e.Value, e.CellStyle.FormatProvider);
e.FormattingApplied = true;
}
}
Edit
You can subscribe to CellFormatting event like this
dataGridView1.CellFormatting += dataGridView1_CellFormatting;
Hope this helps
void dataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var grid = (DataGridView)sender;
if (grid.Columns[e.ColumnIndex].Name == "IsActive")
{
e.Value = (bool)e.Value ? "True_Text_Replace" : "False_Text_Replace";
e.FormattingApplied = true;
}
}
How about this if you only want to show.
It's easy to think.
private void Form1_Load(object sender, EventArgs e)
{
List<Person> list = new List<Person>();
list.Add(new Person(20, true));
list.Add(new Person(25, false));
list.Add(new Person(30, true));
dgv.DataSource = list;
//Hide checkbox column
dgv.Columns["IsProgrammer"].Visible = false;
//Add represent text column
DataGridViewTextBoxColumn textColumn = new DataGridViewTextBoxColumn();
textColumn.Name = "Yes / No";
dgv.Columns.Add(textColumn);
//true/false -> yes/no
foreach (var row in dgv.Rows.Cast<DataGridViewRow>())
row.Cells["Yes / No"].Value = (bool)row.Cells["IsProgrammer"].Value ? "Yes" : "No";
}
private class Person
{
public int Age { get; set; }
public bool IsProgrammer { get; set; }
public Person(int i, bool b)
{
Age = i;
IsProgrammer = b;
}
}
For vb code:
Use the code below to change boolean True/False display to Checkbox in Datagrid:
datagrid1.Columns.Add(New DataGridViewCheckBoxColumn)
Use the code below to display column header:
datagrid1.Columns(column number).HeaderText = "User Status"
If you swap the column out for a DataGridViewComboBoxColumn that is bound to a list/datatable having bool and string columns then it will decode the bool to whatever string you want (and the user can edit the values, but cannot put bad values in)
//your datatable has some boolean column and your DataGridView is bound to it
DataTable dt = new DataTable();
dt.Columns.Add("MyBoolColumn", typeof(bool)); //this is your bool column
dataGridView1.DataSource = dt;
//make a datatable that has 2 columns, string and bool, and 2 rows (one for true, one for false)
DataTable dv = new DataTable();
dv.Columns.Add("Dis"); //it will be shown in the combo
dv.Columns.Add("Val", typeof(bool)); //it will be used by the combo to set MyBoolColumn
dv.Rows.Add("Yeah baby", true);
dv.Rows.Add("Nooo way", false);
//make a combo box column bound to the values table above
//and connected to the table you show in the grid
var dgvcbc = new DataGridViewComboBoxColumn();
dgvcbc.DataPropertyName = "MyBoolColumn"; //connect to the grid table
dgvcbc.DisplayMember = "Disp"; //show this column
dgvcbc.ValueMember = "Val"; //use values from this
dgvcbc.DataSource = dv;
dataGridView1.Columns.Add(dgvcbc);
This grid will now show a combo where it once showed a checkbox, and editing the combo will change the boolean value
You don't have to bind the combo column to a datatable. Maybe you'd prefer a list of Tuple or ValueTuple as the backing data store for the Yes/No combo:
var dv2 = new List<Tuple<string, bool>>() {
new Tuple<string, bool>("Yeah baby", true),
new Tuple<string, bool>("Noooo way", false)
};
var dgvcbc2 = new DataGridViewComboBoxColumn();
dgvcbc2.DataPropertyName = "MyBoolColumn";
dgvcbc2.DisplayMember = "Item1"; //the string in the Tuple
dgvcbc2.ValueMember = "Item2"; //the bool in the Tuple
dgvcbc2.DataSource = dv2;
dataGridView1.Columns.Add(dgvcbc2);
If your datagridview is designed in the forms designer, the easiest thing would probably be to add a DispVal table to a strongly typed dataset, then it becomes available as a "project list instance" in the picker that lets you choose the datasource for the combo column
The answer where we handle CellFormatting event didn't work for me, though it seemed so simple and promising. Perhaps because I have bound a List as the DataSource to my DataGridView. I was getting the exception
value of the cell has a wrong type
I solved it in the DataSource List's class, so instead of having a bool property, I hid it and put the logic inside a string property, like this
Old
public bool PropertyName
{
get => someBusinessLogic();
}
New
[Browsable(false)] // will not be displayed in the DataGridView
public bool PropertyNameBool
{
get => someBusinessLogic();
}
public string PropertyName
{
get => this.PropertyNameBool ? "True" : "False";
}
This worked for me as this class is only used as a DataSource for my grid. But changing around the class may not work for everybody.

GridView Sorting resets page to original data

H guys, I am using VS2005 C# and SQL Server 2005.
I have a search for my GridView and I would like to use the Sort function of the GridView to sort my search results.
However, after every time I have my results filtered, when I press the header to sort my DataGrid, it always reset my GridView back to the original full data from the table.
E.g.
a) My webpage loads, a gridview containing data of 58 students.
b) I search for James under Names and 18 results are displayed in the GridView.
c) I press on the header Class to sort results by class.
d) The GridView refreshes and goes back to original full list of 58 students.
I tried:
Implementing the search table on a seperate webpage so it would not collide with the original gridview.
Changing the gridview name to another name.
I realize that:
When I hover my pointer above the header, it will always display
javascript:_doPostBack('ctl00$MainContent$GridView1,Sort$Issue),
even though I may have changed my GridView1 to another name
I need some solution in sorting search results in gridview, instead of bringing the original data back when I sort them.
I have implemented that using the ViewState to store the sort direction, either ASC or DESC in the following way:
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
listBindByName(); //this would be your procedure to look for the data you want
DataSet dsSortTable = GridView1.DataSource as DataSet;
DataTable dtSortTable = dsSortTable.Tables[0];
if (dtSortTable != null)
{
DataView dvSortedView = new DataView(dtSortTable);
dvSortedView.Sort = e.SortExpression + " " + getSortDirectionString();
ViewState["sortExpression"] = e.SortExpression;
GridView1.DataSource = dvSortedView;
GridView1.DataBind();
}
UpdatePanel1.Update();
}
private string getSortDirectionString()
{
if (ViewState["sortDirection"] == null)
{
ViewState["sortDirection"] = "ASC";
}
else
{
if (ViewState["sortDirection"].ToString() == "ASC")
{
ViewState["sortDirection"] = "DESC";
return ViewState["sortDirection"].ToString();
}
if (ViewState["sortDirection"].ToString() == "DESC")
{
ViewState["sortDirection"] = "ASC";
return ViewState["sortDirection"].ToString();
}
}
return ViewState["sortDirection"].ToString();
}
Let me know if any doubt.
suppose when you call gridview for Bind in Page load
protected void Page_Load(object sender, EventArgs e)
{
fillgrid(false, string.Empty, false); //
}
public void fillgrid(bool sorting, string sortexpression, bool sortdir)
{
//binding codes
var data = from item in DBcontent.Tablename
select new
{
Title = item.Title
}
if (sorting)
{
if (sortexpression == "Title")
{
if (sortdir)
{
GrieviewID.DataSource = data.OrderBy(id => id.Title).ToList();
}
else
{
GrieviewID.DataSource = data.OrderByDescending(id => id.Title).ToList();
}
}
else
{
GrdID.DataSource = data.OrderByDescending(id => id.StartDate).ToList();
}
GrdID.DataBind();
}
protected void grdevents_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
grdevents.PageIndex = e.NewPageIndex;
BindAndSortGrid();
}
/// <summary>
/// Gets the sort direction.
/// </summary>
/// <param name="column">The column.</param>
/// <returns></returns>
private string GetSortDirection(string column)
{
// By default, set the sort direction to ascending.
string sortDirection = "ASC";
// Retrieve the last column that was sorted.
string sortExpression = ViewState["SortExpression"] as string;
if (sortExpression != null)
{
// Check if the same column is being sorted.
// Otherwise, the default value can be returned.
if (sortExpression == column)
{
string lastDirection = ViewState["SortDirection"] as string;
if ((lastDirection != null) && (lastDirection == "ASC"))
{
sortDirection = "DESC";
}
}
}
// Save new values in ViewState.
ViewState["SortDirection"] = sortDirection;
ViewState["SortExpression"] = column;
return sortDirection;
}
/// <summary>
/// Bind and sort grid.
/// </summary>
private void BindAndSortGrid()
{
bool sortdir;
if (ViewState["SortDirection"] != null && ViewState["SortExpression"] != null)
{
sortdir = ViewState["SortDirection"].ToString() == "ASC" ? true : false;
fillgrid(true, ViewState["SortExpression"].ToString(), sortdir);
}
else
fillgrid(false, string.Empty, false);
}
protected void grdevents_Sorting(object sender, GridViewSortEventArgs e)
{
bool sortdir = GetSortDirection(e.SortExpression) == "ASC" ? true : false;
fillgrid(true, e.SortExpression.ToString(), sortdir);
}
Follow below code...Hopes its help

Adding data dynamically to a asp literal control inside a grid view

I'm trying to add data to a literal which place inside a gridview. Currently code look like this
protected void GvListingRowDataBound(object sender, GridViewRowEventArgs e)
{
var query = DisplayAllData();
Literal info = (Literal)e.Row.FindControl("ltritemInfo");
if(query != null)
{
foreach (var listing in query)
{
var list = DisplayListById(listing.id);
info.Text = "<h3>" + list.title + "</h3>";
info.Text += "<h4>" + list.description + "</h4>";
}
}
}
This will generate an error
Object reference not set to an instance of an object.
If anyone has an idea about this it will be great help
Thanks
Ensure you're only operating on the data rows, and not the header, footer, separator, pager, etc. The enum for this is DataControlRowtype. This is why your info object/reference is null, as it operates on the header first.
Check that the e.Row.RowType is of type DataRow.
For safety, also check that your info is not null.
protected void GvListingRowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
var query = DisplayAllData();
Literal info = (Literal)e.Row.FindControl("ltritemInfo");
if(query != null && info !=null)
{
foreach (var listing in query)
{
var list = DisplayListById(listing.id);
info.Text = string.Format("<h3>{0}</h3><h4>{1}</h4>",
list.title, list.description);
}
}
}
}

Categories