Add expandAll/collapseAll or toggleAll details for master detail dataTable using Tomahawk - tomahawk

I wanted to expand/collapse all my extended-record values in the dataTable.
Right now it works with "Hide/Show" for each record in the t:dataTable
I see in the aPI there is are methods
public void collapseAllDetails()
public void expandAllDetails()
How can I use these methods with my t:dataTable

Related

unable to add row to a winforms datagridview that is bound to a SortableBindngList

I have a datagridview that was bound to a generic List<> of my objects. Everything works fine. I then changed the List to a SortableBindingList so that I can sort the columns. This works fine to except now I get an exception when I try to add a row. The exception is:
"Operation is not valid due to the current state of the object."
This occurs in the WinForms runtime in DatagridView.DataGridviewDataConnection.ProcessListChanged method.
Anyone have any ideas what the problem might be?
So you have separated your data from how it is displayed. Good for you! Too often I see that people try to fiddle with cells and rows instead of using the datasource.
However, if your DataSource is a List<...>, the changes that the operator makes to the DatagridView are not reflected in the DataSource.
If you want that items that are added / removed / changed by the operator are also changed in your DataSource, you should use an object that implements IBindingList, like (surprise!) BindingList
You forgot to tell us what you show in your DataGridView, let's assume you show Products
class Product
{
public int Id {get; set;}
public string Name {get; set;}
public decimal Price {get; set;}
public int StockCount {get; set;}
public string LocationCode {get; set;}
...
}
Using visual studio designer you've added the columns that you want to show. You'll have to tell which column shows which property. For instance in the constructor:
public MainForm()
{
InitializeComponents();
// define which columns show which properties
columnId.DataPropertyName = nameof(Product.Id);
columnName.DataPropertyName = nameof(Product.Name);
columnPrice.DataPropertyName = nameof(Product.Price);
...
To make access to the displayed products easy, add a Property:
private BindingList<Product> DisplayedProducts
{
get => (BindingList<Product>)this.dataGridView1.DataSource,
set => this.dataGridView1.DataSource = value;
}
Initialization:
private void ShowProducts()
{
IEnumerable<Product> queryProducts = this.FetchProducts();
this.DisplayedProducts = new BindingList<Product>(queryProducts.ToList());
}
Now whenever the operator adds / removes a row, or edits the cells in a row, the BindingList is automatically updated, even if the columns are rearranged, or the data sorted.
If the operator indicates that he finished editing the data, for instance by pressing a button, you immediately have all updated information:
private void OnButtonOk_Clicked(object sender, ...)
{
ICollection<Product> displayedProducts = this.DisplayedProducts;
// find out what is added / removed / changed
this.ProcessEditedProducts(displayedProducts);
}
If you need to access selected items, consider to add the following properties:
private Product CurrentProduct => (Product)this.dataGridView1.CurrentRow?.DataBoundItem;
private IEnumerable<Product> SelectedProducts => this.dataGridView1.SelectedRows
.Cast<DataGridViewRow>()
.Select(row => row.DataBoundItem)
.Cast<Product>();
If the operator adds a row, he starts with a row that is constructed using the default constructor. If you don't want this, but for instance initialize the Id, or the LocationCode, consider to subscribe to event BindingList AddingNew
this.DisplayedProducts.AddingNew += OnAddingNewProduct;
void OnAddingNewProduct(object sender, AddingNewEventArgs e)
{
e.NewObject = new Product
{
Id = this.GenerateProductId(),
Name = "Please enter product name>",
LocationCode = "Unknown Location",
...
};
}

Sort "Master-Detail" DataGridView bound to Entity Framework in Winforms

I'm writing a small business application in C#, .NET 4.0. I am using SQL Server CE 4.0 as my database.
I use Entity Framework to communicate in both directions with database. My datagridviews are bound to Entity Framework collection, thus user can add new or modify existing data directly in datagridview. The problem is that sorting with Entity Framework bound to datagridview is not really supported. From what I have learned:
I can intercept clicks to column header cells and then perform sorting and rebind result to datagridview. It is a bit tedious, but it works for master datagridview. But when I do that also for "detail" datagridview" then I loose the automatic rebinding of "detail" datagridviews (when new row from master table is selected). So I have to deal with that also.
I can cast query to a list / binding list and pass it to a sortable bindinglist. Well here I have the same problem with rebinding "detail" datagridviews manually. The new problem that here arises is, that now I have to somehow fix saving, because new data is added only to the sortable bindinglist and not directly to the Entity Framework context.
What should I do (and how)? Should I just use DataSets?
My preference is to use an intermediate [observable]collection which holds the sorted entities. However this is in the WPF/MVVM world. And even then the Pattern is still relatively the same for ASP.NET ObjectDataSource or MVC using Collections. It's been quite some time but maybe I can brain dump a bit where hopefully you can find something useful.
I'm pulling this from memory so bare in mind this is nothing more to help point you in some direction.
Form variables we'll use.
private string SortProperty { get; set; }
private ListSortDirection SortDirection { get; set; }
private ICollection<myItems> items; // Entity Collection
private ObservableCollection<myItems> SortedItems { get; set; } // Sorted Collection
Overload the form OnLoad event handler to register a header clicked handler to apply sorting.
protected override void OnLoad(EventArgs e)
{
dataGridView1.ColumnHeaderMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(dataGridView1_ColumnHeaderMouseClick);
LoadDataGridView();
base.OnLoad(e);
}
protected override void OnUnload(EventArgs e)
{
dataGridView1.ColumnHeaderMouseClick -= new System.Windows.Forms.DataGridViewCellMouseEventHandler(dataGridView1_ColumnHeaderMouseClick);
base.OnUnload(e);
}
Perform our initial load of the sorted data.
private void LoadDataGridView()
{
items = myRepository.GetAllItems(); // However you get or have your collection of items.
ApplySort();
dataGridView1.DataSource = SortedItems;
}
Sort our data and save in new collection. The OrderBy requires Dynamic Query Library: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx.
private void ApplySort()
{
// IQueryable<myItems>, ICollection<myItems>, ObservableCollection<myItems>... be aware of cross threading and how you will handle updates.
SortedItems = items.AsQuerable().OrderBy(SortProperty + (SortDirection == ListSortDirection.Ascending ? " asc" : " desc")).ToList();
}
Our click event handler. Remember, you will have to handle entities added, deleted and changed.
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
var propertyName = GetPropertyName(dataGridView1.Columns[e.ColumnIndex])
SortDirection = SortProperty == propertyName ?
SortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending
: SortDirection;
SortProperty = propertyName;
ApplySort();
dataGridView1.DataSource = SortedItems;
}
Trivial helper method for sorting.
private string GetPropertyName(int columnNumber)
{
switch(columnNumber)
{
case 0:
return "Id";
case 1:
return "Name";
default:
return "Id";
}
}
Here is some additional information:
http://msdn.microsoft.com/en-us/library/ms171608.aspx
I know this isn't an exact answer but since no one else will chime in, maybe you can take this, hack it up until it works gracefully and then comment your solution for the next person.

