Jan 18
2010

WatiN - developed in C# - brings to you an easy way to automate your tests with Internet Explorer and FireFox using .Net.
Often WatiN is used to click through the UI of your web application.
In this case it is important to use a sure method to find controls in a page.

A really simple way to find a control for example is:

ie.Link(Find.ById("ctl03_lnkbtnConfirmStartingProcess")).Click();

or

var link = ie.Link("ctl03_repCustomers_ctl00_repProducts_ctl00_lnkSlideDownStatistics");

 

Below there are two examples how to find controls in a page using regular expression. In my opinion this is more comfortable to use.

Example 1 - Find a dropdownlist in a testpage and check dropdown values:

//some other code...
ie.GoTo(
string.Format("{0}{1}", baseURL, "testpage.html"
));
var
selectStatusNames = new[] { "all", "online", "offline", "scheduled" };
var statusOpts = ie.SelectList(FindWithRegEx("ddlState")).Options;
for (var i = 0; i < selectStatusNames.Length; i++)
{
    if (String.Equals(statusOpts[i].InnerHtml, selectStatusNames[i])) continue;
    var msg = "Search in articles: selectbox 'Status': option #" + i + " must be " + selectStatusNames[i];
    trace(msg);
    Assert.Fail(msg);
}

 

Example 2 - Find a hyperlink in a testpage and click it:

//some other code...
ie.GoTo(string.Format("{0}{1}", baseURL, "testpage.html"));
var lnkSubmit = ie.Link(FindWithRegEx("lnkbtnSubmitPage"));
Assert.IsTrue(lnkChangePassword.Exists, "cannot find linkbutton to submit page");
lnkChangePassword.Click();

 

helpmethods:

/// <summary>helpmethod to find a control in a page using regular expressions</summary>
/// <param name="idCtrl">part of control ID as string</param>
/// <returns>control ID as string</returns>
public static Regex FindWithRegEx(string idCtrl)
{
    return new Regex(".*" + idCtrl + "$");
}

/// <summary>helpmethod to trace and debug output to console</summary>
/// <param name="msg">debug message
</param>
/// </summary>
/// <param name="msg">message as string</param>
public
static void trace(String msg)
{
    Console.WriteLine(msg);
}

Tags: Tags:
Apr 14
2009

Im allgemeinen verursacht ein ASP.NET LinkButton einen PostBack. Vereinzelt ist es jedoch notwendig, trotz einer Aktion auf dem Button den PostBack zu unterdrücken.  Mit einem simplen "return false;" im clientseitigen Eventhandler läßt sich das PostBack unterdrücken:

<script language="javascript" type="text/javascript">
    function alertMessage()
    {
        alert('Ich bin ein LinkButton, der keinen Postback verursacht!');
        return false;
    }
</script>

<asp:Button
    ID="btnTestAlert"
    runat="server"
    Text="abschicken"
    ToolTip="Ich bin ein ToolTip zum Button btnTestAlert"
    OnClientClick="return alertMessage();" />

 

Tags:
Feb 10
2009

Um per JavaScript in ASP.NET auf eine Checkbox zuzugreifen und deren Checked-Status abzurufen, kann man sich unterschiedlicher Syntax bedienen. Es ist jedoch zu beachten, dass Browser wie der IE oder der FF unterschiedlich reagieren können. Im schlechtesten Fall ignoriert der Browser den Code komplett, wenn es darum geht, über die ClientID auf das Control zuzugreifen.

Mir ist das im u.g. Codeschnippsel zum Thema Custom Validation einer CheckBox passiert. Mit "document.all" hat sich zwar der IE zufrieden gegeben, im FF hingegen hat die entsprechende Codezeile nicht funktioniert. Anders mit "$get". Diese Syntax verstehen beide Browser.

 <asp:CheckBox 
     ID="cbxTermsLoggedIn" 
     runat="server" 
     ValidationGroup="grpvalB2BLoggedInRegistration" /> 

<script language="javascript" type="text/javascript"> 
    function ClientValidationCbxTermsLoggedIn(source, args) 
    { 
        //use:
        var cbx = $get('<%=cbxTermsLoggedIn.ClientID %>');
        args.IsValid = cbx.checked;

        //instead of:
        //args.IsValid = document.all["<%=cbxTermsLoggedIn.ClientID %>"].checked; 
    } 
 </script>

<asp:CustomValidator 
    ID="cstmvalB2BRegistrationTermsLoggedIn" 
    runat="server" 
    SetFocusOnError="true" 
    Display="Dynamic" 
    ErrorMessage="Sie müssen der Speicherung zustimmen"
    ClientValidationFunction="ClientValidationCbxTermsLoggedIn" 
    ValidationGroup="grpvalB2BLoggedInRegistration"
    ValidateEmptyText="True" />

Tags:
Jan 28
2009

Um eine ASP.NET DropDownList mit Werten aus einem Enum zu füllen, gibt es unterschiedliche Ansätze.

