How to create subcolumns in RadGridView? - c#

I have 2 RadGridViews. A GridView with packages and a GridView with detail information.
I use Winforms and the RadGridView of Telerik.
I have source like this
private void CreatePackages()
{
var datasource = from s in Something....;
gvPackages.Columns["colType"].IsVisible = false;
gvPackages.GroupDescriptors.Clear();
if ((int)cbddlPackageType.SelectedValue == -1)
{
GroupDescriptor descriptorType = new GroupDescriptor();
descriptorSoort.GroupNames.Add("colType", ListSortDirection.Ascending);
gvPackages.GroupDescriptors.Add(descriptorType);
}
gvPackages.DataSource = datasource;
}
...
private void gvPackages_SelectionChanged(object sender, EventArgs e)
{
OpenDetails(CurrentId);
}
I want to create a grid with the detail information in the same gridview
How do you do that?
Like this:

Well, it's a bit too late I guess. Anyway, maybe this helps some other devlopers facing the same problem.
I think you're looking for Templates. You could add a template in two ways:
1st (in designer):
Click on the three dots in your RadGridView.Templates property.
And then click on "Add".
2nd (programmatically):
GridViewTemplate template = new GridViewTemplate();
radGridView1.Templates.Add(template);
Now once you have added your template to your RadGridView, you can use it with its index like:
GridViewTemplate myTemplate = radGridView1.Templates[0];
Now you can use it as a "normal" RadGridView and e.g. set its DataSource property.
myTemplate.DataSource = lFooBar;

Related

Easycomplete Datagridviewcombobox column winforms

I am trying to create a datagridComboBoxcolumn in winforms with Suggestions Based on Loose Character Search similar to Easycomplete combobox. but I want this as Datagridview combobox.
I have created a grid with Datagridviewcombobox column and used autocomplete but it will search only from first characters. I want loose search. I used
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (e.Control is DataGridViewComboBoxEditingControl)
{
((ComboBox)e.Control).DropDownStyle = ComboBoxStyle.DropDown;
((ComboBox)e.Control).AutoCompleteSource = AutoCompleteSource.ListItems;
((ComboBox)e.Control).AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
}
}
Please provide me a solution to create this type of datagridviewcombobox.
For that you have to create a custom DataGridiVew control. This is not a one line code or not a single class code. you have to make several classes for that.
public class MyDgv : DataGridView
{
....
}
And also create some classes like DataGridViewComboBoxColumn, DataGridViewComboBoxCell, DataGridViewEditingComboBoxControl
There is a tutorial how to create custom column in datagridview on msdn

How to get the selected row values of DevExpress XtraGrid?

