re: behaviour of a UserControl in a designer and at runtime - vb.net

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.

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

How to hide a DataGridViewButtonCell

I have a DataGridViewButtonCell in my DataGridView and I wanted to set the property Visible to True.
I have tried:
DataGridView1.Rows("number of row i want").Cells("number of cell i want").Visible = True
Unfortunately it says that the property visible is read only.
Here is the code:
Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
'does not work
DataGridView1.Rows(e.RowIndex).Cells(6).Visible = True
End Sub
Does anyone knows how I can achieve this?
Thanks.
There is no actual way to hide a DataGridViewButtonCell. Currently I can only see two options:
Use padding to move the button over as shown here. I will provide similar VB.NET code
Set the Cell to a DataGridViewTextBoxCell and set the ReadOnly property to True
Use Padding:
Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
If DataGridView1.Rows(e.RowIndex).Cells(6).GetType() Is GetType(DataGridViewButtonCell) Then
Dim columnWidth As Integer = DataGridView1.Columns(e.ColumnIndex).Width
Dim newDataGridViewCellStyle As New DataGridViewCellStyle With {.Padding = New Padding(columnWidth + 1, 0, 0, 0)}
DataGridView1.Rows(e.RowIndex).Cells(6).Style = newDataGridViewCellStyle
End If
End Sub
Use DataGridViewTextBoxCell:
Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
If DataGridView1.Rows(e.RowIndex).Cells(6).GetType() Is GetType(DataGridViewButtonCell) Then
Dim newDataGridViewCell As New DataGridViewTextBoxCell
DataGridView1.Rows(e.RowIndex).Cells(6) = newDataGridViewCell
newDataGridViewCell.ReadOnly = True
End If
End Sub
Both of these should give you the effect of not showing the button.
This is really a perspective issue. From a programmer’s perspective, simply ignoring the button clicks on the buttons I want to disable is very easy to do and takes just a few lines of code.
From a user perspective, this situation would play out like this… the user clicks what appears to be a valid enabled button, and nothing happens. The user did not write the code for this… so at best the user will think the computer is not responding to the button click or at the worst… would think your coding skills are dubious!
The same situation happens if the button is missing. The user is not going to know why it is missing… but will most likely come to the same conclusion described above with a non-working button.
In another very simple approach, let say that all the buttons are enabled and we have a list of the button indexes we want to disable. The users presses one of the buttons, we check the disabled button list and if the clicked button is one that is disabled, simply display a message box to indicate why this button is disabled. This approach says to the user… “Here are a bunch of buttons, guess which ones are enabled”…
The DataGridViewDisableButtonCell and DataGridViewDisableButtonColumn wrappers solve all of the above issues… the button is visible so the user wont question where the button went if you set it to invisible and it is greyed out. “Greyed out” is something most users understand and will relieve the user of having to “guess” which buttons are enabled.
You can create a wrapper for two classes: the DataGridViewButtonCell and the DataGridViewButtonColumn.
The link How to: Disable Buttons in a Button Column in the Windows Forms DataGridView Control to the MS example is one I have used before using C#, however there is a VB implementation at the link also.
Below is a picture of the result of using the two wrappers described in the MS link. For testing, the picture below uses the check boxes to left of the button to disable the button on the right.
IMHO, using this strategy is user friendly. If you simply make the button invisible or read only, then the user is possibly going to think your code is messed up and not have a clear understanding of WHY the button is missing or doesn’t work. A disabled button indicates to the user that the button is not available for that item. An option would be to have a mouse roll-over indicating why the button is disabled.

Using DataRelations and DevExpress Grids - Hide expansion control