Beispielsweise kann das Enum für einen LoginStatus folgendermaßen aussehen:

/// <summary>
/// enum for login status
/// </summary>
public
enum LoginState
{
  Inactive = -1,
  Active = 1,
  Deactivated = 2
}

Um das DropDown mit den Werten des Enum zu füllen, sind zwei Zeilen Code ausreichend:

/// <summary>
/// fills ddlContactPersonLoginState
/// </summary>
private void FillContactPersonLoginStateDropDown()
{
  ddlContactPersonLoginState.DataSource =
Enum.GetNames(typeof(LoginState));
  ddlContactPersonLoginState.DataBind();
}

Allerdings hat diese Lösung zur Folge, dass value und key im DropDown gleich sind.

 

Ein anderer Ansatz über eine Hilfsmethode erlaubt es, value und key separat zu ermitteln
und dem DropDown als DataValueField und DataTextField zuzuweisen:

/// <summary>
/// helpermethod to store enum values and their corresponding names in a SortedList
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static SortedList<string, int> GetEnumDataSource<T>() where T : struct
{
 
Type myEnumType = typeof(T);
 
if (myEnumType.BaseType != typeof(Enum))
  {
   
throw new ArgumentException("Type T must inherit from System.Enum");
  }

  SortedList<string, int> returnCollection = new SortedList<string, int>();
 
string[] enumNames = Enum.GetNames(myEnumType);

  for (int i = 0; i < enumNames.Length; i++)
  {
    returnCollection.Add(enumNames[i], (
int)Enum.Parse(myEnumType, enumNames[i]));
  }
  return returnCollection;

}

Das Füllen des DropDowns muss jetzt etwas erweitert werden:

/// <summary>
/// fills ddlContactPersonLoginState
/// </summary>
private
void FillContactPersonLoginStateDropDown()
{
 
ddlContactPersonLoginState.DataSource = GetEnumDataSource<LoginState>();
 
ddlContactPersonLoginState.DataValueField = "Value";
  ddlContactPersonLoginState.DataTextField ="Key";
  ddlContactPersonLoginState.DataBind();
}

Jetzt stehen im DropDown Value und Key für die weitere Verarbeitung zur Verfügung.

Tags:
Jan 14
2009

Das GridView Servercontrol von ASP.NET 2.0 bietet eine Vielzahl von Möglichkeiten, Spalten mit Informationen zu versehen. Gelegentlich ist es notwendig, eine Spalte mit einer Checkbox zu versehen, um Zeilen einzeln wählen zu können. Das ist schnell implementiert. Allerdings wird es etwas tricky, wenn nur jeweils eine Checkbox aktiviert sein darf, also vergleichbar mit einer Reihe von RadioButtons.
Mit etwas JavaScript ist dieser UseCase jedoch auch problemlos umsetzbar.

So könnte die Spalte im GridView aussehen, in dem es beispielweise nur einen Hauptansprechpartner geben darf:

Hier die CheckBox Deklaration im GridView: 

<asp:TemplateField HeaderText="Haupt AP">
  <ItemTemplate>
    <asp:CheckBox
      ID="cbxIsMainUser"
      runat="server"
      CssClass="cbxCheckbox" /> 
  </ItemTemplate>
</asp:TemplateField>

Hier das JavaScript im aspx-Code:

<script type="text/javascript" language="javascript">
  function uncheckOthers(id)
  {
    var elm = document.getElementsByTagName('input'); for(var i = 0; i < elm.length; i++)
    {
      if(elm.item(i).id.substring(id.id.lastIndexOf('_')) == id.id.substring(id.id.lastIndexOf('_'))) 
      {
        if( elm.item(i).type == "checkbox" && elm.item(i)!=id)elm.item(i).checked =
false;
      }
    }
  }
</script>

RowDataBound des GridView im Codebehind:

//allow only one checkbox in column to be checked using javascript:
CheckBox cbxIsMainUser = (CheckBox)e.Row.FindControl("cbxIsMainUser");
string strScript = "uncheckOthers(" + cbxIsMainUser.ClientID + ");";
cbxIsMainUser.Attributes.Add("onclick", strScript);

Tags:
Oct 16
2008

Obwohl mit ASP.NET 3.5 das neue ListView Control und das neue DataPager Control zur Verfügung stehen, ist in vielen bestehenden Webseiten das GridView Control aus ASP.NET 2.0 in Anwendung. Eigentlich ein sehr leistungsfähiges Control, welches von Haus aus schon Unterstützung für Paging und Sorting bietet. Will oder muss man allerdings ein eigenes Paging implementieren, dann sind doch einige Zeilen Code selbst zu schreiben und einige Dinge zu beachten. Zum Thema "Custom Paging" im GridView habe ich im Netz einen interessanten Artikel im Blog von Francisco Santos Jr. gefunden, der allerdings im Detail schwer nachzuvollziehen ist, da einige wichtige Codepassagen fehlen.

