My C# WebFormsHelper class

I’ve posted a few code snippets and some people noticed that there are references to unresolved methods.I am using a few helper classes. This post describes my WebFormsHelper class:

using System;

using System.Collections.Generic;

using System.Text;

using System.Diagnostics ;

using System.Web.UI;

using System.Web.UI.WebControls;

 

namespace FSCSharpLib.ASP

{

    //TODO merge with FSHelperLib.WebFormsHelper

    public static class WebFormsHelper

    {

        #region  “Recursively FindControl”

               

        // From http://forums.asp.net/2/880691/ShowThread.aspx

        //useful for debugging TODO: add trace option ,

        //see also DNN FindControlRecursiveDown and FindControlRecursive and  http://geekswithblogs.net/mnf/archive/2006/08/16/88101.aspx

        public static System.Web.UI.Control RecursivelyFindControl(System.Web.UI.ControlCollection oParentControls, string ServerID)

        {

            return RecursivelyFindControl(oParentControls, ID, false);

        }

        public static System.Web.UI.Control RecursivelyFindControl(System.Web.UI.ControlCollection oParentControls, string ID,bool bClientID)

        {

             //oChild;

            if (oParentControls.Count > 0)

            {

                foreach (System.Web.UI.Control oChild in oParentControls)

                {

                   // Debug.WriteLine(“Control: ” + oChild.ID + ” (” + oChild.ClientID + “)”);

                    bool bFound = false;

                    if (bClientID)   { bFound = (oChild.ClientID == ID); }

                    else             { bFound = (oChild.ID == ID); }

                    if (bFound)

                    {

                        string sMsg=“Found Control: “ + oChild.ID ;

                        if(bClientID)  sMsg += ” (“ + oChild.ClientID + “)”;

                        Debug.WriteLine(sMsg);

                        return oChild;

                    }

                    if (oChild.HasControls())

                    {

                        System.Web.UI.Control oChild1 = RecursivelyFindControl(oChild.Controls, ServerID);

                        if (!(oChild1 == null))

                        {

                            // Debug.WriteLine(“Recursive Found Control: ” + oChild1.ID + ” (” + oChild1.ClientID + “)”);

                            return oChild1;

                        }

                    }

                }

            }

            return null;

        }

        public static System.Web.UI.Control RecursivelyFindClientControl(System.Web.UI.ControlCollection oParentControls, string ClientID)

        {

            return RecursivelyFindControl(oParentControls, ID, true);

            // System.Web.UI.Control oChild;

            //if (oParentControls.Count > 0)

            //{

            //    foreach (System.Web.UI.Control oChild in oParentControls)

            //    {

            //        Debug.WriteLine(“Control: ” + oChild.ID + ” (” + oChild.ClientID + “)”);

            //        if (oChild.ClientID == ClientID)

            //        {

            //            Debug.WriteLine(“Found Control: ” + oChild.ID + ” (” + oChild.ClientID + “)”);

            //            return oChild;

            //        }

            //        if (oChild.HasControls())

            //        {

            //            System.Web.UI.Control oChild1 = RecursivelyFindClientControl(oChild.Controls, ClientID);

            //            if (!(oChild1 == null))

            //            {

            //                Debug.WriteLine(“Recursive Found Control: ” + oChild1.ID + ” (” + oChild1.ClientID + “)”);

            //                return oChild1;

            //            }

            //        }

            //    }

            //}

            //return null;

        }//end

        #endregion  //”Recursively FindControl”

 

        //From http://www.eggheadcafe.com/articles/20050609.asp “Which control generated my postback?”

        public static System.Web.UI.Control GetPostBackControl(System.Web.UI.Page page)

