Grouping by non-column in objectlistview - c#

I have about 5-6 rows of data that I need to display, when I add data I'd like to be able to sort the data in 4 different sections and none of these will be grouped by any column value its simply getting grouped by a SQL value etc.
How do you do this effectively with the objectlistview?
Its pretty straightforward with the standard listview:
listView1.Items[0].Group = listView1.Groups[0];
I can't seem to figure it out in the objectlistview though.
Thanks.
Adding code:
public class AdminHistory
{
public string Ordernr { get; set; }
public string newImei { get; set; }
public string Imei { get; set; }
public string Fel { get; set; }
public string Modell { get; set; }
public string Garanti { get; set; }
public string Datum { get; set; }
public string User { get; set; }
public string Status { get; set; }
}
private void admin_Load(object sender, EventArgs e)
{
List<AdminHistory> list = new List<AdminHistory>();
list.Add(new AdminHistory() { Ordernr = "12345", newImei = "",
Imei = "test", Fel = "test", Modell = "abc",
Garanti = "ja", Datum = "2014-01-01 18:31", User = "123", Status = "waiting"});
adminHistory.SetObjects(list);
}
My objectlistview has the propper aspectnames.
Basically I don't want to group by any of the fields above, I simply want to be able to create a virtual group and group a lot of data into 4 separate groups, then these groups will be displayed in the listview and the user may view them as he/she wishes.
Example image by creators of objectlistview:
http://www.codeproject.com/KB/list/ObjectListView/fancy-screenshot2.png
The grouping in that image does not group by a column, (I think atleast) but rather a virtual group just like I'm trying to achive.

The grouping in that image does not group by a column, (I think atleast) but rather a virtual group just like I'm trying to achive.
The example actually IS grouped by a columns aspect value. But it additionally uses the "Grouping by Ratings" feature using groupColumn.MakeGroupies.
As far as I know, grouping is always bound to a column. However, you could achieve what you want with a small workaround.
"The crucial part to understand is that all model objects that have the same “key” are placed in the same group. By default, the “key” is the aspect of the model object as calculated by the grouping column."
You can return your own "group key" by installing a GroupKeyGetter delegate, but this property is bound to a column. However, you could just use a "spare" column of your choice , install the GroupKeyGetter for it and return the desired "key" which could be anything.
mySortColumnOfChoice.GroupKeyGetter = delegate(object rowObject) {
var key = /* create your key here */
return key;
};
Then use
objectListView1.BuildGroups(mySortColumnOfChoice, SortOrder.None);
to create the group using your "custom" key.

Related

C# Linq order by with new mapped value

I have List of Orders, which have the property "Status" which is an int. For each status I have a translations in different languages. I want to sort my list by the selected translation and not by numeric status value. What is the best practice here?
public record OrderTranslation
{
public string OrderStatus { get; set; }
public string StatusDescription { get; set; }
public Language Language { get; set; }
}
public record Order
{
public int? Id { get; set; }
public int Status { get; set; }
// I have added a new value to set the translated value and I want to order by this
public string TranslatedStatusValue { get; set;}
}
my function:
public async Task<FilterResult> FilterAsync(FilterRequest filterRequest, List<string> filterProperties, Language selectedLanguage)
{
var orderTranslations = dataContext
.OrderTranslations
.Where(ot => ot.Language == selectedLanguage)
.ToList();
var orders = dataContext.Orders.AsNoTracking();
foreach (var order in orders)
{
var description = orderTranslations
.Single(x => x.OrderStatus == serviceContract.Status)
.StatusDescription;
serviceContract.TranslatedValue = description;
}
// The TranslatedValue is always empty here
// This is not working, but I want to Order by the translation. Is there another possibility to to this, not using an extra property?
IQueryable<ServiceContractOrder> query = orders
.OrderBy("TranslatedStatusValue", filterRequest.IsSortAscending)
.WhereMatchesFilter(filterRequest, filterProperties);
result.FilterHits = await query
.Skip(filterRequest.ItemsToSkip())
.Take(filterRequest.ItemsPerPage)
.Cast<object>()
.ToListAsync();
result.TotalCount = await query.CountAsync();
result.ObjectType = typeof(Order).AssemblyQualifiedName;
result.FilteredProperties = filterProperties;
}
It all depends on your size of data and what you want to achieve.
If you have small data set, without pagination, you can sort them in client side ( in your dotnet code).
If you have a large dataset, and/or you need pagination, then you will need to apply the sorting to the DB. In such case, I would suggest you to store the translated values in Same table as Owned Entity or maybe different table. And then you can apply sorting in your LINQ query.
Two benefits you get is,
Sorting is absolute, and order is maintained across queries.
Performance, as sorting on client-side hurts for large data sets.
What you lose,
Any change to translation has to be applied to DB. This makes your database complex.
If the order status is a fixed set of data, like enum, then you can chose to have a denormalized design. i.e., to have a dedicated OrderStatus table with translations and then join them to your Order table.
Your domain will be somewhat like,
public record OrderStatus
{
int Id{get; set;}
public ISet<OrderTranslation> Translations { get; set; }
}
public record OrderTranslation(Language Language, string)
{
public string OrderStatus { get; set; }
public string StatusDescription { get; set; }
public Language Language { get; set; }
}
public record Order
{
public int? Id { get; set; }
public OrderStatus Status { get; set; }
}