Consider the following picture
I get the selected row values in the three textboxes shown in the figure when i click a cell using following code.
void dataGridView1_CellClick_1(object sender, DataGridViewCellEventArgs e) {
TBGRNo.Text = dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString();
TBSName.Text = dataGridView1.Rows[e.RowIndex].Cells[1].Value.ToString();
TBFName.Text = dataGridView1.Rows[e.RowIndex].Cells[2].Value.ToString();
}
My Question is: how will I do the same thing in DevExpress XtraGrid control??
Here is the way that I've followed,
int[] selRows = ((GridView)gridControl1.MainView).GetSelectedRows();
DataRowView selRow = (DataRowView)(((GridView)gridControl1.MainView).GetRow(selRows[0]));
txtName.Text = selRow["name"].ToString();
Also you can iterate through selected rows using the selRows array. Here the code describes how to get data only from first selected row. You can insert these code lines to click event of the grid.
You can do this in a number of ways. You can use databinding (typical initialized after InitializeComponent();)
textBox1.DataBindings.Add(new Binding("Text", yourBindingSource,
"TableName.ColumnName", true, DataSourceUpdateMode.OnPropertyChanged));
or use a DataLayoutControl (if you are going to use textbox for editing, I really recommend spending some time to learn how to use this component.
or in FocusedRowChanged by assigning from one of these methods:
textBox1.Text = gridView1.GetDataRow(e.FocusedRowHandle)["Name"].ToString();
textBox1.Text = gridView1.GetFocusedDataRow()["Name"].ToString();
textBox1.Text = (gridView1.GetFocusedRow() as DataRowView).Row["Name"].ToString();
textBox1.Text = gridView1.GetFocusedRowCellValue("Name").ToString();
I found the solution as follows:
private void gridView1_RowCellClick(object sender, DevExpress.XtraGrid.Views.Grid.RowCellClickEventArgs e)
{
TBGRNo.Text = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "GRNo").ToString();
TBSName.Text = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "SName").ToString();
TBFName.Text = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "FName").ToString();
}
Which one of their Grids are you using? XtraGrid or AspXGrid? Here is a piece taken from one of my app using XtraGrid.
private void grdContactsView_RowClick(object sender, DevExpress.XtraGrid.Views.Grid.RowClickEventArgs e)
{
_selectedContact = GetSelectedRow((DevExpress.XtraGrid.Views.Grid.GridView)sender);
}
private Contact GetSelectedRow(DevExpress.XtraGrid.Views.Grid.GridView view)
{
return (Contact)view.GetRow(view.FocusedRowHandle);
}
My Grid have a list of Contact objects bound to it. Every time a row is clicked I load the selected row into _selectedContact. Hope this helps. You will find lots of information on using their controls buy visiting their support and documentation sites.
For VB.Net
CType(GridControl1.MainView, GridView).GetFocusedRow()
For C#
((GridView)gridControl1.MainView).GetFocusedRow();
example bind data by linq so use
Dim selRow As CUSTOMER = CType(GridControl1.MainView, GridView).GetFocusedRow()
All you have to do is use the GetFocusedRowCellValue method of the gridView control and put it into the RowClick event.
For example:
private void gridView1_RowClick(object sender, DevExpress.XtraGrid.Views.Grid.RowClickEventArgs e)
{
if (this.gvCodigoNombres.GetFocusedRowCellValue("EMP_dni") == null)
return;
MessageBox.Show(""+this.gvCodigoNombres.GetFocusedRowCellValue("EMP_dni").ToString());
}
var rowHandle = gridView.FocusedRowHandle;
var obj = gridView.GetRowCellValue(rowHandle, "FieldName");
//For example
int val= Convert.ToInt32(gridView.GetRowCellValue(rowHandle, "FieldName"));

multiple ultragrids bound to the same datasource

