I have created a DataSet with multiple tables. I use a few tables on one form, and then 2 other tables on 2 other forms. When I try to do the binding of the data, I cannot figure out how to have all 3 forms refer to the same DataSet object. In the interface (Visual Studio Express 2013) I can select from the Project Data Sources list and get my MainDataSet class and then select whichever table I want. But if I do this, I get a new object. None of the other options seem to allow me to pick an already existing object. I thought I used to see an option to pick my MainDataSet object from somewhere, but I don't currently see that option and even so, it didn't allow me to select a table anyway.
I know I could look closer at the binding code and figure out how to make this work, but since some of that code is in the Designer file, I can't modify it so it seems the best I can do if I do this is replace what it did with new bindings. And it seems like I shouldn't have to do this. There HAS to be a way to do this in the Visual Studio GUI.
You should create a BindingSource in the designer, then set its source to the DataSet in the designer.
You can then change your form's constructor to set the BindingSource's source to a shared DataSet.
Based on SLaks' suggestion, here is what I did.
I dragged a BindingSource onto a form and named it sharedDataSource.
In the Properties of the BindingSource I set the DataSource by selected MyDataSet class under the Project Data Sources heading. I believe this created the DataSource object and bound it to the BindingSource.
In the designer I chose the data source for the the DataGridView objects by selecting sharedDataSource and then the appropriate table under that.
For the DataGridViews in the second form I selected Other Data Sources-->Project Data Sources-->MyDataSet.
I created a constructor for the second form that takes a MyDataSet object as a parameter. In the constructor I set both SomethingOrOtherBindingSource.DataSource and mainDataSet to the paramater. I think the former is required, but the latter may only be required if you refer to it in your code.
When I create the second form (from the first form), I passed in sharedDataSource to the constructor.
So in the designer a data source is bound to the grid and you can use the designer to do whatever you need to (e.g. change column sizes, etc.), but when the program is run, the data source is changed to be the shared one. It seems to work.
Related
I'm learning how to make a WPF application by making a tool to help me with Dungeons & Dragons.
Basically it's a database of Items, where I can also generate a list of loot by "rolling" on a "Treasure Table" which gives me "Item Tables" to in turn roll on.
I'm done making both the Item database viewer as well as a window where you can select an Item table, see its contents in a datagrid and add, edit, and delete Item Tables.
I now need to make the same for Treasure Tables. It needs to be so similar to the Item Table editor, that I wonder If I can't just reuse it, feeding a TreasureTableVM in instead of an ItemTableVM. Depending on which VM is set as the Window's DataContext, the view would do things slightly different, including showing different some columns in the datagrid.
The TreasureTableVM and ItemTableVM have the same methods and properties, although with slightly different implementation. Also a couple properties have different types (currentTable is TreasureTable in TreasureTableVM, ItemTable in ItemTableVM. CurrentRow is TreasureTableRow in one, ItemTableRow in the other. TableList is ObservableCollection in one, ObsevableCollection in the other)
How would I go about it?
You can use the same table and just add a new field in your datacontext, named "type" and the value is "treasure" or "item".
Then on your VM just filter the data by type.
I can directly bind my DataGridView control to a bindinglist of my business objects by setting the DataSource property. My business object implements INotifyPropertyChanged, so the DGV gets updated when a new item is added to the Binding List or existing one is updated.
With respect to dealing with single records, I can bind my business object to textboxes and other relevant controls.
I can also derive from BindingList and create a CustomBindingList class to implement required methods of IBindable, as explained in the link below :
http://msdn.microsoft.com/en-us/library/aa480736.aspx
Alternatively, I have seen people recommend using a BindingSource. BindingSource's Datasource is the business object and the DGV's DataSource is the BindingSource.
In any case, basing it on a BindingSource does not offer me:
Filtering (Filter does not work). Implementation needs to be provided by me.
Sort and Search does not work. Implementation needs to be provided by me.
So, Why is the BindingSource approach recommended?
Broader Picture:
Am new to OOPS concepts and C#. Working with Database applications. Winforms. So far have only used DataSet / DataTable approach. Now trying to create and use my own custom classes.
Typically have a Master/Detail form. When I click on a Detail row in the DGV, I want to edit that record in a separate window. So I need to get a handle on the list item represented by that row in the DGV. Trying to find a solution for that has brought me to this point and this doubt.
Given what I want to do, which approach is better and why?
Some pointers here would really help as I am very new to this.
It is recommended to use a BindingSource when multiple controls on the form use the same datasource (Behind the Scenes: Improvements to Windows Forms Data Binding)
Design-time: I personally find the BindingSource very helpfull when choosing the properties from my business object when databinding to controls.
To get a handle to the currently selected row, try bindingSource1.Current as MyBusinessObject;
As for filtering and searching: I use a third party dll for grids that have that implemented. So can't help you with that, sorry.
When you work with lists of different types of business objects, don't use the list directly
List<IAnimal> animals = new List<IAnimal>();
animals.Add(new Cat());
animals.Add(new Dog());
bindingSource1.DataSource = animals;
Instead use a BindingList like this:
bindingSource1.DataSource = new BindingList<IAnimal>(animals);
That will make sure all accessed objects in the list are of type IAnimal and saves you some exceptions.
Binding to a DataSource could give you benefits when dealing with a large set only a part of which gets displayed. For instance if you look at the Telerik ListView here http://www.telerik.com/help/winforms/listview-databinding.html (there are many of these component packages, this is just the latest one I am using bits and pieces from).
The view is very lightweight and lets your scroll position determine which objects need to be actually displayed. So if you only look at the first 10 objects and never scroll down only 10 get bound and displayed. This potentially avoids a lot of unneeded data access.
Their GridView functions in the same manner. There is the displayed part of the grid which is separate from the potentially huge underlying grid.
As a bonus, you get filtering, sorting, grouping.
As far as I know, if you are working with a database, you use a bindingSource in the middle in order to establish a bilateral bridge between the database and your control. Otherwise you can just use a bindingList as source for your control.
I have a DataGridView on my form that I have associated with a data source using the designer. This allows me to customise the columns in the designer, which helps me a lot. My problem is that I now cannot work out how to submit changes made in the grid view to the database.
I have a DataGridView object, a TableAdaptor object and a BindingSource object - I cannot figure out which combination of calls to make to fluck all changes made in the grid to the database. Ideally, I would also be able to refresh the grids with the latest information from the database as well.
Does anyone have any ideas?
Cheers,
Oops - Straigth after posting I stumbled across the solution:
myTableAdaptor.update(MyDataSet);
For me, both the table adaptor and the data set had been auto-generated as class member variables.
I'm quite new to C# (coming from a Java background) and I'm working on a Form to quickly manage different data (e.g. Users, Domains, Computers) along with providing utilities that use the data.
To avoid confusion the following is a summary of the example data structure;
<User>
<Name>joe</Name>
<Domain>europa</Domain>
</User>
<Domain>
<Name>europa<Name>
<Domain>
<Domain>
<Name>group</Name>
</Domain>
<Computer>
<Name>localhost</Name>
</Computer>
In my Form I have tab pages for each data, each containing a DataGridView (containing a column for each member) to allow for simple management. I'm using a single DataSet which reads the data from an XML file (using a schema) when the Form Load event is fired. After reading the data I am setting the tables as the DataSource of their respective DataGridView using the code;
userDataGridView.DataSource = dataSet.Tables["User"];
domainDataGridView.DataSource = dataSet.Tables["Domain"];
computerDataGridView.DataSource = dataSet.Tables["Computer"];
This is working properly for the Domain and Computer DataGridViews as they only have single text columns which are mapped to the Name properties. However, the Domain column of for the User DataGridView is a combo box and I need that to contain all the possible Domains (e.g. europa, group) as well as the selected Domain being bound to User.Domain (also, the User.Domain being initially selected).
My main question is how I achieve the above but I also have some additional questions hopefully someone can answer;
I'm assuming that changes made to a DataGridView are immediately persisted in the underlying XML file as I am reading it from the build's output directory. Is this correct or is additional configuration/process required?
During my attempts at getting this to work I tried to use a DataRelation as follows;
DataRelation dataRelation = new DataRelation("Domain users",
dataSet.Tables["Domain"].Columns["Domain"],
dataSet.Tables["User"].Columns["Domain"]);
dataSet.Relations.Add(dataRelation);
How exactly do DataRelations work and what effect do/can they have?
In case it helps you understand/explain I am using the SharpDevelop IDE for working on this application.
Thanks in advance.
As you have already found out, the DataGridView is very powerful and does most of the work in an automagically way. Unfortunately you run into problems if these defaults doesn't match your preferences (like using a ComboBox for a text property).
To get the DataGridViewComboBoxColumn into the proper place you can do this programmatically within your code or (if possible) do it with the designer (in Visual Studio don't know if SharpDevelop supports it).
Using the (Visual Studio) Designer
For this scenario it is necessary that the structure of the data is known at design time by providing a class holding all (or more) informations as simple properties (like a person class with properties name, age, etc.). If this is available you can add a BindingSource to your control and click in the properties window at the button next to the DataSource property. Select Add Project Data Source and select Object and select your desired object.
Now you have a binding source configured with a specific type of DataSource. Next select your DataGridView and change the DataSource property to the recently created binding source.
After this the DataGridView will automatically be populated with a column for each property. Now you can easily step into the Columns property and change the behaviour and type of each column as you like.
To connect your concrete data with the DataGridView just apply your table to the binding source.
Doing the same at runtime
If you have Visual Studio and followed the above steps you can afterwards easily take a look into the Designer.cs file to find how Visual Studio did all the stuff. There is nothing you can't do also manually. So if you need to just do it.
Simply create a DataGridViewComboBoxColumn, set the DataPropertyName and HeaderText and you've got a good starting point. Get the IndexOf() the column you want to replace, remove it and Insert() your freshly created column at the position you want.
Before the Grid can show some data (in the ComboBoxColumn) you need to provide a list with the possible values. For this purpose the comboBoxColumn has a DataSource property on itself where you can provide the desired values. With the simplest scenario you just provide an ICollection<string>, but you can also give something more complex like List<KeyValuePair<Enum, string>>. If that's the case you should also set the properties ValueMember and DisplayMember to tell the ComboBox which properties of the objects should be used to populate the list.
Maybe with these informations given you should take a look at the MSDN article about the DataGridViewComboBoxColumn and study the example. This should give you some additional hints on how to set it up properly.
I don't have much experience with C# or VS, but I want to add a property table to a form, like this one:
So that columns are resizable, editable, of different types (e.g. checkbox for boolean) and sortable. How do I do that?
That looks like a WinForms Listview and that should be able to support everything you need. Just add it to the form, change it to the View property to Details and then when you add the columns you can set their types as checkbox column etc.
You can either bind it to a datatable or similar or add the data manually by add to it's Items property (and you add the other columns data by adding sub items to each item).
I'd suggest trying that out first and then come back with separate questions for anything that you're having problems with.