        {

            Control control = null;

            string ctrlname = page.Request.Params[“__EVENTTARGET”];

            if (ctrlname != null && ctrlname != String.Empty)

            {

                control = page.FindControl(ctrlname);

            }

            // if __EVENTTARGET is null, the control is a button type and we need to

            // iterate over the form collection to find it

            else

            {

                string ctrlStr = String.Empty;

                Control c = null;

                foreach (string ctl in page.Request.Form)

                {

                    // handle ImageButton controls …

                    if (ctl.EndsWith(“.x”) || ctl.EndsWith(“.y”))

                    {

                        ctrlStr = ctl.Substring(0, ctl.Length – 2);

                        c = page.FindControl(ctrlStr);

                    }

                    else

                    {

                        c = page.FindControl(ctl);

                    }

                    if (c is System.Web.UI.WebControls.Button ||

                             c is System.Web.UI.WebControls.ImageButton)

                    {

                        control = c;

                        break;

                    }

                }

            }

            return control;

        }

        #region  “GridView helpers”

        public static int ColumnIndexBySortExpression(DataControlFieldCollection Columns, string SortExpression)

        {

            for (int i = 0; i < Columns.Count ; i++)

            {

                if (Columns[i].SortExpression == SortExpression)

                {

                    return i;

                }

            }

            return -1;

        }

        public static TableCell CellBySortExpression(GridViewRow Item, string SortExpression)

        {

            GridView gridView =(GridView) Item.NamingContainer;

            int nColumn = ColumnIndexBySortExpression(gridView.Columns, SortExpression);

            if (nColumn < 0)

            {

                return null;

            }

            else

            {

                return Item.Cells[nColumn];

            }

        }

 

        public static DataControlField ColumnBySortExpression(DataControlFieldCollection Columns, string SortExpression)

        {

            DataControlField oRet = null;

            int i = ColumnIndexBySortExpression(Columns, SortExpression);

            if (i >= 0)

            {

                oRet = Columns[i];

            }

            return oRet;

        }

        public static string GetColumnValueBySortExpression(GridViewRow gvRow, string SortExpression)

        {

            TableCell cell = WebFormsHelper.CellBySortExpression(gvRow, SortExpression);

            string sColumnName = cell.Text;

            return sColumnName;

        }

        #endregion  //”GridView helpers”

 

    }//class

}

 

 


Advertisements

Access to BoundField value when GridView row is selected.

I have a GridView with BoundField , and  I want to access it value when  GridView row is selected:

            <asp:GridView ID=”grvCascadeRulesTemplates” runat=”server” AutoGenerateColumns=”False” DataKeyNames=”CascadeRuleKey” DataSourceID=”odsCascadeRulesTemplates”>

                <Columns>

                    <asp:CommandField ShowSelectButton=”True”

                     SelectText=”Show Values”>asp:CommandField>

                    <asp:BoundField DataField=”CascadeRuleKey” HeaderText=”CascadeRuleKey” ReadOnly=”True”

                        SortExpression=”CascadeRuleKey” />

                    <asp:BoundField DataField=”SourceTable” HeaderText=”Source Table” SortExpression=”SourceTable” />

                Columns>

            asp:GridView>

        Protected Sub grvCascadeRulesTemplates_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles grvCascadeRulesTemplates.SelectedIndexChanged

            DebugHelper.PrintChildren(grvCascadeRulesTemplates.SelectedRow)

 

        End Sub

I have valid SelectedRow , but I didn’t find a way to easily get reference to control in the BoundField.

I don’t want to hardcode access the individual cells of the GridViewRow object by using the Cells property with numeric (non-mnemonic) index.. I can not  use the FindControl method , because the control doesn’t have an ID.
The possible solutions that I found (from some places including here) are:

1. Convert column to template and add an ID to be able use FindControl. Quite simple, but adds more markup code that I actually need.

2. Add my data column to  DataKeyNames – should work, but my data field is not part of primary key, so it is confusing.

3. Search GridView.Columns by my ColumnName to find index of the cell. I preferred it.

DataControlFieldCollection doesn’t provide Find method and furtermore the base class DataControlField doesn’t have ID or Name property, so I have to search by FooterText , HeaderText  or SortExpression. Alternatively I can cast DataControlField to BoundField and use DataField.