I'm using ultraTextEditors to embed multiselect ultragrids. I set up the datasource in the form_load event. The facilities is a list.
ultraGrid1.DataSource = facilities;
ultraGrid2.DataSource = facilities;
The grid loads fine, but if I select rows in the first grid, the selected rows are set in the second grid. How do I disable this?
Also, I can't get selected row into the text editor from ultragrid2. I use AfterEditorButtonCloseUp event to do this. The first grid has the same code and it works fine. What am I missing here?
private void utxtExcludeReport_AfterEditorButtonCloseUp(object sender, Infragistics.Win.UltraWinEditors.EditorButtonEventArgs e)
{
if (ultraGrid2.Selected.Rows.Count == 0)
utxtExcludeReportLab.Text = string.Empty;
else if (ultraGrid2.Selected.Rows.Count == 1)
utxtExcludeReportLab.Text = ultraGrid2.Selected.Rows[0].Cells[0].Text;
else
utxtExcludeReportLab.Text = "<multiple>";
}
Before you set the datasource for the second ultragrid, you need to create a new BindingContext for it, otherwise events raised by the datasource will be propagated to both grids.
For example (off the top of my head, so it may need refining:
ultraGrid2.BindingContext = new BindingContext();
ultraGrid2.DataSource = facilities;

How to 2-way bind a textbox in a template fields programmatically

I have a gridview to which I'm adding template fields programmatically. Each of the template fields have a textbox. I would like to make this text box have 2-way binding to a database column. Please see below code.
public class CustomEditItemTemplate : ITemplate
{
private DataControlRowType templateType;
private string columnName;
public CustomEditItemTemplate(DataControlRowType type, string colname)
{
this.templateType = type;
this.columnName = colname;
}
public void InstantiateIn(System.Web.UI.Control container)
{
TextBox tb = new TextBox();
tb.ID = columnName;
tb.DataBinding += new EventHandler(this.tb_DataBinding);
container.Controls.Add(tb);
}
private void tb_DataBinding(Object sender, EventArgs e)
{
TextBox t = (TextBox)sender;
DetailsView dv = (DetailsView)t.NamingContainer;
//This line does only one way binding. It takes the rows from the database and displays
//them in the textboxes. The other way binding is not done. This is why my code fails
t.Text = DataBinder.Eval(dv.DataItem, columnName).ToString();
}
}
I'm calling the above class as follows
tf = new TemplateField();
tf.HeaderText = "My First Names";
tf.EditItemTemplate = new CustomEditItemTemplate(DataControlRowType.DataRow, "firstName");
dvModify.Fields.Add(tf);
How can I make the text box such that when I edit the text, this change is reflected in the database as well?
Thanks for your time everyone
Perhaps you could changed the line t.Text = DataBinder.Eval(dv.DataItem, columnName).ToString(); to something like t.Text= string.Format("<%# Bind(\"{0}\") %>", columnName); ?
This is just a guess...
If that doesn't work, I found some articles that actually write new classes for handling two way databinding:
Article at CodeProject circa 2005
Article at Programmer's Heaven
Hopefully one of these options will be useful.
It's actually not too bad to do template fields programatically, after you've seen it once, of course. Here's how we do it, abridged:
TemplateField tf = new TemplateField();
//Do some config like headertext, style, etc;
tf.ItemTemplate = new CompiledTemplateBuilder(delegate(Control container)
{
//Add the regular row here, probably use a Label or Literal to show content
Label label = new Label();
lable.DataBinding += delegate(object sender, EventArgs e)
{
label.Text = ((MyDataType)DataBinder.GetDataItem(label.BindingContainer)).MyLabelDataField;
};
});
tf.EditItemTemplate = new CompiledBindableTemplateBuilder(delegate(Control container)
{
//Here we do the edit row. A CompiledBindableTemplateBuilder lets us bind in both directions
TextBox text = new TextBox();
text.DataBound += delegate(object sender, EventArgs e)
{
text.Text = ((MyDataType)DataBinder.GetDataItem(text.BindingContainer)).MyLabelDataField;
}
},
delegate(Control container)
{
OrderedDictionary dict = new OrderedDictionary();
dict["myLabelDataColumn"] = ((TextBox)container.FindControl(text.ID)).Text;
return dict;
});
So here's what's going on. We use CompiledBindableTemplateBuilder and CompiledTemplateBuilder to actually build our template field's contents. Using a delegate is just an easy way to set this up.
The key to answering your question is in the second argument to the CompiledBindableTemplateBuilder, which is a delegate establishing the binding. After an edit, during submit, the template field will call ExtractValuesFromCell and recover an IBindableTemplate, from which it will extract a Dictionary and then pull the value(s) out of it, adding them to it's own dictionary which eventually gets turned into the uploaded data. So that's why you return an OrderedDictionary from the Binding delegate. Hope that helps!

C# Datagridview - Convert TextColumn to ComboBoxColumn

I have a windows forms application containing a datagridview control. The datagridview is populated by the contents of an xml file. At the moment, all of the columns are displayed as datagridviewtextboxcolumns. I want to select one that is populated by a particular xml tag and display it's content in a datagridviewcomboboxcolumn along with 2 other options.
EXAMPLE:
<SMS>
<Number>+447931663542</Number>
<DateTime>2009-07-12T17:00:02</DateTime>
<Message>YES</Message>
<FollowedUpBy>Unassigned</FollowedUpBy>
<Outcome>Resolved</Outcome>
</SMS>
The OUTCOME tag is the column that I would like to be displayed as a comboboxcolumn in the datagridview. If for example the tag is empty and contains no data, then I want to display nothing, but have the comboboxcolumn populated with 3 possible options to choose from (Unresolved, Resolved, Pending). If however the tag contains data, I want that particular item to be displayed in the comboboxcolumn, and have the other two options available to be selected.
Help in achieving this would be appreciated greatly!
Regards,
EDIT:
Currently I use this code:
colOutcome = new DataGridViewComboBoxColumn();
colOutcome.HeaderText = "Outcome";
colOutcome.Width = 90;
colOutcome.Items.AddRange("Resolved", "Unresolved", "Pending");
this.dataGridView1.Columns.Insert(1, colOutcome);
this.dataGridView1.Columns[1].Name = "OutcomeColumn";
This code above populates the combobox. THE PROBLEM IS: When The xml document populates the datagridview, the outcome column just appears as a textbox column, containing the data inbetween the outcome tags in the xml file. My point is, how can i get the datagridview to realise when it reads the outcome column that it needs to be changed into a combobox column and then display the data that way, along with the other potentially selectable options in the combobox?! Currently the datagridview gets populated with all columns as textboxcolumns containing the data, as well as a seperate combobox column which is not what I want. I need the application to merge the outcome column and its data with the code above.
Any ideas?
Updated Answer
You could pass in the XML document to a function that will loop through each node and determine whether it should be a ComboBox one or not i.e. if the name is "Outcome".
private void CreateColumns(XmlDocument doc)
{
foreach (...) // loop through each node in xml document
{
if (node.Name == "Outcome")
{
var items = new List<string>() { "Resolved", "Unresolved", "Pending" };
this.dataGridView1.Columns.Add(CreateComboBoxColumn(node.Name, items));
}
else
{
this.dataGridView1.Columns.Add(String.Format("col{0}", node.Name), node.Name);
}
}
}
Then your code for creating the Outcome column would be:
private DataGridViewComboBoxColumn CreateComboBoxColumn(string colHeaderText, List<string> items)
{
var colOutcome = new DataGridViewComboBoxColumn();
colOutcome.HeaderText = colHeaderText;
colOutcome.Width = 90;
colOutcome.Items.AddRange(items.ToArray());
colOutcome.Name = String.Format("col{0}", colHeaderText);
return colOutcome;
}
You would then just call CreateColumns on the form load event and pass in your XML. You should only need to create the columns once.
My advice would be to have a similar function that will find all the SMS elements and add a new row populating it with the information in each node.
public void MyForm_Load(object sender, EventArgs e)
{
var doc = new XmlDocument(filename);
CreateColumns(doc);
CreateRows(doc);
}
Hope that helps.
Answer #2 for me, based on the updated question.
The problem you are experiencing is with the AutoGeneratedColumns functionality of the DataGridView. You will need to create your columns manually before databinding. This can be done at design-time or run-time. I prefer design-time because it gives you a bit more direction with the look/feel of the grid but either way works.
You will need to disable the AutoGeneratedColumns property of the grid:
private void Form1_Load(object sender, EventArgs e)
{
// Define your columns at run-time here if that's what you prefer
this.dataGridView1.AutoGeneratedColumns = false;
this.dataGridView1.DataSource = myDataSource;
}
I'm not sitting in front of VS so this might not compile but should give you direction.
You need to either pre-populate the ResolvedColumn with the 3-4 possible values at design-time or assign it to another datasource at runtime. If you chose the design-time approach, simply open the DataGridView "Edit Columns" dialog, find the ResolvedColumn, go to Items, and add your values ("", "Unresolved", "Pending", "Resolved"). The empty value might help the ComboBox to render if there is the possiblity of rendering the grid with SMS records that have no Outcome.
To bind the possible options at runtime do something like this:
private List<string> _outcomeDataSource;
private void Form1_Load(object sender, EventArgs e)
{
_outcomeDataSource = new List<string>;
_outcomeDataSource.Add("");
_outcomeDataSource.Add("Unresolved");
_outcomeDataSource.Add("Pending");
_outcomeDataSource.Add("Resolved");
ResolvedColumn.DataSource = _outcomeDataSource;
ResolvedColumn.PropertyName = "Outcome";
}

Categories

Resources