I have a bit of a weird issue. We use DevExpress controls to do all our Windows Form development. Anyway, I found a perfect use for the DataRow.SetParentRow/GetParentRow methods in my grid. So I created a DataRelation, added it to the DataSet and bound it as the data source for my grid. The issue is I now find this:
On my grid. It seems to be the DataRelation (when I mouse over it the tooltip is the DataRelation name).
Does anyone know how to hide this line of controls? If I cannot get rid of them I will have to write a parent/child link between the rows, and that would be a shame because the DataRelation stuff works almost perfectly.
Thanks in advance!
You want to set the following property to hide those: (this is for a grid view, banded grid view or advanced banded grid view)
In OptionsDetail set EnableMasterViewMode=False
If you have a master Detail grid that has times where the details are empty and you want to hide those you can do so by handling the custom draw for the masterview cells something like this:
Private Sub gvMain_CustomDrawCell(ByVal sender As Object, ByVal e As DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventArgs) Handles gvMain.CustomDrawCell
Dim View As DevExpress.XtraGrid.Views.Grid.GridView = CType(sender, DevExpress.XtraGrid.Views.Grid.GridView)
If e.Column.VisibleIndex = 0 And View.IsMasterRowEmpty(e.RowHandle) Then
CType(e.Cell, DevExpress.XtraGrid.Views.Grid.ViewInfo.GridCellInfo).CellButtonRect = Rectangle.Empty
End If
End Sub

How to capture current location (on canvas) of an MDIWindow, after it has been moved?

I have a Silverlight 4 app that has a canvas with five MDIWindows on it. The Canvas.Left and Canvas.Top properties are set in XAML. These five MDIWindows can be moved around with the mouse. I am trying to use IsolatedStorageSettings to save their current location, invoked from a button event. However, when I call MDIWhatever.GetValue(Canvas.LeftProperty) I always get the initial value of Canvas.Left as set in XAML, and what I want is the current location. I've tried calling InvalidateArrange() and UpdateLayout() on both the MDIWindow and LayoutRoot (the canvas).
Private Sub btnSaveLayout_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSaveLayout.Click
MDIWhatever.InvalidateArrange()
MDIWhatever.UpdateLayout()
LayoutRoot.InvalidateArrange()
LayoutRoot.UpdateLayout()
_settings.Clear()
_settings.Add("MDILeft", MDIWhatever.GetValue(Canvas.LeftProperty))
_settings.Add("MDITop", MDIWhatever.GetValue(Canvas.TopProperty))
_settings.Save()
End Sub
This ought to be easy, what am I missing?
EDIT: This is a third-party control, from off of Codeplex. I assumed it was part of Silverlight because of the System.Windows.Controls namespace. I did not expect a third-party control to use this namespace instead of having its own.
Rather than get this one to work, I found another control that supports a Position property (that returns a Point object of the current position). FloatingWindowControl at http://jevgenijpankov.heliocode.com/articles/FloatingWindow.aspx

How do I print just one or two controls instead of the whole form in Visual Basic