Nachfolgend meine Lösung, die auf dem o.g. Blogeintrag basiert, jedoch versucht, dessen Schwachstellen weitestgehend zu beseitigen. Das Paging kann optisch etwa so aussehen:

 

aspx-Code (PagerTemplate für das GridView):

            <PagerTemplate>
                <asp:ImageButton
                    ID="btnFirst" runat="server" ToolTip="zur ersten Seite" ImageUrl="~/img/first.gif" CommandArgument="First" OnCommand="TurnThePage" />
                <asp:ImageButton
                    ID="btnPrevious" runat="server" ToolTip="zur vorherigen Seite" ImageUrl="~/img/previous.gif" CommandArgument="Prev" OnCommand="TurnThePage" />
                    Seite
                <asp:DropDownList
                    ID="ddlPages" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ddlPages_SelectedIndexChanged" />  von
                <asp:Label ID="lblPageCount" runat="server" />

                <asp:ImageButton
                    ID="btnNext" runat="server" ToolTip="zur nächsten Seite" ImageUrl="~/img/next.gif" CommandArgument="Next" OnCommand="TurnThePage" />
                <asp:ImageButton
                    ID="btnLast" runat="server" ToolTip="zur letzten Seite" ImageUrl="~/img/last.gif" CommandArgument="Last" OnCommand="TurnThePage" />
        </PagerTemplate>

  cs-Code:

         /// <summary>
        /// when page is changed by dropdown
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ddlPages_SelectedIndexChanged(object sender, EventArgs e)
        {
            GridViewRow gvrPager = grdvwCompanies.BottomPagerRow;
            DropDownList ddlPages =(DropDownList)gvrPager.Cells[0].FindControl("ddlPages");

            grdvwCompanies.PageIndex = ddlPages.SelectedIndex;

            // populate gridView
            DoCompanySearch(searchTerm);
        }

        /// <summary>
        /// when page is changed by clicking pager arrows
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void grdvwCompanies_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {
            GridViewRow gvrPager = grdvwCompanies.BottomPagerRow;
            DropDownList ddlPages =(DropDownList)gvrPager.Cells[0].FindControl("ddlPages");
            grdvwCompanies.PageIndex = ddlPages.SelectedIndex;

            // populate gridView
            DoCompanySearch(searchTerm);
        }

        /// <summary>
        /// method for OnCommand in imagebutton
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void TurnThePage(object sender, CommandEventArgs e)
        {
            // get the current page selected
            int intCurIndex = grdvwCompanies.PageIndex;

            switch (e.CommandArgument.ToString().ToLower())
            {
                case "first":
                    grdvwCompanies.PageIndex = 0;
                    break;
                case "prev":
                    grdvwCompanies.PageIndex = intCurIndex - 1;
                    break;
                case "next":
                    grdvwCompanies.PageIndex = intCurIndex + 1;
                    break;
                case "last":
                    grdvwCompanies.PageIndex = grdvwCompanies.PageCount;
                    break;
            }

            // populate gridView
            DoCompanySearch(searchTerm);
        }

        /// <summary>
        /// event when data are bound to gridview
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void grdvwCompanies_DataBound(object sender, EventArgs e)
        {
            GridViewRow gvrPager = grdvwCompanies.BottomPagerRow;
           
            if (gvrPager == null) return;
            gvrPager.Visible = true;
            // get controls from the gridview
            DropDownList ddlPages = (DropDownList)gvrPager.Cells[0].FindControl("ddlPages");
            Label lblPageCount = (Label)gvrPager.Cells[0].FindControl("lblPageCount");

            if (ddlPages != null)
            {
                // populate pager
                for (int i = 0; i < grdvwCompanies.PageCount; i++)
                {
                    int intPageNumber = i + 1;
                    ListItem lstItem = new ListItem(intPageNumber.ToString());

                    if (i == grdvwCompanies.PageIndex)
                        lstItem.Selected = true;

                    ddlPages.Items.Add(lstItem);
                }
            }

            // populate page count
            if (lblPageCount != null)
                lblPageCount.Text = grdvwCompanies.PageCount.ToString();

            //– For First and Previous ImageButton
            if (grdvwCompanies.PageIndex == 0)
            {
                ((ImageButton)grdvwCompanies.BottomPagerRow.FindControl("btnFirst")).Enabled = false;
                ((ImageButton)grdvwCompanies.BottomPagerRow.FindControl("btnPrevious")).Enabled = false;
            }

            //– For Last and Next ImageButton
            if (grdvwCompanies.PageIndex+1 == grdvwCompanies.PageCount)
            {
                ((ImageButton)grdvwCompanies.BottomPagerRow.FindControl("btnLast")).Enabled = false;
                ((ImageButton)grdvwCompanies.BottomPagerRow.FindControl("btnNext")).Enabled = false;
            }
        }

Tags: Tags: |