I have a normal data binding situation where my underlying question object properties are bound to columns in a devexpress XtraGrid.GridControl. However, I have one text property that takes the form of "{Question|True},{Question|False}". These must be mapped to checkboxes in the grid (potentially many per property). Is it possible to use data binding to bind this string property directly to a cell, providing checkbox editing, perhaps using a CheckedComboBox? I'm thinking I'd need an intermediate step in the binding process to map the original string to checkboxes, and then from the checkboxes back to the string.
Otherwise my current thinking is to create another layer of objects, which contains a new object for each of the checkbox options, but if I could somehow interrupt the default binding process with a mapping from the above text to the checkboxes in a CheckComboBox I'd be able to bind straight to the underlying objects.
If I understood you well I think that you should change your question object
to contain bool property. Bool properties are bound to grid as checkboxes, so it will work automatically.
I know that your real value of that property should be string "{Question|True}"
so you can set that property in that way:
private string question;
private bool questionBool;
public bool QuestionBool{
get{return questionBool;}
set{
if(value)
question = "{Question|True}"};
else
question = "{Question|False}";
questionBool = value;
}
I ended up converting the text into a collection of CheckboxQuestionAndAnswer objects which I then bound to the grid, then converting them back into a single text string for writing the data back.
Related
I have a combo box in a datagrid located in an activity. Based on combobox selection I populate another grid with controls programatically. User enters some data in these controls and then saves it. The object that the combo box is bound has many properties of which two are used in selected value path and display member path. The data is bound using two way binding for combo box. When the saved activity that has been placed on a workflow is reopened the data is reloaded correctly and the correct object is value is set in the combo box. But on UI rendering only the values that are attached with the combo box remain intact (i.e those in selected value path and display member path) the rest are reset.
Any idea why this might be happening?
P.S: Setting the binding to OneTime solves the problem of retrieval but any changes that are made on the UI after loading are not reflected back.
Code-Behind:
public ObservableCollection<MyRule> AllRules {get;set;}
public MyRule myRule{get;set;}
In datagrid Loaded Event I populate the AllRules as:
AllBusinessRules.Add(new MyRule () { RuleId = item.Id, RuleName = item.Name});
where item.Id and item.Name are obtained from the database via service call.
In the same event if I also load any previously saved rules as:
myRule=SelectedRule;
where SelectedRule has RuleId, RuleName, Inputs and Outputs as well.
Code:
<ComboBox
ItemsSource="{Binding Path=AllRules}"
SelectedItem="{Binding Path=myRule,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
SelectedValuePath="RuleId"
DisplayMemberPath="RuleName">
<DataTemplate>
<TextBox Text="{Binding Path=myRule.RuleName}"/>
</DataTemplate>
</ComboBox>
Class:
public class MyRule{
public int RuleId{get;set;}
public string RuleName{get;set;}
public List<string> Inputs{get;set;} //properties that are reset when the UI renders
public List<string> Outputs{get;set;} //properties that are reset when the UI renders
}
The Inputs and Outputs properties are obtained from the programatically generated controls via reflection and added to the object populated by combobox and saved.
I have studied about this problem here but the solution does not solve my problem. Any help would be great.
SelectedValuePath, DisplayMemberPath are set wrongly. DisplayMemberPath should be "RuleName". SelectedValue, SelectedValuePath are not needed as you have set SelectedItem. SelectedItem will get the chosen item automatically because of Binding. From the myRule object you can access other properties.
It took a lot of time to investigate what was wrong but now that I know its just quite simple.
As I have shown that in the datagrid's Loaded event I used to set the ItemsSource of the combo box and in the item source I have only set the properties RuleId and RuleName.
Problem:
So the problem was that when I assigned the value i.e the selected value on reloading the combobox e.g. myRule=SelectedRule the other properties i.e. Inputs and Outputs are not there in the ItemsSource. That is why the selected object though correct did not have Inputs and Outputs as the SelectedItem was from ItemsSource of the Combo Box giving me the impression that the two way binding had somehow reset the values of properties not bound with the combo box.
Solution:
In the end I wrapped my MyRule Object in another object like RuleInformation i.e
public class RuleInformation{
public List<string> Inputs;
public List<string> Outputs;
public MyRule myRule{get;set;}
}
where MyRule is like:
public class MyRule{
public int RuleId{get;set;}
public string RuleName{get;set;}
}
So the combo box is bound to the MyRule object whereas the inputs and output properties remain untouched in the upper object.
I have implemented below code:
gridControl.DataSource = CusColumnList
CusColumnList is of type MyBindingList which inherits BindingList, in my case T is class MyColumn. The binding works well.
But now my problem comes, I don't want the data source to bind to every column in CusColumnList, I only want it binds to column whose name contains "ABC" or whose display name contains "XYZ". I tried to set
gridControl.DataSource = CusColumnList.Where(column => column.Name.Contains("ABC") || column.DisplayName.Contains("XYZ"));
But seems it does not work.
I also tried to create another bindinglist collection MyTempCusColumnList of type MyBindingList, and in the Get method of this MyTempCusColumnList, I just return every item in CusColumnList where the name or display name qualifies. But in this way, every time when CusColumnList is updated, I need to manually update MyTempCusColumnList.
I wonder whether there is a better way to archive this goal with just CusColumnList.
Thanks!
Edit : format code
You could use a filter string on a BindingSource object.
Check out the MSDN documentation on it, it's quite good: http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.filter(v=vs.100).aspx
My setup:
C#.Net 4.0, Windows Forms, DevExpress 13.1.5 although I doubt its a DX issue
I have a form with a GridControl (with GridView) on the top and a detail area that holds TextEdits and other edits in a LayoutControl below.
Both the grid and the edits below are bound to the properties of the objects contained in a list in the binding source.
The grid is set to ReadOnly, MultiSelect, RowSelect and all its columns are set to ReadOnly, not focusable.
Editing is only happening in the detail area below.
The behavior I want to create:
When multiple rows are selected in the grid the edits below should show the following:
the value of field in question is the same in all selected rows -> show the value
the value of the field in question differs between the rows -> show nothing
if the user writes into the TextEdit while multiple rows are selected:
the value of the edit should update the values of the same field of all the selected rows
Where I am with this:
I'm working on a solution by building a custom BindingSource that would be aware of the selection. It would bind the list of object to the grid and a single object that is not part of the list to the edits. Depending on the selection I would set the properties of that single object or forward its changes to the selected objects in the list.
I got that working for a single property with 2 binding sources and would now extend it to use reflection to do this for all of the public properties. I also want to encapsulate the whole behavior into a class that looks and acts like BindingSource just with that added behavior.
The question:
Is there a simpler way to achieve this? Does something already exist which can do this that I overlooked in either .Net or DevExpress? Are there traps to my approach that I should consider or why I should go about this totally differently?
I think that you can achieve your goal in a simpler manner:
Just bind a single BindingSource with all the data that you need to your grid. That should display the data.
Then, bind the required fields from that same BS do the edits through the DataBindings propriety.
You can then implement a save object (through a control or programatically) so the changes made in the edits are shown in the grid.
To check the grid values, you can use:
//get the handles of the rows
gridView.GetSelectedRows();
//get the value of the desirable cells
gridView.GetRowCellValue(handle, column);
Also, in future projects, consider using the Entity Framework to construct a data-aware model and custom objects based on the elements of your Database.
Hope this helped!
In my Windows Mobile .NET application I have a simple array of object with the data I want to display in my DataGrid. To do this, I simply call:
myDataGrid.DataSource = myArray;
This works, but I have a problem with it: it uses all properties as columns and uses the names of the properties as the column headers. I can't figure out how to customize two things:
Select which subset of properties should be displayed as columns (say I have an ID, Name and Value property, I'd only want to show Name and Value);
Rename the column headers to make more sense (for example if the property is called ID display a column header saying "Number").
Is this possible at all?
As mentioned this is in a Windows Mobile .NET (version 2) application.
You need to set the Datagrid.TableStyles property to customize the layout.
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagrid.tablestyles.aspx
More details on binding to an array of objects here:
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridtablestyle.mappingname(VS.71).aspx
To bind the
System.Windows.Forms.DataGrid to a
strongly typed array of objects, the
object must contain public properties.
To create a DataGridTableStyle that
displays such an array, set the
MappingName property to classname[]
where classname is replaced by the
class name. Also note that the
MappingName property is
case-sensitive.
I don't know if you know the name of the columns in advance? But if it's the case, you can go in the "Edit Columns" of your DataGridView and just create your columns there. In the "Data" Category, change the "DataPropertyName" from "(none)" to the name of the class property. From there you can customize the name, if it's visible, the size, etc. The DataGrid will bind it to your DataSource.
Also, there is a property "DataGridView.AutoGenerateColumns" that you can set to false so you don't have to bind all the properties of your object. I tought that migh help as well.
In this code _im is an object of table and I bind this object with DataGridView dgvItem after binding I change header text of dgvItem as required.
dgvItem.Rows.Clear();
dgvItem.DataSource = _im ;
dgvItem.Columns[2].HeaderText = "Mobile Code";
dgvItem.Columns[3].HeaderText = "Mobile Name";
Edit 1
I believe my problem stems from the following. The function that fills the dropdown portion sets the Display Member to the CountyName. Then when I try and set the SelectedText or EditValue, as has been suggested, that function only returns the CountyID which it try's to match to something in the DropDown list DisplayMember. I need it to match it to something in the ValueMember list.
Using the following I got it to work but it is a HACK and I'd greatly appreciate finding a real solution.
lkuResidenceCounty.ItemIndex = Convert.ToInt32(row["ResidencyCountyID"].ToString());
Original Post
I have a lookup box(DevExpress) on a member form that I fill the possible values in from the DB with this code -->
lkuResidenceCounty.Properties.DataSource = ConnectBLL.BLL.Person.CountyList();
lkuResidenceCounty.Properties.PopulateColumns();
lkuResidenceCounty.Properties.DisplayMember = "CountyName";
lkuResidenceCounty.Properties.ValueMember = "CountyID";
lkuResidenceCounty.Properties.Columns[0].Visible = false;
lkuResidenceCounty.Properties.Columns[2].Visible = false;
lkuResidenceCounty.Properties.Columns[3].Visible = false;
This works just fine as the CountyName is displayed as expected.
However, When I try and load an existing member's value for this field using the below, which is part of a function that takes a row from the DataSet -->
lkuResidenceCounty.Properties.ValueMember = row["ResidencyCountyID"].ToString();
I get a blank box. I have stepped through the code and the correct ID is being returned for the member.
Unfortunately the stored procedure to fill the dropdown options pulls from a Maintenance Table with the columns "CountyName" & "CountyID". So that is correct. Unfortunately, the stored procedure to load a specific person's current county pulls from the Person Table where there is a column called "ResidencyCountyID". It is so named because there is also a "ResponsibilityCountyID" column.
I need a way for them both to coexist, any solutions?
Thanks!
DisplayMember and ValueMember are used to populate the control with the list of selectable values. To set the selected value of a populated LookUpEdit control, set its EditValue property:
lkuResidenceCounty.EditValue = row["ResidencyCountyID"].ToString();
In response to your edit: According to the documentation:
The currently selected row determines values for the editor's edit value and display text. The value for BaseEdit.EditValue is obtained from the RepositoryItemLookUpEditBase.ValueMember field, while the text to display in the edit box is obtained from the RepositoryItemLookUpEditBase.DisplayMember field of the selected row.
When you change BaseEdit.EditValue,
the editor locates and selects the row
whose
RepositoryItemLookUpEditBase.ValueMember
field contains the new value. The text
in the edit box is changed to reflect
the newly selected row.
I don't use these controls but it sounds to me that it shouldn't be working as you described. I think the ToString() is the problem because EditValue accepts an object so it's probably expecting an int for the value. Try:
lkuResidenceCounty.EditValue = (int)row["ResidencyCountyID"];
The ValueMember property tells the list what field to pull from when setting the Value property. Once you've set the ValueMember to "CountyID", then when the list is Databound, it will set all the list items' value properties to their respect objects' CountyID fields.
Hence, you should not do:
lkuResidenceCounty.Properties.ValueMember = row["ResidencyCountyID"].ToString();
but rather
lkuResidenceCounty.Properties.ValueMember = "CountyID";
was perfectly fine, as long as you've correctly identified the field you're trying to databind. Once the list get's databound you should see the results you're expecting.
However, after looking at your code, it seems that you're mismatching your field. In one place you're using ResidencyCountyID and in another you're using CountyID. That is most likely your source of confusion. Figure out what the actual field name is and make sure you set the ValueMember to that.
UPDATE
After reading your comment, what your looking for is the SelectedValue property. The SelectedValue property tells the list to force the selected value to whatever input you give it.
Essentially you have two things going on here. ValueMember tells the list what to use as the value from your data source, and SelectedValue which tells the list what the currently selected value should be.
Why is it that you need the same LookUpEdit to have two value members? Is it being used standalone or in a grid? If standalone, you could swap out the two repository editors depending on the current row. But, are there more than 2 possible values for the ValueMember? That would also complicate things.
UPDATE
Looking at your edit, I think I understand what's going on a little more. So, you don't wish to change your ValueMember (which refers to a data column), but rather to change the value of the editor? If so, then you should definitely use EditValue (not SelectedText, which I don't believe is meant to be set), and assign it to row["value_field"] like so:
lkuResidenceCounty.EditValue = row["ResidencyCountyID"];
What happens when you do that?