I have a program that gives the user driving directions, I would like the user to be able to print just the directions or just the directions and a map by selecting a corresponding radio button for each option. How can I print just these sections and not the whole form? And how can I use the radio buttons to tell it what to print? Thanks
Updated code:
Private Sub btnprint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnprint.Click
If rbprintall.Checked = True Then
'Ad code to print all here
ElseIf rbprintdirections.Checked = True Then
lbldirections.DrawToBitmap()
lbldirections2.DrawToBitmap()
lbldirections3.DrawToBitmap()
lbldirections4.DrawToBitmap()
Else
MessageBox.Show("You must select one of the above options!")
End If
If you're using Windows Forms, almost all of the built-in controls can be easily rendered to an image using their DrawToBitmap method. If you simply want to print whatever is currently displayed by a control, this is the easiest way to do it. Do note, however, that there are a couple of caveats to what can be drawn this way. See the linked documentation for details.
Printing in the .NET Framework is also made relatively simple by taking advantage of the functionality provided in the System.Drawing.Printing namespace. If you aren't already experienced with this, Google for some tutorials. For example, there's a pretty good article here from the MSDN Magazine.
So, to accomplish your ultimate goal, you'll need to do the following:
When the user clicks "Print", determine which radio button is currently selected.
Create a temporary bitmap and grab a copy of the appropriate control in that bitmap using the control's DrawToBitmap method. (If you need to print multiple controls, create a separate temporary bitmap for each of them, and then print each of them in the next step.)
Draw that image to the printer using the Graphics.DrawImage method in the PrintPage event handler method for a PrintDocument object you've created.
EDIT: I'm not really sure where your question is with regards to the code that you've posted, but I see two primary problems.
In the first block of your if statement, the comment suggests you don't know how to print all of the controls. You have a couple of different options. If you just want to print every control on the form as it appears, you can simply use the DrawToBitmap method of the Form itself. That will create a bitmap of the form's entire client area, including all of the controls it contains.
If there are still some controls on the form that you don't want to print, even when the user chooses "Print All", you'll need to call the DrawToBitmap methods on each individual control. You might set up a loop so that you don't have to write a line of code for every control, but there's not really another good option.
I suspect you're going to have problems with the second elseif block working as you expect it to, also. Recall that I said above you need to create temporary bitmap images, and then draw into those bitmaps? The DrawToBitmap method takes two parameters:
bitmap: a System.Drawing.Bitmap that you want an image of the control to be drawn into
targetBounds: a System.Drawing.Rectangle that describes the bounds of the control that will be rendered
The code you've shown is missing both of those parameters. In this case, the second (targetBounds) is simple—because you want to draw the entire control, all you need to do is specify it's ClientRectangle property for that parameter.
For the first (bitmap) parameter, you need to do as I mentioned above and create a new Bitmap image by declaring a temporary variable. Then, you need to call the DrawToBitmap method with this temporary bitmap specified.
Maybe I can be clearer with an example. Modify your above code to look like this:
'Declare some class-level variables to hold images of the controls to print
Private bmpDirections1 As System.Drawing.Bitmap
Private bmpDirections2 As System.Drawing.Bitmap
Private bmpDirections3 As System.Drawing.Bitmap
Private bmpDirections4 As System.Drawing.Bitmap
Private Sub btnprint_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnprint.Click
If rbprintall.Checked = True Then
'Add code to print all here
ElseIf rbprintdirections.Checked = True Then
'Draw lbldirections control to bitmap variable named bmpDirections1
bmpDirections1 = New Bitmap(lbldirections.Width, lbldirections.Height)
lbldirections.DrawToBitmap(bmpDirections1, lbldirections.ClientRectangle)
'Draw lbldirections2 control to bitmap variable named bmpDirections2
bmpDirections2 = New Bitmap(lbldirections2.Width, lbldirections2.Height)
lbldirections2.DrawToBitmap(bmpDirections2, lbldirections2.ClientRectangle)
'Draw lbldirections3 control to bitmap variable named bmpDirections3
bmpDirections3 = New Bitmap(lbldirections3.Width, lbldirections3.Height)
lbldirections3.DrawToBitmap(bmpDirections3, lbldirections3.ClientRectangle)
'Draw lbldirections4 control to bitmap variable named bmpDirections4
bmpDirections4 = New Bitmap(lbldirections4.Width, lbldirections4.Height)
lbldirections4.DrawToBitmap(bmpDirections4, lbldirections4.ClientRectangle)
Else
MessageBox.Show("You must select one of the above options!")
End If
End Sub
The only thing to remember is that you need to call the Dispose method on each bitmap variable when you are finished using it. The Dispose method "releases the resources owned by the image", which means that it frees up the memory it was using. There's no reason to keep those large-ish images around if you're not going to use them again. So, you should probably do this after the print job is completed. Once you dispose the bitmap object, you will no longer be able to use the image it contained, but you can always create a new bitmap object and assign it to the variable (as shown in the above code) the next time the user clicks print.
Unrelated: There's no reason to test for If x = True. The simpler If x is the same thing, and considered by most programmers to be better style. Effectively, you're doing a double comparison against True, which isn't necessary.