I need simple way to persist and edit a set of string pairs in my application. I believe that DataGridView with two culmns can help me with viewing and editing, and I was hoping to use application settings instead of database to store data (maybe a DataSet as setting type). I just can't put all that together. Is there a way?
Here's how I did it. Class MyMap holds value pairs. They must be properties, because DatGridView doesn't work with fields. MyMapCollection holds the collection of MyMaps, as BindingList (allows adding rows in DataGridView). This class is needed to make Visual Studio settings editor happy, couldn't make it work with plain BindingList. So:
public class MyMap {
public String FirstField { get; set; }
public String SecondField { get; set; }
}
public class MyMapCollection : BindingList<MyMap>
{
public MyMapCollection Clone()
{
MyMapCollection result = new MyMapCollection();
foreach (MyMap map in this)
result.Add(new MyMap() {
FirstField = map.FirstField, SecondField = map.SecondField });
return result;
}
}
Function Clone creates a deep copy of the object, so that data is not changed directly on the object in Settings.Default, but when the users says so. In settings editor you would add an item of type MyMapCollection, called say TheValues, and use very simple it in the code:
myDataGridView.DataSource = Settings.Default.TheValues.Clone();
If data should be changed back to settings (when users clicks OK) then change settings accordingly:
Settings.Default.TheValues = (MyMapCollection)myDataGridView.DataSource;
Using a DataTable or DataSet instead of MyMapCollection is also possible, but this solution allows me to use TheValues in the rest of the code, which is even sweeter than DataSet could have been.
If the values that you are trying to edit are plain key value pairs, you can create a class which holds these values as properties and serialize this class object into an XML file. You can deserialize the class and assign the values to the DataGridView.
You could also create a custom configuration and store it separately from App.config / Web.config file. This will be similar to what NHibernate or spring.Net configuration files are stored with a reference to them in the configsections key.
Here is a link how to creat your own custom configuration.
MSDN link
Related
I have a simple set of 20+ classes. They are all serializable to allow use of these objects within a web service. (DataContract/DataMember) Each of them has an ID and a variable number of other properties, depending on the class.
And I have a database which will store just an ID, a Name that identifies the class and an XML string. And this XML is also the same data in serialized form, but without one property: the ID field should not be stored, since it's redundant.
But the ID must still be sent to the client of the web service, making things a bit complex. And although I could just create a copy of each class, where one has the ID as DataMember and the other doesn't, I'm just looking for a much cleaner solution to solve this. One where I would not need to store the ID field as part of the XML within the database.
So, question: what is the simplest solution to make sure the ID becomes part of the data that's sent to the client, but skipped when storing it as XML? (Without the need of hacking in the XML to remove it.)
And although I could just create a copy of each class, where one has
the ID as DataMember and the other doesn't
What about inheritance?
public class MyEntity
{
// some props
}
public class MyEntityWithId : MyEntity
{
public int Id { get; set; }
// some props
}
Here's what I want to do:
Have an application-scoped Settings setting whose value is an array of a custom type
Have the array of the custom type serialized to XML as opposed to a string
Have the serialized value of my setting saved in app.config.
So far this is eluding me.
I have a custom type:
[TypeConverter(typeof(ServiceConfigurationConverter))]
[Serializable]
public class ServiceConfiguration
{
public string Name { get; set; }
public string Url { get; set; }
// more
}
It has a custom TypeConverter that converts it back and forth from a string. I wrote it that way because the examples I found were all for converting to strings, and because I'd be willing to serialize to a string if it meant that my values were being saved to app.config. But as we will see, they aren't.
If I indicate (through editing the Settings.settings file directly) that the type of this setting is MyNamespace.ServiceConfiguration[], I can enter XML manually to represent the array. (I got the XML by writing a test that programmatically built the array and then serialized it using XmlSerializer.) But, while this XML gets set in Settings.designer.cs as the default value for the setting, it doesn't get saved to app.config.
And that's problematic, because I want people to be able to see the property values in XML form in the the app.config, and be able to change them if need be. If it's not written and read from the app.config, it's not run-time configurable.
If I manually create an entry in app.config, under applicationSettings, and enter in my serialized array as the setting's value, the settings designer asks me if I want to update the settings file value, and does so -- but removes the entry I put in under applicationSettings.
I'd be willing to consider writing some kind of designer for my custom type, if necessary, but I don't know what kind of designer that would be.
(I know that if I just changed the property type to "string" I could save the serialized XML as a string and avoid this whole problem. But what I want is a property whose type is my custom type, not one I'd have to reconstitute.)
Can anyone tell me how to achieve the three goals at the top of this post with a custom type?
Many thanks.
So here is the current problem I'm facing:
I have C# Business Object classes that are generated dynamically from XML Schema.
I build forms dynamically to display and capture data bound to my Business Objects.
I store my serialized (xml) objects into the database.
I need to persist the display properties associated to each Property in my Business
Object C# classes (How to accomplish this??)
Lets say I have a Person Business Object:
public class Person
{
public string Name {get;set;}
public PhoneType Phone {get;set;}
}
public class PhoneType
{
public string HomePhone{get;set;}
public string WorkPhone{get;set;}
}
Now let's say I create a new Person:
Person me = new Person();
me.Name = "BOB";
me.Phone = new PhoneType()
me.Phone.HomePhone = "1234";
me.Phone.WorkPhone = "4321";
Now when I build my form I know that Person.Name is a TextBox of Width = 300 and Height = 30
and my PhoneType.HomePhone and PhoneType.WorkPhone are TextBoxes of Width 200 and Height = 30.
What are the best ways to persist those Display Properties in the DataBase and associate them to each of the Properties in my Business Objects? Considering that most of my Business Objects are represented by very deep object graphs... so I'm wondering what the best way is to recursively store and regenerate display properties from Database based on the deep hierarchical nature of my model.
Now a few conditions:
-I don't want to store static forms since my application is very dynamic. XSD -> Code -> Form
-Display properties may be user-specific (e.g. backcolor of certain field), so can't just have generic form templates
-I just need a good mechanism to associate POCO properties to display properties so I can build my forms on the fly and persist changes to the database
I'm currently exploring the possibility of creating a PropertyBag (collection) property in each of my Business Objects and populate them recursively as I navigate the object graph, but haven't gone far yet..
The way that we handle this is to provide unique identifier attributes to each of the classes, then store the UI definition, including required fields, size, label values, etc, in the database.
We actually also attribute each of the properties in the classes in order to separate those that are visually important from those that are "helpers" only.
At run time, we use reflection to retrieve the attributes for the classes and properties that are to be displayed, then fetch the appropriate list of visual modifiers from the database.
I have dynamically created DataGridView control on form, with DataSource specified as:
((DataGridView)createdControl).DataSource = (IList)(p.GetValue(editedClient, null));
where IList is defined as generic collection for following class:
public class CDocumentOperation
{
[DisplayName(#"Time")]
public DateTime TimePosted { get; set; }
[DisplayName(#"User")]
public CUser User { get; set; }
[DisplayName(#"Action")]
public string Action { get; set; }
}
grid is populated successfully with data, but the only problem that all columns
are created as Text fields.What I need is to manually convert column
which binds to User field, to have Buttons or Links (convert column type to DataGridViewButtonColumn).
Can I do this, without modifying grid auto-fill on grid post creation, without manual
column creation of appropriate type and data copying ?
The short answer is that this cannot be done without manually creating the columns (and setting the DataPropertyName property) before binding. There is no attribute you can use to decorate your data source, the DataGridView will simply generate a DataGridViewTextBoxColumn for every data type (except Boolean which it will resolve to a checkbox column). This behaviour is internal and unchangeable.
Your best bet is to disable AutoGenerateColumns on the grid and write your own method that dynamically generates appropriate column types, perhaps based on your own custom attribute, such as (from your example above):
[DisplayName(#"Time"), ColumnType(typeof(DataGridViewButtonColumn))]
public DateTime TimePosted { get; set; }
The attribute class is easy to write (just extend Attribute, add a Type field and an appropriate constructor). In the method that will generate the columns (immediately before binding), you can use reflection to crawl for properties and check for the presence of the custom attribute. (BindingSource.GetItemProperties() is very useful for obtaining information about the properties on objects in a collection.)
This is not the most elegant solution (and it delves into some intermediate-level concepts), but it's the only way to get around this limitation with auto-generated columns in the DataGridView control.
According to Microsoft:
http://msdn.microsoft.com/de-de/library/system.data.linq.mapping.columnattribute.expression.aspx
It's possible to add expression to the Linq-to-SQL Mapping.
But how to configure or add them in Visual Studio in the Designer?
Problem, when I add it manual to thex XYZ.designer.cs it on change it will be lost.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.4927
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
This is generated:
[Column(Name="id", Storage="_id", DbType="Int")]
public System.Nullable<int> id
{
...
But i need something like this
[Column(Name="id", Storage="_id", DbType="Int", Expression="Max(id)")]
public System.Nullable<int> id
{
...
Thanks.
According to this article:
http://msdn.microsoft.com/en-us/library/system.data.linq.mapping.columnattribute.expression.aspx
you should use the ColumnAttribute.Expression Property when you use CreateDatabase to define a column as containing computed values.
So you should check this article:
http://msdn.microsoft.com/en-us/library/Bb399420%28v=VS.100%29.aspx
Another way is to define expression on your sql server so it'll be mapped by the LINQ designer.
Edit: mmmm you edited your question, so probably my answer is not gonna help you so much, but you might be able to do this anyway with your 'extended' question :D
I do this by adding another class file to the project, give them the same name as the object from LinQ-to-SQL you want to extend and define it as partial.
for example, if you have a table called Files, the object File will be created for you by L2S. If you then create a file (with the same namespace as your DataContext object), and make it partial, like this:
public partial class File
{
}
You can just add properties, methods, etc. From within this class, you also have direct access to the properties of the 'other' File class.
It's a little klugy, but in your linq2sql designer, rename the field from 'id' to 'xid' (or anything else) and change its accessibility to internal.
then, in another file, start another partial class, like Wim Haanstra showed, and create a new property called 'id', add all the attributes you want, and in the get & set, just map it to and from the original property, now called 'xid'.
it would look something like this:
public partial class File
{
public int? id
{
get { return xid; }
set { xid = value; }
}
}
this is more commonly done to map fields in the database to a different type in the object, e.g. an int in the DB to an enum in the object, a byte/smallint/etc. in the DB, a boolean in the object. or to add attributes, like [DataMember] to the property.