LINQ and ComboBox DataSource issue - c#

How far is the code for best functionallity?
I have two ComboBox, so the first is related for choose the company, and the second for choose the branch-office in relation with the one.
I note that the only way I can fill datasource with filtering .Where on LINQ is on this way, maybe Im wrong please take a moment for look the following snippet :
private void cboCompany_SelectedIndexChanged(object sender, EventArgs e)
{
var _index = ((ComboBox)sender).SelectedIndex;
using (DB db = new DB())
{
var su = (from s in db.Branchs select s);
if (cboCompany.SelectedIndex == 0)
{
cboBranch.DataSource = su.Where(x => x.codeCompany == 1).Select(x => x.name).ToList();
}
else if (cboCompany.SelectedIndex == 1)
{
cboBranch.DataSource = su.Where(x => x.codeCompany == 2).Select(x => x.name).ToList();
}
cboBranch.BindingContext = this.BindingContext;
cboBranch.DisplayMember = "name";
cboBranch.SelectedIndex = 0;
}
}
Thanks in Advance!

Rather than hand-coding this, I would make data binding do all this work for me. In particular, it can be set up thus:
Make it so that your Company class has a property to get all associated branches - e.g. Company.Branches. If you use LINQ to SQL or Entity Framework, there should be one there already.
Have two BindingSources, bsCompanies and bsBranches.
Set cboCompany.DataSource to bsCompanies, and cboBranch.DataSource to bsBranches
Set bsCompanies.DataSource to collection/DataSet that contains companies.
Set bsBranches.DataSource to Branches under bsCompanies (the form designer should let you do this after you do the previous step, if your collection is strongly typed).
Now whenever user picks a different company in the first combo, the current item in the companies binding source will change. This will cause binding for the second binding source to re-evaluate, and set list of branches for a newly selected company to be the source for the second combo.

Related

Filtering Children in Entity Framework Query

I have a database which it's schema is as follows:
As you can see, We have WareCategories which will be category of the wares i'm going to be working in my website. WareTypes which will be Definition of each Item type. Categories define properties in the table WarePropertyDefinitions and WareProperties define values for each property that has been defined in WarePropertyDefinitions table.
Now i have a search page that users search for items in OldWares and user selects category and i show the user all properties defined in WarePropertyDefinitions and user fills the data if he likes better results. But my problem is that i can't filter WareTypes based on WareProperties because it's from the type ICollection and i can't access filter options.
How can i apply this kind of filtering based on properties?
Thanks in advance...
Edit:
This is a part of the code i'm presenting to describe more:
var lst = WareCategory.GetItem(Convert.ToInt32(ddlChildren.SelectedValue)).WarePropertyDefinitions.ToList();
foreach (var ListItem in lst)
{
var value = BaseHelper.FindFormValue("PropertyValue" + ListItem.Id.ToString());
if (!string.IsNullOrEmpty(value))
{
query = query.Where(m => m.WareType.WareProperties.);
}
}
}
This segment of code is in my search function and as you can see i'm going to generate a list of items in WarePropertyDefinition that user selected via a drop down menu called ddlChildren. I'm going to iterate in this definition and user entered value for each property (the value variable will hold the value user entered and i will check if user have entered anything in the textbox) i will include it in where section (through this i will add it in where clause that ultimately filters my selection). but as you can see the code is incomplete because i don't know how to complete it.
Use the Any() extension method, for example:
query = query.Where(m => m.WareType.WareProperties.Any(wp => wp.Id == 5));
I have fixed the my problem by this code:
query = query.Where(m => m.WareType.WareProperties.Any(wp => wp.WarePropertyDefinition_Id == ListItem.Id && wp.TextValue == value));
but because #user3159792's answer was the basic of my problem i have selected his answer as the default answer to my problem. very thanks.

Entity Framework edit data in grid bound to Entity which uses joins