C#: Pushing changes from DataGridView to BindingList back to database?

I'm using a BindingList to display a list of Person objects in a DataGridView in a Windows Forms application. Changes to the DataGridView change the underlying BindingList. I've got this part working.
Now I want the list persisted to a database table. Reading the list from the database and populating the Person list is straight forward, but if I add/edit/delete a person from the DataGridView, how and when do I persist that change back to the database?
(Secondly, is this approach okay or am I missing some bigger picture? I don't want to use data tables because I want to work with my code in an abstracted object oriented way.)
For easy persistence of objects in Windows Forms for a start you can use LINQ2SQL, it does exactly what you want plus also materializes objects when you want to gather them from database.
Quick example, after you create linq context from database schema for supported databases, which is SQL Server (Express), all you need is to create it's instance in your form and use it during single atomic operation with data - read, edit, write or cancel.
private YourAppContext context;
private void RenewContext()
{
context = new YourAppContext();
}
private void LoadData()
{
RenewContext();
DataGridView1.DataSource = context.Articles.OrderByDescending(x => x.DatePosted).Take(10);
}
private void AcceptButtonPressed()
{
context.SubmitChanges();
}
private void CancelButtonPressed()
{
LoadData();
}
Obviously you can pass your data through BindingSource.

Requirements for design-time data source in Report Viewer 2010

What are the requirements for a custom data source to be listed in the 'Data Source' drop-down list when adding a Dataset to a .rdlc report in Report Viewer 2010?
As can been seen from the screen grab, for some reason it is listing potential sources from a variety of referenced assemblies, but I can't see an obvious pattern as to why it is selecting these.
The 'GeneralDataSet' makes sense as that is a strongly-typed Dataset class, but I'm pretty sure most of the others are not, yet the design dialog still lists them.
I'm looking to roll my own custom data source and would prefer it to be selectable from this list.
I think it scans your project file looking for methods that return Lists<> and so on.
So something like:
public class Person
{
public string name { get; set; }
public int age { get; set; }
}
public class GetPeople
{
public List<Person> GetPeopleList()
{
return null;
}
public IEnumerable<Person> GetPeopleIEnumerable()
{
return null;
}
public IQueryable<Person> GetPeopleIQueryable()
{
return null;
}
}
All three show up, so take your pick. (Code is just thrashed out, ignore bad names/practices :))
But when you use a ReportViewer, you will need to manually set the datasets. Selecting it inside the report from what I have found just basically tells it what data to expect. So add an ObjectDataSource or just set it in the code behind.
I noticed the dataset does not appear if the source is exposed as a Property and not a method.
ie this fails to be a selectable data source.
public class FooData
{
public List<string> Data {get;set;}
}
but this will show up as a data source
public class FooData
{
public List<string> GetData();
}
I just had a problem with this also,
my class was returning Lists but would not show up in the datasources list.
I then added a parameterless constructor and it started to show up ( there was not one before ) I assmume this is so the reportviewer can create and instance of it.
eg:
public MyObject()
{
}
I've had a similar problem with custom lists which inherit from List.
You can work around it if your system will allow you to inherit without using interfaces. Ours doesn't.
The project containing this class WILL appear in the DataSource dropdown, and the class itself appears in the DataSet dropdown:
public class AccountList : List<AccountData>
{}
This class will NOT appear as a Dataset, which prevents its project from appearing as a DataSource (notice the "I" in front of AccountData):
public class AccountList : List<IAccountData>
{}
This is a pain because other aspects of our system require the lists to inherit from an interface not a concrete class. I don't know why it doesn't work.

