WebForms label text is not updated from OnInit() - vb.net

I have a WebForms application. Among other things, it has a Search box, a repeater, and a label totalItems that displays the count of the items in the repeater. The repeater is populated in a method called from Page_Init() method, based on a text entered into the Search control. For some reason, if I run the application with nothing in the Search control, and then second time with a text in the Search control, the content of the repeater changes accordingly, but the totalItems label is not updated. I debugged it and know that totalItems.Text is set to the correct value.
Here is the code:
In .aspx:
<div class="col-md-6">
<div class="makeblock">
<asp:Label ID="totalItems" CssClass="totalItems" Runat="server"></asp:Label>
</div>
</div>
In .aspx.cs:
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
InitializeComponent()
If Not IsNothing(Request.QueryString("group")) Then
buildTable(CInt(Request.QueryString("cat")), CInt(Request.QueryString("group")), CurrentPage)
End If
End Sub
Sub buildTable(ByVal itemCat As Integer, ByVal itemGroup As Integer, Optional ByVal pageNo As Integer = 1)
...
totalItems.Text = "Total Items: " & numItems.ToString()
...
itemRepeater.DataSource = pageds
itemRepeater.DataBind()
End Sub

To sum up some suggestions from the comments and discussion:
Generally speaking you should use the Page_Load() method as it ensures that all your page controls are properly loaded. Furthermore, you should guard your Page_Load() method with a check of the IsPostBack property to prevent re-populating your Repeater accidentally when handling another event, such as an OnItemCommand event from the repeater itself.
To help improve the architecture and to possibly expose some of the reasons why things are not updating as expected, I would suggest you separate the database operations, repeater population, and label updates into different methods. Then have a method that composes them together, calling them in proper sequence.
As for paging the repeater...the repeater is a very basic control that requires a lot of effort to do custom things with...the Web Forms event lifecycle can trip up even the most experienced of people. My suggestion would be to look into other SO questions about doing custom paging with repeater or other resources on the web to make sure you don't go down a path to insanity. You may find that something like a DataGrid could get the job done, although it is opinionated in its output and formatting.

Related

How to allow user to select individual UserControls?

