views:

378

answers:

1

Let's say I have an interface representing a domain object:

public interface IFoo
{
    Bar Bar { get; }
}

The Bar type is a family of objects, each of which has a slightly different schema. In the database, this is represented as XML (this is a mobile app, so it is simply nvarchar, not a true XML column).

I have a generated DataSet which contains an FooDataTable and corresponding FooRow objects:

// AcmeDataSet.designer.cs

public partial class FooRow : DataRow
{
    public string BarXml
    {
        // Generated get and set
    }
}

I would like to implement IFoo and cache the deserialized instance of Bar:

// FooRow.cs

public partial class FooRow : IFoo
{
    private Bar _bar;

    Bar IFoo.Bar
    {
        get { return _bar; }
    }
}

How can I, from within the partial class, determine that the value of BarXml has changed?

I realize that FooDataTable contains ColumnChanging and ColumnChanged events, but I don't know how to subscribe to them. There is no analog to Linq to Sql's OnCreated partial method and I don't know of another way to hook into the generated constructor.

+2  A: 

If I understand you correctly, then your FooRow object (the instance) is an instance of some type that derives from Type DataRow... If so, then since DataRow has a property that references the DataTable, just cast your IFoo variable to a DataRow,

Inside of FooRow

  public partial class FooRow
  {    
       private void myColumnChanging Handler(object sender, EventArgs e)
       {
            // Implementation
       }
       private void myColumnChanged Handler(object sender, EventArgs e)
       {
            // Implementation
       }
       public void RegisterEvents()
       {
          ((DataRow)this).Table.ColumnChanging += myColumnChanging; 
          ((DataRow)this).Table.ColumnChanged += myColumnChanged; 
       }
   }

Then, in FooDataTable class, add a new factory method, MyNewFooRow()

public class FooDataTable 
{
    //  -- Other implementation
    public FooRow MyNewFooRow()
    {
        FooRow fr = this.NewFooRow(); // call the original factory
        fr.RegisterEvents();
        return fr;
    }
 }

and use this new factory wherever you were using the old one...

Charles Bretana
As stated in the last paragraph of the question, I am aware of those events and am unsure where to put this code to allow FooRow to declare the handler.
Bryan Watts
Sorry I didn't quite understand yr last para.. What do you mean "hook into generated ctor"? If the class that is generated derives from DataRow, why do you need to ?
Charles Bretana
Can't you put the handler, and the subscription code, in your client code where you are using the instance of FooRow?
Charles Bretana
The constructor is the place to subscribe to those events. The generated class already has a constructor, so I cannot redefine one in my partial class. There is no other hook, such as OnCreated in Linq to Sql, therefore I have no way to run code upon instantiation.
Bryan Watts
FooRow is an implementation of a domain object and is solely responsible for implementing IFoo. Conceptually this approach is sound, but there are technical limitations. Externalizing the handler is a compromise I am not willing to make. (By analogy, Linq to Sql objects have full access to changes.)
Bryan Watts
Why can't you define an ctor overload with a different signature? say with public FooRow(Delegate MyEventHandler) ? Or are you restricted because you're using 3rd party ORM tool that only calls default ctor when it news up entity objects ?
Charles Bretana
As a DataRow, it is created by calling FooDataTable.NewFooRow() (part of the DataSet pattern).
Bryan Watts
By your code (under your control) or by the ORM tool? cause if it's called by your code, this is a factory method, and you could write your own factory that does the same thing and also subscribes to the events... you'd just call the new custom factory instead of the built-in one
Charles Bretana
I call the method, but that is beside the point. The handler does not belong in a factory - it belongs in FooRow. The object should be privy to changes in its *own values*; I cannot encapsulate the behavior because of what appear to be purely technical reasons.
Bryan Watts
Not suggesting you put the handler in the factory. I was suggesting you use the factory to "register" the handler. the handler "belongs" in FooRow?? R U trying to add an event, and a handler, and wire then up to each other, inside a class you have no control over, and cannot change?
Charles Bretana
I can change it, as it is a partial class. I am simply trying to get notification of changes in column values. I am not adding an event, just trying to subscribe to ColumnChanged. The logic "belongs" in FooRow because it is behavior associated with state change - the role of the housing object.
Bryan Watts
Then in FooRow, add the new handlers, and add method in FooRow to register these handlers with the events in the base class. Add a new factory to FooDataTable that calls this method, (and also calls old factory) and switch to new factory ffrom whereever u'r calling old facroty now ??
Charles Bretana
That appears to be what I have to do. I was hoping to keep it self-contained in FooRow. I'm going to leave this question open for a while. Write your suggestion up as a new answer, and if I don't get a better one, I will accept it.
Bryan Watts
Sorry this took me so long to grok what you were after... Wish I could be more help... good luck! –I'll edit this one...
Charles Bretana
No worries, it is a really idiosyncratic thing about the DataSet.
Bryan Watts