Entity framework : Watch changes saved on my objects

For my project, I have to log all changes made on my objects, through the entity framework. This consists just to register which fields have been edited on which table at which time.
Roughly, put changes in a table with this kind of structure:
IDEvent, EventDate, TableName, RowID, FieldName, OldValue, NewValue
If there is multiple changes, several rows will be inserted.
It already works for 90% of my cases, I'm listening the SavingChanges event of the ObjectContext
My only problem: In the case of an add, my primary keys that are generated by SQL(IDENTITY), are not present at this moment(logic) on the SavingChanges event, because it's not already stored in the DB, and the problem is that I really need it(To fill my RowID in my table)
So, do you have an idea how to do this? I didn't found any "ChangesSaved" event. An idea of workaround?
You will not be able to do this in SavingChanges event. I think you can create your own wrapper for ObjectContext and implement your own logic in wrapper method for SaveChanges. Logic should be like
public class MyContextWrapper : IDisposable
{
private ObjectContext _context;
public void SaveChanges()
{
// Detect changes but do not accept them
_context.SaveChanges(SaveOptions.DetectChangesBeforeSave); // SaveChanges(false) in .NET 3.5 SP1
// TODO audit trail
// Audit is completed so accept changes
_context.AcceptAllChanges();
}
}
You should also add TransactionScope to your new SaveChanges.

Resources