I have an ObservableCollection of dynamic objects that is bound to a RadGridView. I want to use the RadDataFilter control with this list. For some reason when I set the Source nothing appears as options for creating filtering rules.
You can see in the picture that the DropDown box that is supposed to have the names of the columns is empty.
I'm setting the source as follows
DataFilter.Source = Data;
Data is declared as ObservableCollection<dynamic>
Related
I am having trouble understanding how to bind data to some controls.
From the image below, I have n objects in a list that I want to be editable, but I don't want n amount of controls. I want to select which object from the combo box - so that I can reuse one set of controls.
I have bound data to my combo box, and bound data to a grid view - 'easy'.
But my numericalUpDown doesn't have a DataSource member.
How can I bind it?
And, would I change the binding when comboBox1_SelectedIndexChanged() is called? If not, what is a good way to do this?
Thank you for any advice.
I am not sure if this is the best or neatest way, but it definitely works and gives me what I needed.
I believe I need to clear the binding each time, when the selected object I am binding to changes.
The below code clears any existing bindings, and binds the control to the selected data object, binding the Text property of the control to the Xpos value of the object.
Taking the index value of the combo box, and then using it to access the object that we want in the list.
Within comboBox1_SelectedIndexChanged:
int index = comboBox1.SelectedIndex;
pos_xUpDown.DataBindings.Clear();
pos_xUpDown.DataBindings.Add("Text", objectlist[index], "Xpos");
pos_yUpDown.DataBindings.Clear();
pos_yUpDown.DataBindings.Add("Text", objectlist[index], "Ypos");
pos_zUpDown.DataBindings.Clear();
pos_zUpDown.DataBindings.Add("Text", objectlist[index], "Zpos");
As in the title, I have a DataGrid and a ViewModel that implements ICustomTypeDescriptor, adding a few properties at runtime.
public class PartCloneSettingsController : BaseController, ICustomTypeDescriptor
{
...
private List<StringPropertyDescriptor> generatedProperties;
private void generateProperties()
{
foreach (PartAttributeDefinition item in PartAttributes.DefinedAttributes)
{
var propertyDescriptor = new StringPropertyDescriptor(item.AttributeTitle, typeof(PartCloneSettingsController), item);
// attach value changed handler [ memory leak? TODO: Remove handler at some point...]
propertyDescriptor.AddValueChanged(this, OnGeneratedPropertyChanged);
generatedProperties.Add(propertyDescriptor);
}
}
public PropertyDescriptorCollection GetProperties()
{
// Get All Default (defined) properties
var properties = TypeDescriptor.GetProperties(this, true);
// concat default properties and generated properties into a single collection
var newProperties = new PropertyDescriptorCollection(properties.Cast<PropertyDescriptor>().Concat(generatedProperties).ToArray());
return newProperties;
}
}
DataGrid Definition in XAML:
<DataGrid x:Name="dataGrid" AutoGenerateColumns="True" />
I set the ItemsSource like this:
controller.LoadAssembly(ofd.FileName); // loads the file and creates a ObservableCollection of PartCloneSettingsControllers...
// set data grid source, doesn't create columns for generated properties...
overviewGrid.ItemsSource = controller.PartCloneSettingsControllers
// set data source from a winforms DataGridView which generates columns properly...
((System.Windows.Forms.DataGridView)wfhost.Child).DataSource = controller.PartCloneSettingsControllers;
where controller.PartCloneSettingsControllers is defined as:
public ObservableCollection<PartCloneSettingsController> PartCloneSettingsControllers { get; private set; }
For debugging purposes I created a DataGridView in a Winforms control host and attached the same ViewModel to it, and voila: The Winforms grid creates all columns and displays the data as I want it, but the WPF DataGrid fails to generate columns for my custom properties ( it works with plain, normal properties).
Does anybody have a working solution using a DataGrid, ICustomTypeDescriptor and AutoGenerateColumns=True (if I generate the columns by hand in XAML it works fine, and I can bind to all my properties...)
If your PartCloneSettingsControllers is a generic collection of some item type other than object, it will use the generic parameter type to populate the columns, as opposed to the runtime type of the items in the collection.
For example, if your collection is an IEnumerable<PartCloneSettingsController>, then the grid will only populate columns for the properties declared on the PartCloneSettingsController type (and its base types)1. It will not bother inspecting the actual objects in the collection, and since ICustomTypeDescriptor exposes properties at the instance level, the grid won't see those properties.
If you have the option of exposing your 'dynamic' properties at the type or collection level instead of the item instance level (e.g., by using TypeDescriptionProvider or ITypedList), that would probably be your best bet. Otherwise, you'll have to use a collection type for which the grid can't infer the item type (e.g., List<object>); that will force the grid to inspect the first item it encounters to figure out what the columns should be.
1 The grid ultimately resolves properties using TypeDescriptor.GetProperties(Type componentType), as opposed to TypeDescriptor.GetProperties(object component), so without an actual item to inspect, it has no way of knowing which 'dynamic' properties are exposed by the individual items.
I have a Singleton BindingList list with objects.
I need to bind this list to DataGridView.
I need the grid to show only objects with specific property value (Property IsEmpty and I want to show only objects with IsEmpty=false).
I tried to iterate trough the DataGridView rows after the bind completed and hide rows with IsEmpty=false. This worked but the grid doesn't work well in some situation like sorting of columns.
My conclusion is I need to have a sublist of the original list with refrence to all the objects in the original list that have property IsEmpty=true.
Any idea what is the best way for doing this? (I need to preserve the ListChanged event in the new list for the binding work well)
You'll need to filter your data source before binding to your grid. The best way would like be with a call to linq's Where method.
IEnumerable<yourType> initialSource = getYourSource();
yourGrid.DataSource = initialSource.Where(x => !x.IsEmpty).ToList();
This will keep your original collection intact, and will bind the grid only to those objects that match the filter.
Edit
If you can't use linq, then why not a simple loop?
List<yourType> filteredSource = new List<yourType>();
foreach(var item in initialSource)
if (!item.isEmpty)
filteredSource.Add(item);
yourGrid.DataSource = filteredSource;
I have recently begun development using c# and wpf. In our application we have a DataGrid object that we would like to bind to a list. However we do not want all entrys in the list to be bound, only those that meet a certain criteria. The reason that we cannot bind to a seperate list (ie. bind to a list created by the applying the filter) is that we would like 2 way binding, so that when a user adds a row to the table it will be added to the overall list.
Question1: is it possible to bind to a 'filtered' list
Question2: if not what is the best way to get this functionality? i.e. display only certain values but add all new entries to the overall list
thanks in advance
sam
What you want can be accomplised using the CollectionView classes. Here is how to create one with a DataTable as the source.
DataView myView = new DataView( MyDataTable );
ICollectionView cv = CollectionViewSource.GetDefaultView(myView);
You can also use ObservableCollection for a collection of your custom classes. After you create your collection view, you can set filters and sorting and grouping. In the UI, you bind to the CollectionView and you are good to go. So, for multiple views of the same data, just create different CollectionView instances and bind to those. When you update a value on the UI, the item in your store will update "automatically"
this site contains a pretty decent, but simple, example
How to remove selected items from ListBox when a datasource is assigned to it in C#?
When trying to remove, got error
"Items collection cannot be modified when the DataSource property is set."
But when i try to remove item from datasource (datatable) ,
it thorws error as "datarow is not in current row collection".
Find that item in the DataSource object and remove it, then re-bind the ListBox.
EDIT:
Here's how you delete from a DataTable as your DataSource, regardless of the .NET version.
DataRowView rowView = listBox.SelectedItem as DataRowView;
if (null == rowView)
{
return;
}
dt.Rows.Remove(rowView.Row);
I haven't tried with anything other than WinForms DataGridViews, but I highly recommend BindingListView, which is both faster than DataTables/Views and allows you to bind generic List<T>s as your DataSource.
Alternatively, use a list that implements IBindingList or inherits from BindingList. When objects are added or removed from a Binding List, any controls bound to it are automatically notified of the change and will update themselves accordingly. If you are using BindingList and your class also implements INotifyProperty changed, Any changes to class properties will also be updated automatically in the databinding control. For example, if a column in a datagrid(view) is bound to a property, "Name", and you change "Name" in the datasource, the datagrid will automatically update. If you add a new item to the datasource, the datagrid will update automatically. Binding List also supports notification in the other direction. If a user edits the "Name" field ina datagrid, the bound object will be updated automatically. Going off topic slightly, if you go a little further and impliment "SupportsSortingCore" and the associated methods in BindingList, you can add automatic sorting to your data. Clicking on a columnm header will automatically sort the list and display the header sort direction arrow.
If the ListBox has a datasource assigned, you must remove items from the datasource and then rebind the ListBox
You need to modify the data source rather than the Items collection of the control. Depending on what kind of data source you are binding to, there are going to be different things you have to do so that your UI updates.
The best way is find a collection that fits your needs and implements IBindingList or IBindingListView. Those two interfaces implement even handlers that listen for a CollectionChanged event and update your UI accordingly.
If your collection doesn't support those interfaces, you're going to have to re-bind your data source every time somebody adds/removes an item.
when you get the message "Items collection cannot be modified when the DataSource property is set."
setting the datasource to something else, empty list or null does not help when
the code initializecomponent is not completed.
to avoid that error, one must do the change of datasource or the item list during or after form load.
I know it does not seem to make sense. Hoever, the visual studio designer will generate code in the form designer.cs or vb that will add items to the listbox if any code that changes the items is found before end of initialize components
While Chris Doggett posted a valid solution, I ran into problems while using it. By using that method it was not allowing a subsequent GetChanges(DataRowState.Deleted) to work properly.
To better solve my problem, I only had to change a single line - the last line.
DataRowView rowView = listBox.SelectedItem as DataRowView;
if (null == rowView)
{
return;
}
rowView.Row.Delete();
This allowed my GetChanges call to work properly.
This worked for me
DataTable temp = (DataTable)lstBlocks.DataSource;
temp.Rows.RemoveAt(position);
its vary simple , assign a new blank value to listbox
eg..
Dim ABC As New List(Of String)()
ListBox1.DataSource = ABC
ListBox implementation is bugged, you need to create a new data source instance for the component for it to recognize a change.
Eg:
ActivitiesList.DataSource = _activities;
_activities = new List<Activity>(_activities);
_activities.Remove((Activity)ActivitiesList.SelectedItem);
ActivitiesList.DataSource = _activities;