Getting value and putting value to combobox

I'm newbie with winforms and I'm using a combobox. I like to learn how to load from Database to Controls (Combobox) and how to SAVE values from Control (combobox) to Database field.
Below I need some help on process get from Combobox and put/select value to combobox... But don't know how to do...
Below I get all rows in a list and bind to a combobox. That works fine, but like to do some actions which I'm struggling.
Can someone advice how to do these action?
I'd like to "add on top" of comboboxList an empty value so they can also select an empty value in comboboxlist.
How to select a value in combobox when putting from DB to Control.. I'm doing like this
comboboxAccount.SeletedText = _account.Number, but it's not selecting.
now it's showing "Number" in combobox, but I like to show Number + "-" Description. How to do this? now it's showin e.g. 4000 but I like to show "4000 - Description1"
I like to store the Account.Id into the Database not the Account.Number, but how can I do that because the combobox is showing the Number... so SelectedText is not which I want.
Code:
public class Account
{
public Int32 Id { get; set; } e.g. 1
public string Number{ get; set; } e.g. 4000 (alpha-numeric)
public string Description1 { get; set; } e.g. Customer
public string Description2 {get; set;} e.g. VAT account
public string Language {get; set;} e.g. EN
}
//returns all rows
IList<Account> _account = new List<Account>(Account_repository.GetAll());
comboboxAccount.DataSource = account;
comboboxAccount.DisplayMember = "Number";
comboboxAccount.Add(??); (see point 1)
//saving to database
Client _client = new Client();
_client.Account = comboboxAccount.??; (see point 4)
1) I'd like to "add on top" of comboboxList an empty value so they can
also select an empty value in comboboxlist.
An item can never be added directly to the comobbox items, if the DataSource property is set.
So, the list(datasource) should be updated with empyt/dummy object before setting it as the DataSource.
You might have to find a way to describe that your current object is a dummy object.
Example, you could introduce an EmptyItem property, and handle/filter it before saving:
public class Account
{
public Account(bool isEmptyItem =false)
{
this.EmptyItem = isEmptyItem;
}
public Int32 Id { get; set; }
public string Number { get; set; }
public string Description1 { get; set; }
public string Description2 { get; set; }
public string Language { get; set; }
public bool EmptyItem { get; private set; }
}
IList<Account> _account = new List<Account>();
_account.Add(new Account(true))
_account.AddRange(Account_repository.GetAll());
.
2) *How to select a value in combobox when putting from DB to Control..I'm doing like this comboboxAccount.SeletedText = _account.Number, but it's not selecting.*
Since the comboBox is binded to an object, you cannot set its SelectedText instead you should use SelectedItem
Example://You need to write a logic to find out how to get this item.
this.comboboxAccount.SelectedItem = this.comboboxAccount.Items[1];
3) now it's showing "Number" in combobox, but I like to show Number + "-"
Description. How to do this? now it's showin e.g. 4000 but I like to
show "4000 - Description1"
You might have to expose another propety say DisplayText and bind it to DisplayMember of the combobox.
Example:
public class Account
{
public string Number { get; set; }
public string Description1 { get; set; }
public bool EmptyItem { get; private set; }
public string DisplayText
{
get{return this.Number + "-" + this.Description1}
}
}
this.comboboxAccount.DisplayMember = "DisplayText";
4) I like to store the Account.Id into the Database not the
Account.Number, but how can I do that because the combobox is showing
the Number... so SelectedText is not which I want.
You should use SelectedItem since you have binded an object
var account = this.comboboxAccount.SelectedItem as Account;
var accountID = account.Id;
First, I think you shoul use something like a Dictionary or List> or DataTable.
1) You should insert your empty value in your List and then bind it to your combobox
_account.Insert(0, "Empty");
2) Define your ValueMember also(you shoul have a List or a DataTable):
If you have a DataTabele:
comboboxAccount.ValueMember = "columnID";
comboboxAccount.DisplayMember = "columnValue";
comboboxAccount.DataSource = yourDataTable;
combobox.SelectedIndex = 0; //your empty value
3) You should create another property in your class and use this as DisplayMember;
string NumberDescription{ get; set; };
comboboxAccount.DisplayMember = "NumberDescription";
4) If you want to store the ID of the selected value you should use your previously defined ValueMember(the column ID):
int value = Convert.ToInt32(cbomboboxAccount.SelectedValue);
// if you want to save the text of the value selected in the combobox:
string strValue = comboboxAccount.Text;