I choose SortExpression as it is less likely to change and should be the same as DataField.

I’ve included helper functions  CellBySortExpression,ColumnBySortExpression, GetColumnValueBySortExpression into my WebFormsHelper class

 

Some workaround for ObjectDataSource: could not find a non-generic method ‘…’

I tried to use generated by VS 2005 typed dataset/adaptors with  ObjectDataSource and got am error:


Exception Details

: System.InvalidOperationException: ObjectDataSource ‘odsCascadeRulesValues’ could not find a nongeneric method ‘Update’ that has parameters: ….


I found the thread that suggested some workarounds, but the simple one “Change this  OldValuesParameterFormatString=”original_{0}” to  OldValuesParameterFormatString=”{0}” didn’t work for me.

I’ve found that the problem only happened if your Update/Delete methods were generated using “Optimistic Concurrency”. In this case you need to create own Update method with parameters expected/specified in ObjectDataSource/UpdateParameters element.


Alternatively, if you are happy not to check for concurrency, you can re-generate your adaptor methods:
1.Select Adaptor
2.Click Configure
3.Click “Advanced Options…” 
4.Untick  “Use Optimistic Concurrency”.
5.Click “Finish” to generate Updates


Now you should go to your ASPX/ASCX and configure ObjectDataSource . Ensure that correct Update and Delete methods are selected.


There is another thread “Dataset + ObjectDatasource + GridView + ASP.NET 2” that discuss different options for workaround.
Update: I’ve posted related “Editable GridView with ObjectDatasource and Update method parameters.” and “Why we are getting ObjectDataSource: could not find a non-generic method ‘Update'” .


 

Custom TextBoxListener to write messages into windows form Output

About a year ago I played with Enterprise Library Logging application block and created  TextBoxSink based on the provided DebugTraceSink.  It wasn’t fully complete, but now I decided to check can I use it for my current task. 
Because of .Net 2.0 changes  I renamed the class to TextBoxListener, derived it from CustomTraceListener and had to overide TraceData,Write and WriteLine instead of previously overridable SendMessageCore.

It also requred to add in App.config listener in categorySources/listeners and listeners elements.

Now it works with January 2006 version of Enterprise Library, but still not good  enouph for use in general application- at the moment  it requires to set static reference to TextBox. 

 The source code of the  TextBoxListener is the following:

      /// <summary>

            /// Logging sink that writes messages to the Visual Studio      /// <summary>

      /// Logging sink that writes messages to the Visual Studio debugger output.

      /// </summary>

    public class TextBoxListener : CustomTraceListener

      {

            /// <summary>

            /// Property TextBoxToLog (TextBox)

            /// </summary>

            static public TextBox TextBoxToLog

            {

                  get

                  {

                        return st_textBoxToLog;

                  }

                  set

                  {

                        st_textBoxToLog = value;

                  }

            }

            static private TextBox st_textBoxToLog=null;

        //In Sink it was overridable SendMessageCore(LogEntry logEntry)

        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)

        {

            string sToWrite = “”;

            if (data is LogEntry && this.Formatter != null)

            {

 

                sToWrite=(this.Formatter.Format(data as LogEntry));

            }

            else

            {

                sToWrite=(data.ToString());

            }

            //this.WriteLine(sToWrite);

            if (null != TextBoxToLog)

            {

                WriteLine(sToWrite);

                //      System.Diagnostics.Debug.WriteLine(SR.TextBoxSinkMessage(logEntry.EventId,logEntry.Message));

            }

        }

 

            private static void AppendToTextBox(string results)

            {

 

            st_textBoxToLog.Text += results;// +Environment.NewLine;

                  st_textBoxToLog.SelectAll();

                  st_textBoxToLog.ScrollToCaret();

            }

        /// <summary>

        /// Writes a message to the debug window

        /// </summary>

        /// <param name=”message”>The string to write to the debug window</param>

        public override void Write(string message)

        {

            AppendToTextBox(message);

        }

 

        /// <summary>

        /// Writes a message to the debug window

        /// </summary>

        /// <param name=”message”>The string to write to the debug window</param>

        public override void WriteLine(string message)

        {

            AppendToTextBox(message+ Environment.NewLine);

        }

 

      }

 

