Search code examples
c#extension-methods

Is there anyway to have the result of extension method stored in the original object?


I have a class UserControl class (says MyDataGrid) which inherits from a 3rd party DataGrid (says TheirDataGrid). In this case, I only create MyDataGrid control, but there is no MyDataGridColumn and MyDataGridCell which inherit from TheirDataGridColumn and TheirDataGridCell

My case is that I create some extension method for the TheirDataGridColumn, which will add some event handler to TheirDataGridColumn (by += operator)

If we call the extension method once only, it is fine But if we call the extension method more than one times, the number of events will add up. (In my case, it is still ok, because it only modifies a primitive property in the event and the last event will take effective finally. But still want to know if there is any better way to do so).

There are several approaches I can think of at the moment:

  1. Clearing all the event handler at TheirDataGridColumn each time I call the extension method. But it seems that we can only do it by reflection to retrieve nonpublic variable (How to remove all event handlers from an event). Also, in the case above, it is a well-known default Win Button Control, but I am using a 3rd party one.

  2. Have my own MyDataGridColumn class, which inherits from TheirDataGridColumn, with an extra variable to store added event handle. So, everytime I call the extension function (indeed, at this case, no extension function is needed as we can add the function directly at MyDataGridColumn class), it can remove the event handler (by -= handler).

  3. Have somewhere to store the added event handler so that it can be removed later. But since I am at the extension method, there is no way for me to save the added event handler because there is no extension property. If I save it in static level of another class, it is in static level but not instance level. Sure, I may have a Dictionary at static level, but need to think of a unique key to identify each column.

For 1, it is quite dirty way to do so. Also, it may remove some other event handlers unintentionally

For 2, it needs quite much refactoring, which I would like to avoid

For 3, personally speaking, I prefer this approach, provided I can find a way to save the added event handler and remove it next time when I call this method again

Any help is highly appreciated.


Solution

  • Updating the code from a previous answer, we could either remove the handler before we add it (because removing won't fail if there are no handlers):

    private void UltraGrid1_InitializeLayout(object sender, InitializeLayoutEventArgs e)
    {
        var column = e.Layout.Bands[YOUR_BAND_INDEX].Columns[YOUR_COLUMN_INDEX];
        column.Style = Infragistics.Win.UltraWinGrid.ColumnStyle.URL;
        var editor = column.Editor as FormattedLinkEditor;
    
        //remove the handler before add, to prevent adding multiple handlers
        editor.LinkClicked -= this.Editor_LinkClicked;
    
        editor.LinkClicked += this.Editor_LinkClicked;
    }
    

    Or we could use one of the controls' Tag properties to remember that we've added a handler for this. Windows forms controls have a Tag property that is an object and is intended for storing general purpose data to be associated with the control. If we store a string in the tag and check for it later, we can avoid to add the handler multiple times. Perhaps like one of these:

    private void UltraGrid1_InitializeLayout(object sender, InitializeLayoutEventArgs e)
    {
        var column = e.Layout.Bands[YOUR_BAND_INDEX].Columns[YOUR_COLUMN_INDEX];
    
        //did we add the handler already?
        if(column.Tag != null && column.Tag.ToString() == "handlerIsAdded")
          return;
    
        column.Style = Infragistics.Win.UltraWinGrid.ColumnStyle.URL;
    
        var editor = column.Editor as FormattedLinkEditor;
        editor.LinkClicked += this.Editor_LinkClicked;
    
        column.Tag = "handlerIsAdded"; //remember for next time, so we don't add handler again
    }
    

    I don't know if it's at the column level or the editor level you want to add this; I've never worked with the grid control you're using. If there is only one editor control for the column and it doesn't get renewed then you could also use the editor control:

    private void UltraGrid1_InitializeLayout(object sender, InitializeLayoutEventArgs e)
    {
        var column = e.Layout.Bands[YOUR_BAND_INDEX].Columns[YOUR_COLUMN_INDEX];
        column.Style = Infragistics.Win.UltraWinGrid.ColumnStyle.URL;
        var editor = column.Editor as FormattedLinkEditor;
    
        //did we add the handler already?
        if(editor.Tag != null && editor.Tag.ToString() == "handlerIsAdded")
          return;
    
        editor.LinkClicked += this.Editor_LinkClicked;
    
        editor.Tag = "handlerIsAdded"; //remember for next time
    }