search for int id starting with x entity framework 4.1

I currently have an Entity Framework model that collects data from a legacy database and I am currently using an int on my Id properties
I am attempting to build a search box with autocomplete capabilities and want to have the autocomplete function to return a subset of records based on whether the sample id either contains or starts with (final design decision not made yet) and I am running into problems with converting the integer id to a string as I would normally use a recs.Id.toString().StartsWith(recordId) but this is apparently not supported by the Entity Framework
Is there a way around this limitation ?
My code looks like the following
Model:
public class Sample
{
public Sample()
{
Tests = new List<Test>();
}
public int Id { get; set; }
public DateTime SampleDate { get; set; }
public string Container { get; set; }
public string Product { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public virtual SamplePoint SamplingPoint { get; set; }
public virtual SampleTemplate SampleTemplate { get; set; }
public Customer ForCustomer { get; set; }
public virtual ICollection<Test> Tests { get; set; }
}
and the query I am currently trying to apply to this model
[HttpGet]
public JsonResult AutoComplete(string partialId)
{
var filteredSamples =
repo.AllSamples.Where( s =>
String.Compare(s.Status, "A", false) == 0
&& (s.Id.ToString()).StartsWith(partialId)
).ToList();
return Json(filteredSamples, JsonRequestBehavior.AllowGet);
}
Any ideas would be awesome I am out of ideas at this point
No matter what you do, this is going to result in some awful performance on large datasets, because you will not be able to use any indices. My recommendation would be to use a trigger or scheduled task to store the leading digit in a separate field and filter on that.
I ended up adding a view for autocomplete data and converting the data to string in the select statement and this solved my issue
Wild thought: how about your create a computed, persisted column on your database table, that converts your ID (INT) into a string?
Then you could:
put an index on that column
use a simple string comparison on that string column
Basically, you need this:
ALTER TABLE dbo.YourTable
ADD IDAsText AS CAST(ID AS VARCHAR(10)) PERSISTED
Now update you EF model - and now you should have a new string field IDAsText in your object class. Try to run your autocomplete comparisons against that string field.

How to Store a list of Design-Time data

I have the following structure in my data:
Category0
-SubCategory0
-SubCategory1
-SubCategoryN
Category1
-SubCategory1_0
-SubCategory1_1
-SubCategory1_N
A category will have a NAME, a Description and a Unique Integer ID
e.g.
Category = Ford Description = "USA Car" Id = 12345678
-SubCategory: Name = Mondeo Description = "Some text" Id = 12324
-SubCategory: Name = Fiesta Description = "Some text" Id = 9999
-SubCategory: Name = Orion Description = "Some text" Id = 123456
-SubCategory: Name = Focus Description = "Some text"Id = 8799
The list is known at design time and I need to bind to the listview. I'd like to bind the Description as the Display Text on each line of the listview and the values(an object or an enum with the Name and Id) as the corresponding valuemember.
What is the best method to store this info? Should I create a large number of enumerations? Or should I bind directly to the listview in designer mode using delimited strings such as "Ford:Mondeo:Some Text: 12324" and then parse and extract as needed. Perhaps it would be better to have the data stored strongly typed enums with custom attributes for the id/description values e.g bind to a dictionary where string is a description and CarType is a class with properties: Make(Ford):enum, Model(Modeo):enum and Id(12324):int?
Typically you would model this with two classes:
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<Model> Models { get; set; }
}
If you are concerned about performance in the comparisons, and you know exactly all the manufacturer and model names, you should consider changing the names into enums.
Also, if you will be accessing these items by name, you should consider keeping them in a dictionary with the name as the key.
This sounds like a perfect use for XML. You can add / remove categories, change the values of the name & description etc. Parse it into a simple class structure...
public class ParentCategory : Category
{
public List<Category> SubCategories { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
And then you simply bind these classes to your view.
Just because it's known at design time is not a good enough reason to go and create tons of duplicated, redundant code. It makes your program so much harder to maintain. Yes, it's simpler to look at for someone uncomfortable with XML (or any data file) but if something changes - you need to add another property to the categories, for example - you'll need to go and change every single class / enum. Messy and tedious.
edit: Just to clarify, when I say XML that's just my preferred format. You can also store your data as text, CSV, whatever your favourite format. I prefer XML as it's easier to work with.
edit2:
I see your concern (if(carListView.SelectedValue == "Mondeo")). Without knowing (or wanting to know) your whole system or what you're trying to do, I'd prefer to work in a more generic, object focused fashion.
So you'll need an if statement for each type of car? Why not just get the car to do its own work?
public class ParentCategory : Category
{
public List<Category> SubCategories { get; set; }
public void DoThings()
{
// look at SubCategories, print something, etc
}
}
// and then get the item to do things!
((ParentCategory)carListView.SelectedValue).DoThings();
This way there's no looping through whole lists. Again, keep your number of lines down.

entity framework when many to many is holding data

I'm using Entity Framework CTP5.
I have a schema like this:
A group contains many textdescriptions.
A textdescriptions has many texts.
A Language has many texts.
So there are 4 tables.
Groups one-to-many DEscriptions many-to-many Texts many-to-one Languages.
So I have a many-to-many relationship where the relation also holds data.
Definitions of Text and TextDescription ( since we can query on the Id for Group and Languages I havent added them here )
public class Text
{
public int TextID { get; set; }
public int TextDescriptionID { get; set; }
public int LanguageID { get; set; }
public string OriginalText { get; set; }
public bool IsValid { get; set; }
public DateTime Added { get; set; }
public DateTime Updated { get; set; }
public Language Language { get; set; }
public TextDescription TextDescription { get; set; }
public static Text GetMissingText(string input)
{
Text text = new Text();
text.OriginalText = "Missing: " + input;
text.IsValid = true;
text.TextDescription = new TextDescription()
{
IsStatic = true,
Name = input,
IsMultiline = false,
};
return text;
}
}
public class TextDescription
{
public int TextDescriptionId { get; set; }
public int TextDescriptionGroupId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseHtml { get; set; }
public bool IsMultiline { get; set; }
public bool IsStatic { get; set; }
public TextDescriptionGroup TextDescriptionGroup { get; set; }
public virtual ICollection<Text> Texts { get; set; }
public static TextDescription GetNewItem(int textDescriptionGroupId)
{
var item = new TextDescription();
item.Name = item.Description = "n/a";
item.UseHtml = item.IsMultiline = item.IsMultiline = false;
item.TextDescriptionGroupId = textDescriptionGroupId;
return item;
}
}
When adding either a new language or a new text is inserted ... the many to many relation is not inserted into the database. (Think it would be a bad idea, so in the end, if thats the only solution, I could be able to that)
So how do I handle this in a smart way when I need to fetch all the text for a specific group from the database, but also get the translation if there are one for that languages.
I can't start fra the translation object, since its possible its not there. If I start to query from the Text entity ... how do I only select one language without getting all languages first.
repo.Find(x =>
x.GroupId == groupId &&
x.Translation.Any(a => a.LanguageID == id.Value)
);
I'm lost here ... any there any smart way ... so I wont have to query the database for all the Texts ... and then a query for each item ... to see if there are a translation? or else just make a new empty one.
In SQL I would do it like this:
SELECT TD.Name, T.OriginalText FROM TextDescriptions TD
LEFT JOIN Texts T ON TD.TextDescriptionId = T.TextDescriptionId
WHERE TextDescriptionGroupId = 41 AND ISNULL(T.LanguageId, 1) = 1
The above SQL will give me the elements even if there is not record now, I get a NULL for these values. I could then handle that it my code and avoid lazy load.
But can I get the same behavior in Entity Framework. I could see there would be some problems maybe for EF4 to do the mapping ... since I'm going from TextDesciptions to Texts ... and TextDesciptions have a List of Texts ... but here ... I only want either 1 or NULL, or just a new Entity that havent been added to the database yet.
Looking forward to some interesting answers.
mvh
For now ... if no other solution is found I will be running the follow SQL script to insert empty records. This way I'm sure the record is there when a user wants to edit it and dont have to ensure its there before saving it. Maybe also avoiding some naste Linq query.
I only have to run this SQL 2 places. When adding a new Language or new a new TextDesciption.
INSERT INTO Texts
SELECT TD.TextDescriptionId, L.LanguageId, '', 0, GETDATE(), GETDATE(), L.TwoLetterISOLanguageName
FROM TextDescriptions TD
INNER JOIN Languages L ON 1 = 1
LEFT JOIN Texts T ON
T.TextDescriptionId = TD.TextDescriptionId AND
T.LanguageId = L.LanguageId
WHERE TextId IS NULL

Categories

Resources