I have a DataGridView which binds to a database through Entities (I am using a Database First approach).
I want to display data in a grid (and update this information before posting back to the database) for an Entity which contains Navigation Properties (i.e. Joins).
The context is that there are Permissions in the application; these permissions are separated into relevant sections and every user either has this permission or does not.
The relationships between the tables
In the dialog, there are two grids; one to show the sections available and another to show the permissions within that section and whether the user has that permission enabled; the bottom grid dynamically populates based on the row selected in the top grid.
The DataGridView has AutoGenerateColumns = false and this cannot change (this is because it's a custom DataGridView to which you add columns yourself due to additional properties being required); additionally, the DataPropertyName is set to that of the column I want to display from the appropriate table.
The two approaches I have explored so far are as follows:
Load entire USER_PERMISSIONS entity and bind the DataGridView:
PermissionsSectionContext.PERMISSIONS_SECTION
.Load();
PermissionsValues.USER_PERMISSIONS
.Where(x => x.USER_ID == 5)
.Load();
SectionsGrid.DataSource =
new BindingSource(
PermissionsSectionContext
.PERMISSIONS_SECTION.Local.ToBindingList(), null);
ValuesGrid.DataSource =
new BindingSource(
PermissionsValues
.USER_PERMISSIONS.Local
.Where(x => x.PERMISSIONS_NAME.PERMSECTION_ID == 1), null);
Problem: This loads the items fine and I can also edit the permissions values and post this back to the database however the Permissions names (i.e. x.PERMISSIONS_NAME.FRIENDLY_NAME) do not show in the grid:
The DataPropertyName values of the columns in the bottom grid are 'FRIENDLY_NAME' and 'VALUE'.
Creating Anonymous types and then setting the 'Column names' using these anonymous types:
PermissionsSectionContext.PERMISSIONS_SECTION
.Load();
PermissionsValues.USER_PERMISSIONS
.Where(x => x.USER_ID == 5)
.Load();
SectionsGrid.DataSource =
new BindingSource(
PermissionsSectionContext
.PERMISSIONS_SECTION.Local.ToBindingList(), null);
ValuesGrid.DataSource =
new BindingSource(
PermissionsValues
.USER_PERMISSIONS.Local
.Where(x => x.PERMISSIONS_NAME.PERMSECTION_ID == 1), null)
.Select(x => new {
FRIENDLY_NAME = x.PERMISSIONS_NAME.FRIENDLY_NAME,
VALUE = x.VALUE});
Problem: All the values show exactly as I want in the grids, including the Permission Name; however, you cannot edit the 'Value' column. Debugging this reveals that when the anonymous type is bound to the DataGridView, it is setting the ReadOnly property to true; this column still needs to be editable and for SaveChanges() to post these changes back, which does work for option (1).
Thanks to Gert Arnold's initial response about using named types (many thanks for the pointer!) I did a bit of reading around and I have managed to get this working as I require.
The first thing I did was create a class which contained only the fields that I was going to use as part of the data operations:
private class UserPermissionsValue
{
public int? PERMISSION_ID { get; set; }
public int? PERMSECTION_ID { get; set; }
public string FRIENDLY_NAME { get; set; }
public int? VALUE { get; set; }
}
As I needed to store all of the permissions which were applicable against the user and then only show, in the bottom grid, those which were relevant to the selected row in the top grid, I kept all of the permissions against the user in a List<UserPermissionsValue>:
private List<UserPermissionsValue> UserPermissionsList = new List<UserPermissionsValue>();
I could then get the records that I needed for this list using projection on the base entities:
UserPermissionsList = ValuesGrid.DbContext.USER_PERMISSIONS.Local
.Select(x => new UserPermissionsValue {
PERMISSION_ID = x.PERMISSION_ID,
PERMSECTION_ID = x.PERMISSIONS_NAME.PERMSECTION_ID,
FRIENDLY_NAME = x.PERMISSIONS_NAME.FRIENDLY_NAME,
VALUE = x.VALUE
}
).ToList();
Using the existing _RowEnter event I had set up, I could simply select the permissions from the section I needed and then bind this to the grid:
int PermissionsSection = ((DataEntity.PERMISSIONS_SECTION)ValuesGrid
.Rows[e.RowIndex].DataBoundItem).PERMSECTION_ID;
ValuesGrid.DataSource = UserPermissionsList
.Where(x => x.PERMSECTION_ID == PermSectionID)
.ToList();
This had the benefit of the modified values being maintained and 'remembered' when changing options in the top grid, as the value and subsequent changes were bound to UserPermissionsList.
Finally, when confirming the dialog, the actual entities were brought in and their values were updated to what they had been set to in the dialog itself; I decided it would be less of a load to bring back all entities in a single request and then iterate through the collection of entities locally, rather than get the records from the DB one-by-one and update them that way:
var PermissionsCommitList = ValuesGrid.DbContext
.USER_PERMISSIONS.Local;
foreach (DataEntity.USER_PERMISSIONS permission in PermissionsCommitList)
{
UserPermissionsValue ValueToCommit = UserPermissionsList
.Where(x => x.PERMISSION_ID == permission.PERMISSION_ID)
.First();
permission.VALUE = ValueToCommit.VALUE;
}
dtgPermissionsSettings.pFormGrid.DataEntityProvider.SaveChanges();

Implementing Search functionality on a datagrid column in C# windows appl

I am working on a windows application using .net 2.0. The UI appl has a datagrid and the data will be populated from the XML file.
The data grid has more than 500 rows. Sorting functionality has implemented. but customer still wants a find option or a search functionality on one of the columns with a text box where user is going to enter first 3 letters and it has to search in the grid and has to show the related rows that starts with the give search criteria.
Any suggestions pls how to implement this....
Thanks
You can use a Filter option in the BindingSource object.
private BindingSource dashBoardBindingSource = new BindingSource();
dashBoardBindingSource.DataSource=<<data source items>>;
dashBoardBindingSource.Filter="Column Name=textbox.text";
datagrid.DataSource = dashBoardBindingSource;
Store off your full collection of data, and then when the filter needs to be performed, create the filtered collection and bind the filtered collection to the grid. Just wire up appropriate text changed events to your filter box, calling FilterGridData. It works nicely when filtering via multi-column as well. Oh, and you don't have to use BindingList here. Use whatever data source you want to bind to the grid - the core of this is just "create the filtered collection by filtering with LINQ."
BindingList<Foo> _allFoos;
private void LoadData(IEnumerable<Foo> dataToDisplayInGrid)
{
this._allFoos = new BindingList<Foo>(dataToDisplayInGrid.ToList());
this.FilterGridData(string.Empty);
}
private void FilterGridData(string filterText)
{
BindingList<Foo> filteredList = null;
if (!string.IsNullOrEmpty(filterText))
{
string lowerCaseFilterText = filterText.ToLower();
IList<Foo> filteredItems = this._allFoos.Where(x => (x.Name ?? string.Empty).ToLower().Contains(lowerCaseFilterText)).ToList();
filteredList = new BindingList<Foo>(filteredItems);
}
else
{
filteredList = new BindingList<Foo>(this._allFoos);
}
dataGrid.DataSource = filteredList;
}

Adding an item to a bound WPF ListBox

Ok, this has been a head scratcher for me. I have a ListBox I am binding to a linq query like so:
private IQueryable<Feed> _feeds;
public IQueryable<Feed> Feeds
{
get
{
if (_feeds == null)
{
var feedsQuery = from f in _db.Feed orderby f.Title select f;
_feeds = feedsQuery;
}
return _feeds;
}
}
public Options()
{
InitializeComponent();
this.DataContext = Feeds;
}
(For the record I've also tried List, instead of IQueryable)
Everything shows up great and I have a databound form that allows you to edit a record and all of those changes work just fine, the modified data shows up in the list.
The problem comes with I add an item. Nothing shows up in the list. The data goes into the database fine, but the only way to see the data is closing and restarting my app. I'm using the code below as an example:
Feed feed = new Feed()
{
ID = Guid.NewGuid(),
Url = "http://www.test.com",
Title = "Test"
};
_db.Feed.InsertOnSubmit(feed);
_db.SubmitChanges();
_db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
(with or without the _db.Refresh nothing happens)
What's going on?
You are doing everything right, you jus need to use ObservableCollection. This will notify the ListBox about any changes in the list and refresh it automatically.
From MSDN
In many cases the data that you work
with is a collection of objects. For
example, a common scenario in data
binding is to use an ItemsControl
such as a ListBox, ListView, or
TreeView to display a collection of
records.
P.S. you don't need a db refresh
Unless notified otherwise, the ListBox only iterates once over its ItemsSource. Your query is only being run once.
The query object doesn't know when the database changes (and Refresh doesn't help; see below)--it's up to you to know (or anticipate) that and to rerun relevant queries at the appropriate times.
Stan R mentions ObservableCollection. That's fine, but simply storing the result of your query in an ObservableCollection won't solve the problem unless you do some work to update the collection yourself when the database changes. This means rerunning the query and manually adding new items and removing deleted items from the collection. (You could alternatively just rerun the query and set the entire result back in to the ListBox, but that means a whole new set of items will be created--not very performant, and maybe not what you want for other reasons.)
As an aside, your call to DataContext.Refresh is probably not doing what you think it is. From the docs:
This method is useful after an optimistic concurrency error to bring items into a state for another attempt. It updates the state of the primitive fields and properties on the objects.
Okay. I'm not positive this is 100% the correct way to use the ObservableCollection, but this seems to work:
private ObservableCollection<Feed> _feeds;
public ObservableCollection<Feed> Feeds
{
get
{
if (_feeds == null)
{
var feedsQuery = from f in _db.Feed orderby f.Title select f;
_feeds = new ObservableCollection<Feed>();
foreach (var item in feedsQuery)
{
_feeds.Add(item);
}
}
return _feeds;
}
}
And add my item:
Feed feed = new Feed()
{
ID = Guid.NewGuid(),
Url = "http://www.test.com",
Title = "Test"
};
_db.Feed.InsertOnSubmit(feed);
_db.SubmitChanges();
// manually update the list
Feeds.Add(feed);
It took me a little while to figure out I had to update the list manually (thanks Ben), but it all seems to work. Sorting would be nice, but I'll worry about that another time.

How do I add to a list with Linq to SQL?

I have a table in the database that I'm retrieving using LINQ to SQL, and as a part of my processing I want to add to this list, then update the database with the new items + any changes I've made.
What I thought I could do was this:
var list = (from item in db.Table
select item).ToList();
[do processing where I modify items & add to the list]
list = list.Distinct();
db.SubmitChanges();
What happens is that the modifications happed (ie. SQL updates) but any new items I add to the list don't get added.
Obviously I'm doing this wrong, what is the correct way to modify & add to a list of DB entities, then commit all the updates & inserts?
The List is meaningless. It's just happens to hold objects that the DataContext knows about. We need to make sure that the DataContext knows about the new ones. The important thing is that they don't have to be complete when we alert the DataContext to them:
Item item;
if (needNewOne)
{
item = new Item();
db.InsertOnSubmit(item);
}
else
{
item = list[i];
}
/// build new or modify existing item
/// :
db.SubmitChanges();
You can create an extension method for it:
static void EnsureInsertedOnSubmit<TEntity>( this Table<TEntity> table
,IEnumerable<TEntity> entities)
{ foreach(var entity in entities)
{ if ( table.GetModifiedMembers(entity).Length == 0
&& table.GetOriginalEntityState(entity) == default(TEntity))
{ table.InsertOnSubmit(entity);
}
}
}
And then you can do this:
var list = db.Table1.ToList();
list.Add(new Item());
db.Table1.EnsureInsertedOnSubmit(list);
db.SubmitChanges();
You have to add the new items via InsertOnSubmit.
You've got to tell LINQ to insert the new row on submit, using InsertOnSubmit:
db.InsertOnSubmit(newrow);
db.SubmitChanges();
You do not need a new DataContext, you can use the one you are using for updates.
Same for delete DeleteOnSubmit(row). Modifications will be tracked, though.

Categories

Resources