The sample testing code is the following:

  

        private void btnLogToTextBox_Click(object sender, EventArgs e)

        {

            //MNF 17/8/2005 modified customizedSinkButton_Click

            try

            {

                Cursor.Current = Cursors.WaitCursor;

                TextBoxListener.TextBoxToLog = this.resultsTextBox;

                for (int i = 0; i < 100; i++)

                {

                    LogEntry log = new LogEntry();

                    log.Message = Properties.Resources.DebugSinkTestMessage + ” i= “ + i.ToString();

                    log.Priority = 5;

                    log.EventId = 100;

                    log.Categories.Clear();

                    log.Categories.Add(“Debug”);

                    Logger.Write(log);

                    Logger.Write(“My Message”, “Debug”);

                }

                TextBoxListener.TextBoxToLog = null;

                this.DisplayResults(Properties.Resources.CustomizedSinkEndMessage);

            }

            finally

            {

                Cursor.Current = Cursors.Default;

            }

 

        }

 

The changes in app.config are the following:

<configuration>

      <configSections>

            <section name=loggingConfiguration type=Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging />

      </configSections>

      <loggingConfiguration tracingEnabled=true defaultCategory=General>

    <categorySources>

      <add

                        name=Debug

                        switchValue=All>

        <listeners>

          <add name=Debug Destination />

          <add name=TextBox Destination />

        </listeners>

      </add>

    </categorySources>

            <listeners>

      <add name=TextBox Destination

                        type=LoggingQuickStart.TextBoxListener, LoggingQuickStart

                        listenerDataType=Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging

        formatter=Text Formatter

                        />

    </listeners>

 </loggingConfiguration>
</configuration>

 

 

 


Links to my photo albums

It’s interesting to note,that since I’ve started this blog more than a year ago,it’s my first personal post.
I’ve noticed, that my photo albums  on Webshots are not picked up by the Google Images.

So I will provide links here and (hopefully)  Google indexer will add them.(some comments are in Russian)
http://community.webshots.com/user/mfreidge 

http://community.webshots.com/user/karinag_2/

http://community.webshots.com/user/karinag_1/

http://picasaweb.google.com.au/karina.gurarie/GoldCoastDecember2007

Intermittent execution of custom action for installation of product upgrade.

I’ve recently posted Custom action condition to run for a new or upgraded product., but I found that the custom action doesn’t always call executable.
 I removed any custom action conditions, but it still doesn’t always produced the same result
I had to install ORCA, and found that my Custom Action has source _5C6AF63299974A76AD78EA44FCE751A6 (reference to MSIAssembly table ) and type 1042(Custom Action Type 18 + msidbCustomActionTypeInScript 1024)
The CustomAction guid key has entry in InstallExecuteSequence table with condition $C__5C6AF63299974A76AD78EA44FCE751A6>2  and sequence 5999.
According to Conditional Statement Syntax. $component-action >2 means Action state of the component.is installed locally or run from the source.
It means that sometimes installer doesn’t recognize that a component is installed( I still don’t understand the pattern??). 
Actually according to Custom Action Tutorial  Custom Action runs only when the component is being added(or deleted).

DotNetNuke function FindControlRecursive -not clear name.

DotNetNuke has function FindControlRecursive. Initially I assumed that it search down hierarchy, but it doesn’t work as I expected.
After reading code it seems that it searched siblings or parens siblings up to the top of hierarchy.
So the name is misleading.


Fortunately  there is a separate function FindControlRecursiveDown, that does what I needed.