views:

349

answers:

1

My application contains several forms which consist of a strongly typed datagridview, a strongly typed bindingsource, and a strongly typed table adapter.

I am using some code in each form to update the database whenever the user leaves the current row, shifts focus away from the datagrid or the form, or closes the form.

This code is the same in each case, so I want to make a subclass of form, from which all of these forms can inherit.

But the strongly typed data objects all inherit from component, which doesn't expose the events I want to bind to or the methods I want to invoke.

The only way I can see of gaining access to the events is to use: Type(string Name).GetEvent(string EventName).AddEventHandler(object Target,Delegate Handler)

Similarly, I want to call the Update method of the strongly typed table adapter, and am using Type(string Name).GetMethod(String name, Type[] params).Invoke(object target, object[] params).

It works ok, but it seems very heavy handed. Is there a better way?

Here is my code for the main class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using System.ComponentModel;

namespace MyApplication
{
    public class AutoSaveDataGridForm: Form
    {
        private DataRow PreviousRow;

        public Component Adapter
        {
            private get;
            set;
        }


        private Component dataGridView;
        public Component DataGridView
        {
            private get
            {
                return dataGridView;
            }
            set
            {
                dataGridView = value;
                Type t = dataGridView.GetType();
                t.GetEvent("Leave").AddEventHandler(dataGridView, new EventHandler(DataGridView_Leave));

            }
        }
        private Component bindingSource;
        public Component BindingSource
        {
            private get
            {
                return bindingSource;
            }
            set
            {
                bindingSource = value;
                Type t = bindingSource.GetType();
                t.GetEvent("PositionChanged").AddEventHandler(bindingSource, new EventHandler(BindingSource_PositionChanged));


            }
        }



        protected void Save()
        {
            if (PreviousRow != null && PreviousRow.RowState != DataRowState.Unchanged)
            {
                Type t = Adapter.GetType();
                t.GetMethod("Update", new Type[] { typeof(DataRow[]) }).Invoke(Adapter, new object[] { new DataRow[] { PreviousRow } });

            }

        }


        private void BindingSource_PositionChanged(object sender, EventArgs e)
        {
            BindingSource bindingSource = sender as BindingSource;
            DataRowView CurrentRowView = bindingSource.Current as DataRowView;
            DataRow CurrentRow = CurrentRowView.Row;
            if (PreviousRow != null && PreviousRow != CurrentRow)
            {
                Save();
            }
            PreviousRow = CurrentRow;

        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // AutoSaveDataGridForm
            // 
            this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.AutoSaveDataGridForm_FormClosed);
            this.Leave += new System.EventHandler(this.AutoSaveDataGridForm_Leave);
            this.ResumeLayout(false);

        }

        private void DataGridView_Leave(object sender, EventArgs e)
        {
            Save();
        }

        private void AutoSaveDataGridForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            Save();
        }

        private void AutoSaveDataGridForm_Leave(object sender, EventArgs e)
        {
            Save();
        }


    }
}

And here is a (partial) form which implements it:

    public partial class FileTypesInherited :AutoSaveDataGridForm
{
    public FileTypesInherited()
    {
        InitializeComponent();
    }

    private void FileTypesInherited_Load(object sender, EventArgs e)
    {
        // TODO: This line of code loads data into the 'sharedFoldersInformationV2DataSet.tblFileTypes' table. You can move, or remove it, as needed.
        this.tblFileTypesTableAdapter.Fill(this.sharedFoldersInformationV2DataSet.tblFileTypes);
        this.BindingSource = tblFileTypesBindingSource;
        this.Adapter = tblFileTypesTableAdapter;
        this.DataGridView = tblFileTypesDataGridView;

    }

}
A: 

This demontrastes how you can use an "MustInherit" base class for your typed datasets for the purpose of accessing unexposed properties.

Set this as the "BaseClass" for each of your typed TableAdapters, replacing "System.ComponentModel.Component". By using "MustInherit/MustOverride" ("Abstract" in C#) you can get to the properties you can't otherwise reach.

Public MustInherit Class SuperTableAdapter
    Inherits System.ComponentModel.Component

    Public MustOverride ReadOnly Property MyCommandCollection As Data.SqlClient.SqlCommand()

    Public Sub New()
        MyBase.New()
        'With the command collection exposed, you can replace it with your own.  You can do the same for events.'

        For i = 0 To MyCommandCollection.Length - 1
             Dim myspecialCommand As New Data.SqlClient.SqlCommand()
            MyCommandCollection(i) = myspecialCommand
        Next
    End Sub
End Class

For each of your table adapters that you set to inherit your BaseClass you must override the required "MustOverride" property. Without it, it won't compile. If you add the code but do not set the TableAdapter base class, it will not compile either. That is good thing; it ensures you do it right.

Namespace DataSet1TableAdapters
    Partial Public Class Table1TableAdapter
        Public Overrides ReadOnly Property MyCommandCollection As System.Data.SqlClient.SqlCommand()
            Get
                Return Me.CommandCollection
            End Get
        End Property
    End Class

    Partial Public Class Table2TableAdapter
        Public Overrides ReadOnly Property MyCommandCollection As System.Data.SqlClient.SqlCommand()
            Get
                Return Me.CommandCollection
            End Get
        End Property
    End Class
End Namespace

Now you can put all sorts of special code in your SuperTableAdapter. If you need access to something that wasn't exposed, just use "MustOverride" to guarantee that it is available.

Carter