I have a Car class with various properties.
I have a static Cars collection class in which, for simplicity, I have defined a bunch of car items which I can make available in XAML via an object data provider.
I have a collection view source defined in XAML which binds successfully to my ObjectDataProvider as it should.
I have a listbox which shows the collection.
I added the sort to the CVS as recommended in all the standard tutorials and all works fine.
My Question:
Suppose I want to sort on a different field. Surely there is a way to change this without having to give the code to the customer. So I implemented a combo box.
I use the following code to load a list of properties from the Car class into the combo box but I don’t just get a list of properties. I also get their data types. I don’t want this.
Car xyz=new Car(); //Make a temp Car Object so we can get a list of properties.
//Assign this to the combobox for listing.
cbxSortPrimary.ItemsSource = xyz.GetType().GetProperties();
Result (what displays in the combo box):
System.String Model
Double Price
Int32 NoOfPrevOwners
DataType PropertyName
ect... ect...
ect... ect...
ect... ect...
My goal is to load in the property names to the combo box. Then use the selected property name to build a line of code like:
myListBox.Items.SortDescriptions.Add(new SortDescription(ComboBox.SelectedItem.ToString(), ListSortDirection.Descending));
Where the ComboBox.SelectedItem.ToString() will contain the name of the property to be sorted on.
So how do I get rid of the data type in front of the property name. I know I can do all sorts of messy loading into another list, then a bunch of string handling looking for the first space from the right and chopping everything before that. But surely there must be an easier way.
Effectively what I am looking to do is to let the user sort on a different property of the Car class (So I need to load the properties somewhere and make them available for the user to select, hence the combobox). What I am asking is that there must be an easy way to get the list of properties without all the string manipulation code, and hopefully without much reflection (unless I am already using it without knowing), as it seems like a very basic requirement.
Thanks in advance for any help!
It's not messy at all:
var properties = new List<string>();
foreach (var info in typeof(Car).GetProperties())
{
properties.Add(info.Name);
}
cbxSortPrimary.ItemsSource = properties;
Related
I'm sorry in advance for the mess you're about to read, because I'm not 100% sure what I'm searching for.
I have created an entire UI system that automatically grabs a list of properties from various scripts/components on GameObjects (Unity) and creates a fitting UI input variant for them (for example, float gets a single line, Vector3 gets 3 lines, color gets something else etc.).
What goes into UI input fields creation is a Component (that we want to look into), while individual created UI inputs store this Component and Property Name. So when input changes in one of input fields, it does SetValue on Property of a Component. Now I have also created a variant where we peak into a Class of a property and basically list Property's Properties, so the UI input stores Component, Property Name, and subProperty's Name and modifies properties as such. All this works well.
So, now I hit a brick wall with Lists. I would like to treat individual elements of a list as properties so that I could pass them into my preexisting UI scheme.
tl;dr Does List<> treat it's individual elements as Properties, Fields or does it depend on the situation? How do I get these properties, fields or their respective names from this list in order to use them with my mess of an UI system? 0 work for me means treating individual elements of List as properties.
----------------------------
EDIT----------------------------
Again I am sorry for this mess of a question. It is a mixture of confused theory and description of an existing situation that I am trying to shoehorn into my already existing project (which is a bit too over the place to be easily reduced to an example).
If anyone grasped what I was asking for, the single easiest solution was to create a property which prior to listing was equated to an element of a list.
Example looks something like this:
public List<MyCustomClass> myCustomList;
[Listable("ForEdit")]
public myCustomClass myCustomPropertyForEdit
{
get;
set;
}
And before withdrawing properties of myCustomPropertyForEdit's class (myCustomClass) I would simply do:
myCustomPropertyForEdit = myCustomList[0]; //or whatever index is in question
Then later on I would do reflection on "myCustomPropertyForEdit" instead of myCustomList. I highly doubt this will ever help anyone because it touches more onto how I built methods for listing properties into my UI, but there it is just in case.
List stores references to objects, by providing an index you get a standard object reference, which you can proceed to query using reflection (do not do it against the list itself as you will get methods of the List class, and notthing related to what the list contains)
take for example:
public Class Tree
{
public int branches;
public Tree(int branch)
{
branches=branch;
}
}
List<Tree> trees = new List<Tree>();
trees.Add(new Tree(3));
now my list has one element at index 0;
so i can do trees[0].branches;
to access the fields/props of an element in trees.
list is not an array, it holds the actual item, allowing you to reference, not just the object but also its own unique variables. as long as they are public in the class.
Background
My ASP.NET MVC application allows users to create custom reports and select things like fields to display, order of fields etc. A View should be able to read those custom report configurations and display the model fields accordingly.
Example
1) Let's say we have a model called Person - Id, Name, Age, Address, Height.
2) Let's say the custom report configuration is in a model called CustomReportConfig - Shows only Age, Name and height (in that order).
Now, what should happen in the View is something like (assuming there exists a ViewModel that contains both Person and CustomReportConfig)
foreach(string fieldName in #model.ViewModel.CustomReportConfig)
#model.ViewModel.Person.**fieldName**
As you notice, the fieldName part in the above code is a string variable but in Views this should be statically typed.
Question
Is it possible to use a variable for the fieldName part in #model.Person.fieldName in the above code?
Note: I understand that this can be done by if else conditions for each field or reflection or creating a generic DataTable type of object in ViewModel etc but I'm wondering it there's a better way to do it by just creating the the fieldName in #model.Person.fieldName programmatically.
Perhaps keep a list of fields / property names, and use reflection to grab the property?
Probably a neater way to do it would be to keep a list of objects that each implement some interface, and then just loop over the list.
foreach (IMyCustomInterface obj in #model.ViewModel.CollectionOfCustomReportConfigs)
#obj.ToRenderedString()
I've created two classes in business layer.
the first one is called Users with id (int), pass (string) and privileges (Privilege) properties and the second one is called Privilege and has id (int) and privilegeName (string) properties.
I've a method that returns all the users, and I use a repeater (actually I bind it to a DataList to auto create the ItemTemplate for me and then use a repeater) and it works and displays all the properties well except for my List property. it generates instead something like this System.Collections.Generic.List`1[WebApplication2.Public.BLL.Users]
I want to display it in a friendly way like "User Privileges : Privi1, Privi2" but still I want to keep the layers of my application clean and structured, for example I won't store them in a database in the same table and just store them as a text and append it.
I hope to find a simple and good solution...Thanks in advance guys =)
PS : I don't want to display the object Privilege, I want to display privilege.privilegeName
When using repeaters, there are two approaches, one is the one suggested by Bugai13: to have a custom property that displays it. This is fine for certain types of nested data.
Your other option is to just have a repeater inside a repeater, and bind it appropriately (to what would be a list assigned to your main data object, depending on how you O/R Mapper works).
You can have the code for the custom display property not in the data model, but in your presentation layer somewhere (depending on your framework/design), so it's not a "bad" thing to do that. It's up to you, with whatever "feels" best.
Just create property at your Bussiness object, and bind it:
public string PrivilegiesString
{
get
{
var sb = new StringBuilder("User Privileges : ");
foreach(var item in privileges)
{
sb.AppendFormat("{0}, ",item.privilegeName);
}
return sb.ToString();
}
}
I want to display and edit some objects in a WPF data grid and I'm looking for a good way to do so. All objects I want to display have the same fields, but every execution the fields of my objects can differ. Here is a piece of the interface to illustrate what I mean:
public interface IMyObject
{
IEnumerable<string> GetFieldNames();
IEnumerable<Type> GetFieldTypes();
object GetField(string name);
void SetField(string name, object value);
}
How can I generate a data grid which displays this kind of objects? I thought of XAML generation to define the columns, but I'm still facing the problem of accessing the fields. I think I could realize this with value converters, another option would be to dynamically create a type which exposes the dynamic fields with properties.
Are there any other ways and which should I favor? I'm keen on hearing your opinions.
Best Regards,
Oliver Hanappi
I would do this to my interface
public interface IMyObject
{
IEnumerable<string> GetFieldNames();
IEnumerable<Type> GetFieldTypes();
//i would add this property, then you can bind directly to it.
//basically it is a collection indexer, indexed by string
object this[String name] { get; set; }
object GetField(string name);
void SetField(string name, object value);
}
I would build the columns in code like so, (where stringKeyCollection is a collection of strings returned from GetFieldNames() - although personally i would keep this information separate from my object - like a master definition)
foreach(String item in stringKeyCollection){
//create the base column (use whatever column type you want
DataGridBoundColumn column = new DataGridBoundColumn();
//create the binding for the column
column.Binding = new Binding("[" + item + "]");
//set the header
column.Header = item;
}
then you have objects in each cell of the grid and you can define templates however you wish.
The fact that the type of your bound objects changes each time is not hugely important, if your grid is set to AutoGenerate columns then it will create the columns for you. However this could lead to some rather un-pretty results.
What i would suggest is this:
with your data objects, annotate each displayable property with a custom attribute, this is simply to mark it for later inspection
once you have obtained your collection of items, take the first item in the list and pass it to a factory function that returns grid columns
the grid column factory function can inspect the data object using reflection looking for properties with the special attribute you used earlier, and create the appropriate grid column with the appropriate binding and value converter
add the collection of grid columns to the grid, and bind the data
this approach depends upon all the items in the collection being of the same type, but should be reasonably snappy.
If you have different items in the collection and they have little or no commonality then you could look to the method where you query each item for it's bindable properties and then mash the whole lot together.
I have a custom property descriptor that I use to support flattening object hierarchies.
To accomplish this I subclassed PropertyDescriptor and I store a linked list to the "next" (child) property that I want to retrieve the value for.
This enables me to bind subproperties to a grid(export to excel, whatever) in a "flat" manner.
eg.
Grid(bound Property, Caption)
Col1:Customer.Name(Customer)
Col2:Customer.Address(Address)
Col3:Customer.OutstandingOrders.Count(Outstanding Orders)
The problem is that once I add in a column with a duplicate name, regardless of the fact it's got a unique caption it will retrieve the property for the 1st one but still put the correct header in:
Col4:Customer.Company.Name(Company)
Any ideas?
The problem is that once I add in a column with a duplicate name, regardless of the fact it's got a unique caption it will retrieve the property for the 1st one but still put the correct header in.
Can you clarify that line? I've done this before, but I used the navigation path in the imaginary name - i.e. I might have the PropertyDescriptor.Name report Customer_Company_Name rather than Name, and use the .DisplayName to report something more readable.