I'm working on a windows form app containing a TabControl. In one of the TabPages I have a GroupBox that contains a FlowLayoutPanel. I also have a SQL database table containing user notes/comments. Upon form load, I use a SqlDataReader to populate a user control for each note (creation date, note text, username, etc.). The FlowLayoutPanel then gets filled by UserControls. However, I would like for the user to be able to select individual notes/UserControls for editing/deleting. I was initially using a DataGridView instead of UserControls, but notes vary in length and the DataGridView didn't look very organized. My UserControl contains a self-expanding RichTextBox. I thought about adding CheckBoxes next to each UserControl, but I'm not sure how to track which box belongs to which UserControl. Is there a smarter way to accomplish this?
This is a url for a screenshot of the UserControl: https://imgur.com/a/ZN7MM
(I don't have enough reputation to post images.)
And here is the code I got from another post on the self-expanding richtextbox:
Private Sub RichTextBox1_ContentsResized(sender As Object, e As ContentsResizedEventArgs) Handles rtbNote.ContentsResized
rtbNote.Height = e.NewRectangle.Height + 10
End Sub

Filter a listview in vb.net

Currently I have a program that is able to write to a ListView with column named : number, time, description . This listview is not bound to anything data, I'm just basically writing into it using the code.
What I want to do is to have a TextBox, whereby if the user wants to look at particular number i.e. 2, when they type into the textbox, then I want the listview to only show data with number = 2. When there's nothing in the textbox, I want the listview to show all the data.
I have being looking around on the internet and I didn't seem to find a filter method. Does it even exist and if so how would I go about implementing this.
All help is appreciated.
While I recommend using a DataGridView with DataSource but in cases that you need to use ListView, you can use this solution.
You can filter your list view this way:
Define a member field as backup storage of items:
In form Load after adding items to list view, store each item in that member field
Put a TextBox and a Button on form and handle Click event of the Button and in the handler, first clear all items of ListView then each item from that backup storage that matches with criteria.
Member Field for Backup of Items
Private ItemsBackup As New List(Of ListViewItem)
Fill backup after loading items in ListView in the form Load event
For Each item As ListViewItem In ListView1.Items
ItemsBackup.Add(item)
Next
Code of Filter
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.ListView1.BeginUpdate()
Me.ListView1.Items.Clear()
For Each item As ListViewItem In ItemsBackup
If (item.Text = Me.TextBox1.Text Or String.IsNullOrEmpty(Me.TextBox1.Text)) Then
Me.ListView1.Items.Add(item)
End If
Next
Me.ListView1.EndUpdate()
End Sub
You can also use above code for TextChanged event of the TextBox.
Here is a test data:
For i = 1 To 30
Dim item As New ListViewItem(i.ToString())
item.SubItems.Add(DateTime.Now.AddHours(i))
Me.ListView1.Items.Add(item)
Next
A normal .NET ListView can't do this without a considerable amount of work. So, you could use ObjectListView -- an open source wrapper around a standard .NET ListView -- which has already done all the work for you.
It has built-in filtering (and highlighting)

re: behaviour of a UserControl in a designer and at runtime

I'm trying to create a StackPanel user control that would allow me to stack newly added controls in a vertical fashion (like a WPF StackPanel but using Windows forms).
I created a new user control with the core code shown below, but even though my Location gets asigned right values in designer I can pop message boxes, the designer view does not re-arange the child controls that I drag and drop onto my stack panel, also at runtime my location seems to be overwriten with what the designer thinks is right (a Location of where I placed the control)
Public Class StackPanel
Inherits Panel
Private biasHeight As Integer = 0
Private Sub StackPanel_ControlAdded(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ControlEventArgs) Handles MyBase.ControlAdded
Dim newControl As System.Windows.Forms.Control = e.Control
'
' NOT WORKING: Set location of the newly added control in a panel and at runtime
'
newControl.Location = New System.Drawing.Point(0, biasHeight)
'
' Store the y-cooridnate of the next control
'
biasHeight = biasHeight + newControl.Height
End Sub
End Class
Typically these kind of things will be done by implementing the custom LayoutEngine. Msdn has a sample as well.
Am not sure why your code doesn't work, no reason to go behind it because it is terribly flawed. You are just setting the Location only when adding new control. There are lot more. You need to consider when a control is removed, when some control is hidden(visible set to false), When Size changed, When Padding changed etc etc.
So, Instead of reinventing the wheel I suggest you to use FlowLayoutPanel. If at all you want to implement it yourself then do it right. I mean create your LayoutEngine as shown in the provided link. In fact that link do have what you need.

Best Practice For Error Checking Controls On A Form

So I have a form with a variety of different controls (combobox, textboxes, listboxes, etc).
My first thought is to create a If, Else, End If statement. Well while that would work, it could also get pretty long, depending on the amount of controls and combinations.
Validation could include if a listbox is filled, checkbox is checked, etc pertaining to WinForms.
Is there a better solution to check all possiblities than an If statement?
It might be worthwhile to do the error checking as the user fills out the form. This could be implemented with the LostFocus event. Ex:
Private Sub btnTest_Leave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles yourbutton.LostFocus
Dim txt = yourbutton.Text
If txt = "yourtest" Then
'do stuff
EndIf
End Sub
As above. It depends on the Validation you are trying to do. Are you validating user input, datatype lenght range, etc. Are you validating business rules. Should such and such a value equal something else. There's all kinds of possibilities.

How can I refer to a control from within a control's method (like the "me" for classes)?

How can I refer to the control while I am inside a control's method in VB.NET?
For example, I want in a textbox to show a message box with that textbox's text every time the text changes. The code would be something like:
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
msgbox("The text is:"+ Me.text)
' ok the line above wont work i already know that, because "Me" refer to the form,
' not the control textbox1
' how i will refer to the textbox1's text???
' i dont want to use "textbox1.text" is there a way similar like the "Me" is for forms?
' because i want to copy-paste a code like this in a lot of controls and do not want to
' have to change in every copy the name to each control name
End Sub
I hope I made myself clear; my English needs some improvement :D
No, there's no keyword that allows you to do that. However, every event raised by a control passes in a sender parameter that you can use to determine which particular control raised that event.
Note that this parameter is always typed as a basic Object (because it can represent any possible control), so you'll need to downcast to a more specific control class if you need to access any of the unique members that it exposes. Since you're handling an event raised by a TextBox control, you know that the sender must be of type TextBox, so you can simply use DirectCast to handle the upcasting. You don't have to worry that an InvalidCastException will be thrown.
For instance, your above example would become:
Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As EventArgs) Handles TextBox1.TextChanged
Dim textBox As TextBox = DirectCast(sender, TextBox)
MessageBox.Show("The text is: " & textBox.Text)
End Sub
That being said, there are a couple of concerning things that jump out at me in your question:
Any time that your approach to solving a problem is "copy-pasting" code, you should stop, take a step back, and try to figure out if there's any better way to achieve your ultimate goal.
For example, if you need every textbox on your form to react in the same way whenever a particular event is raised, you should consider subclassing the existing TextBox control and consolidating all of your code in one place. Remember that you can inherit off of most of the standard controls to add custom functionality. This is often a far better solution than copying and pasting code to multiple places in your project. If you ever need to track down a bug or modify that functionality, you'll only have to change it one place in your code, rather than several. As a somewhat cheekier benefit, you'll be able to use Me to refer to that control when you're editing its subclass.
You should always prefer to concatenate (combine) strings using the & operator in VB.NET, rather than the + sign. Or perhaps even better, the String.Concat or String.Format methods.
There is no reason to use MsgBox in VB.NET, as opposed to MessageBox.Show. No, this won't improve performance of your application, but it's a good practice to get into for .NET languages.
The sender variable contains the TextBox instance you want to access. You only need to convert the sender to TextBox.