dotnet windows forms databinding:
I've got a problem that I've been wracking my brain to try to come up with a solution for. Basically, I've got either some XML or an object deserialized from that XML which has elements that have more than one occurrence. So, for instance, a fragment of the XML might look like this: <Sender> <Name>Test Sender</Name> <Address>Address Line 1</Address> <Address>Address Line 2</Address> <Address>Address Line 3</Address> </Sender> This would get serialized into an object that looked something like this: public class Sender { private string name; private string[] address; public string Name { get { return name; } set { name = value; } } public string[] Address { get { return address; } set { address = value; } } } My problem is that I want to databind to either a DataSet that the XML has been loaded into, or to the object that was deserialized from it. Binding to the Name property is no problem. The Address represents a problem, though. The form I want to bind data on has 3 textboxes for address lines, and I'd like to bind each textbox to one of the address string in Address. The first problem, of course, is that there may or may not be 3 entries in Address but I'm willing to stipulate that the XML schema will have minOccurs=3. Which comes to the real problem. Is there anyway to databind to a specific element within a collection? It doesn't matter whether it's in a DataSet or an object. But I haven't found any way to do it yet. Unfortunately, this is very common pattern in the data model of the application I'm trying to reengineer, so I'm not going to have a lot of control over changing it. Currently, the application implements methods on each form to load and save the fields from and to an object, so each form has at least one LoadFieldsFromXxx and SaveFieldsToXxx method, which is a terribly unsatisfying way to implement them. Any help or suggestions would be greatly appreciated. Thanks, Doug Harber
Do you control the class? How about a simple shim through properties - i.e. [XmlIgnore] public string AddressLine1 { get {return Address[0];} set {Address[0]=value;}} [XmlIgnore] public string AddressLine2 { get {return Address[1];} set {Address[1]=value;}} you can now databind to these, safe in the knowledge that they don't affect serialization. (you'd need error handling on the index etc) Also - I don't recomment coding against an array - a Collection<Address> or similar would be far more controlled: private readonly Collection<Address> addresses = new Collection<Address>(); [ some combination of XmlArray etc to get the naming right ] public Collection<Address> AddressLines {get {return addresses;}} (note then that your setter (for instance) could .Add if necessary) I'll see if I can find the xml-markers for serialization of the above (xsd.exe will be my first tool...) Marc
like so (and I meant "string", not "Address"); note that I haven't implemented notifications against AddressLine1 etc; this could be done, but you'd need to work with a subclass of Collection<string>, or switch to BindingList<string> (which also works), and handle the insert/etc. Marc using System; using System.Collections.ObjectModel; using System.Xml.Serialization; using System.ComponentModel; using System.Collections.Generic; class Program { static void Main(string[] args) { Sender s = new Sender(); s.Name = "Test Name"; s.AddressLine3 = "Test 3"; s.AddressLine1 = "Test 1"; XmlSerializer ser = new XmlSerializer(typeof(Sender)); ser.Serialize(Console.Out, s); } } [Serializable] public sealed class Sender : INotifyPropertyChanged { [XmlIgnore] public string AddressLine1 { get { return GetAddressLine(0); } set { SetAddressLine(0,value); } } [XmlIgnore] public string AddressLine2 { get { return GetAddressLine(1); } set { SetAddressLine(1,value); } } [XmlIgnore] public string AddressLine3 { get { return GetAddressLine(2); } set { SetAddressLine(2,value); } } public string GetAddressLine(int index) { return AddressLines.Count > index ? AddressLines[index] : ""; } public void SetAddressLine(int index, string value) { while (AddressLines.Count <= index) { AddressLines.Add(""); } AddressLines[index] = value; } string name; public string Name { get { return name; } set {SetField(ref name, value, "Name");}} readonly Collection<string> addressLines = new Collection<string>(); [XmlElement("Address")] public Collection<string> AddressLines {get {return addressLines;}} public event PropertyChangedEventHandler PropertyChanged; private void SetField<T>(ref T field, T value, string propertyName) { if(EqualityComparer<T>.Default.Equals(field,value)) return; // no change field = value; PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }
[quoted text, click to view] On 2007-08-09, Douglas Harber <--remove-this--dh-nospam@pobox.com> wrote: > Which comes to the real problem. Is there anyway to databind to a specific > element within a collection? It doesn't matter whether it's in a DataSet or > an object. But I haven't found any way to do it yet. Unfortunately, this is > very common pattern in the data model of the application I'm trying to > reengineer, so I'm not going to have a lot of control over changing it.
Instead of manually creating 'shim' properties, you could also implement ICustomTypeDescriptor and expose each element via the GetProperties implementation. -- Kind regards,
Don't see what you're looking for? Try a search.
|