Monday, October 22, 2012

Multi Select Listbox "Select All" should select all items in the Listbox.



We got a requirement from our client that, when user clicks on the “All” option from a Silverlight list box, and then all Items from that Listbox should be selected.

Here below are the three scenarios.

·         User Clicks on “All” option to select All Items, then all items in the list to be selected.
·         User can select all items individually using Ctl key, then the option “All” also to be selected, even the user not selects it.

·         If any of the Items got unselected, then “All” option also to be unselected.

Here we are trying to write the logic in List Box Selection Changed event, there is a possibility that we may end in infinite loop, if we are trying to implement it without taking care. As selection and de selection will raise Selection Changed event, we should do something to avoid it.

Even if Selection Changed event logic is having some code to be executed, when user really changes selection, that code will be executed unnecessarily because of our newly added code. So it will create latency and performance will be down.

After some research, I have come up with below solution.

        void LstGeographics_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListBox lstBox = sender as ListBox;
            if (lstBox.Tag != null && (bool)lstBox.Tag == false)
            {
                lstBox.Tag = true;
                return;
            }
            SetRegionListBoxSelection((ListBox)sender, e);
      
              DoSomething();
        }


In the above event handler, we are checking for ListBox’s tag property, which we are setting to false, when our code itself changing the selection, without user interaction.
So if it is false, then we can avoid unnecessary execution of the method “Dosomething”


   public void SetRegionListBoxSelection(ListBox lstBox, SelectionChangedEventArgs e)
        {
            try
            {
                if (e.AddedItems.Count == 0 && e.RemovedItems.Count == 0)
                    return;
                if (lstBox.SelectedItems.Count == lstBox.Items.Count - 1)
                {
                    if (!e.AddedItems.Cast<ClassName>().Contains(lstBox.Items.Cast<ClassName>().First()))
                        if (!e.RemovedItems.Cast<ClassName>().Contains(lstBox.Items.Cast<ClassName>().First()))
                        {
                            lstBox.Tag = false;
                            lstBox.SelectAll();
                            return;
                        }
                        else
                        {
                            lstBox.Tag = false;
                            lstBox.SelectedItems.Clear();
                        }
                }

                if (e.AddedItems.Cast<ClassName>().Contains(lstBox.Items.Cast<ClassName>().First()))
                {
                    lstBox.Tag = false;
                    lstBox.SelectAll();
                    return;
                }

                if (lstBox.SelectedItems.Count <= lstBox.Items.Count - 1)
                {
                    lstBox.Tag = false;
                    lstBox.SelectedItems.Remove(lstBox.Items.Cast<ClassName>().First());
                   
                }

            }
            catch (Exception ex)
            {
            }
            lstBox.Tag = true;
        }


Friday, October 12, 2012

Asp.Net Online Test with Timer

We got a requirement that, we need to implement logic for a timer which continues to run between page post backs. For each question the page sends a postback request to the server.

So to implement this logic, I used java script Timer with some custom functionality to maintain the clock time between the server round trips. Below is the code.

<div id="timer" style="height:30px; float:right; padding:3px" >
Time:<asp:Label ID="lblTimer" runat="server" ></asp:Label>
<asp:TextBox style="display:none" ID="tbTimer" runat="server"></asp:TextBox>
<asp:Button ID="hdnBtnTimeOut" OnClick="ExamTimeOut" runat="server" style="display:none" />
</div>

<script type="text/javascript" language="javascript">
var Timer;
var TotalSeconds;


function CreateTimer(TimerID, Time) {
        Timer = document.getElementById(TimerID);
        TotalSeconds = Time;
       
        UpdateTimer()
        window.setTimeout("Tick()", 1000);
}


function Tick() {
        if (TotalSeconds <= 0) {
            alert("Time's up!")
            document.getElementById('<%=hdnBtnTimeOut.ClientID %>').click();
                return;
        }

        TotalSeconds -= 1;
        UpdateTimer();
        window.setTimeout("Tick()", 1000);
}

function UpdateTimer() {
        var Seconds = TotalSeconds;
       
        var Days = Math.floor(Seconds / 86400);
        Seconds -= Days * 86400;

        var Hours = Math.floor(Seconds / 3600);
        Seconds -= Hours * (3600);

        var Minutes = Math.floor(Seconds / 60);
        Seconds -= Minutes * (60);


        var TimeStr = ((Days > 0) ? Days + " days " : "") + LeadingZero(Hours) + ":" + LeadingZero(Minutes) + ":" + LeadingZero(Seconds)


        Timer.innerHTML = TimeStr;
        document.getElementById('<%=tbTimer.ClientID %>').value = TimeStr;
}


function LeadingZero(Time) {

        return (Time < 10) ? "0" + Time : + Time;

}

</script>

C#
        private void SetTimer()
        {
            string time = tbTimer.Text;
            int totalSeconds = 0;
            if (!string.IsNullOrEmpty(time))
            {
                string[] timeParts = time.Split(':');
                string hours = timeParts[0];
                string minutes = timeParts[1];
                string secons = timeParts[2];

                int hoursCnt, minutesCnt, seconsCnt;

                Int32.TryParse(hours, out hoursCnt);
                Int32.TryParse(minutes, out minutesCnt);
                Int32.TryParse(secons, out seconsCnt);

                totalSeconds = hoursCnt * 60 * 60 + minutesCnt * 60 + seconsCnt;

                if (totalSeconds == 0)
                {
                    //Time up, Write you logic here,like exam report.
                    return;
                }
            }
            ScriptManager.RegisterStartupScript(this, this.GetType(), "startTimer", "CreateTimer('" + lblTimer.ClientID + "'," + totalSeconds + ");", true);
        }

//User clicks on this button ,to start the test.
protected void btnproceed_Click(object sender, EventArgs e)
        {
//Write ur logic , below EXAM_TIME is a constant variable.
            ScriptManager.RegisterStartupScript(this, this.GetType(), "startTimer", "CreateTimer('" + lblTimer.ClientID + "'," + EXAM_TIME + ");", true);
}

//User clicks on the “Next” button.

protected void btnnext_Click(object sender, EventArgs e)
        {
SetTimer();
}



protected void ExamTimeOut(object sender, EventArgs e)
        {
            SetTimer();
        }