How to assign passive easy-to-change styles to controls in VB.NET windows forms (similar to android styles.xml) - vb.net

I'm trying to add theme options to my VB.NET program without doing it the dirty way of repeating the same code for each element... Is it possible to create some styling method similar to what we have in android? (styles.xml)
First thing I started making is a library for the themes I want to use in my app but I quickly realized that it still won't help to use a regular class/group of methods since I will still have to call them everytime I need a control to be themed since it is not passive like the following:
Public Class Theme
Public Shared Sub SetThemeLight(c As Control, Gray As Boolean)
Dim LBack As Color = Color.White
Dim LBackGray As Color = Color.WhiteSmoke
Dim LFore As Color = SystemColors.ControlText
Dim LForeGray As Color = Color.FromArgb(51, 51, 51)
If Gray Then
c.BackColor = LBackGray
c.ForeColor = LForeGray
Else
c.BackColor = LBack
c.ForeColor = LFore
End If
End Sub
'...
'Somewhere else in the program for example
Public Class Main
Theme.SetThemeLight(TextBox1, False)
'...
Issue here is the excessive simplicity which is so inefficient. I would love to find an efficient way of theming similar to android's styles.xml

Related

VB.NET Link Label to another Label

I am new to VB.NET and also am self taught, so basically I know nothing. I have written some software (~2000 lines) it is fairly basic. However many of those lines are just changing different labels (on different tabs) when the user does different things.
I find modifying labels to be very annoying, mostly when I have 3-4 labels that always show the same thing but in different places. I have done some searching related to trying to link or bind these labels but I don't think I have found what I am looking for. I'm sure I am searching the wrong terminology or something very simple.
My question is: Is there a simple way to link labels together so I only need to change text/color on one label and the other "linked" labels follow suit?
Below is a snippet of what I am trying to simplify.
lblStatus.Text = "Connected to transmitter!"
lblStatus.BackColor = Color.Green
lblStatus.ForeColor = Color.White
lblRadioStatus.Text = "Connected to transmitter!"
lblRadioStatus.BackColor = Color.Green
lblRadioStatus.ForeColor = Color.White
lblStatusRec.Text = "Connected to transmitter!"
lblStatusRec.BackColor = Color.Green
lblStatusRec.ForeColor = Color.White
lblRadioSetup.Text = "Connected to transmitter!"
lblRadioSetup.BackColor = Color.Green
lblRadioSetup.ForeColor = Color.White
These labels always show the same but are displayed on different tabs. There has to be a better way.
You can create an array of labels declared at the form level and then fill this array after the call to InitializeComponent with the labels that you want to change.
Then write a method that loops over the array and change all the labels with your values.
For example:
Public Class Form1
Dim myLabels() As Label
Public Sub New()
InitializeComponent()
myLabels = New Label() {lblStatus, lblStatusRec, lblRadioStatus, lblRadioSetup};
End Sub
Private Sub UpdateLabel(labelText As String, fore As Color, back As Color)
For Each lbl In myLabels
l.Text = labelText
l.BackColor = back
l.ForeColor = fore
Next
End Sub
End Class
Now, everytime you need to change these labels you call the UpdateLabel method with the parameters required.

Non-client area form modification issues

I seem to be having a few issues with the form on my project after I decided to extend the non client area by use of this code:
<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential)> Public Structure Side
Public Left As Integer
Public Right As Integer
Public Top As Integer
Public Bottom As Integer
End Structure
<Runtime.InteropServices.DllImport("dwmapi.dll")> Public Shared Function DwmExtendFrameIntoClientArea(ByVal hWnd As IntPtr, ByRef pMarinset As Side) As Integer
End Function
Try
Me.BackColor = Color.Black
Dim Side As Side = New Side
Side.Left = -1
Side.Right = -1
Side.Top = -1
Side.Bottom = -1
Dim result As Integer = dwmExtendFrameIntoClientArea(Me.Handle, Side)
Catch ex As Exception
End Try
The code isn't exact, just hopefully it can serve to give a better understanding of what I attempted to accomplish. The issue I'm having now with the black color now being used as transparency with aero. Some text colors that are supposed to be black are now reflecting the color of the current aero color theme as you can see in the examples as well as other color issues elsewhere such as the text highlight color as well.
Having the non client area extended is an important part of the project, so I can't deviate from that too much. Anyway I can try to have a color set designated for other things like this or some other kind of solution to resolve this? I'm a little fuzzy on meddling around with form stuff having to do with aero. Thanks!

Disabling the "disabled look" of disabled buttons (VB.net for desktop)

I have many buttons in my app, and some of them are disabled in various circumstances. The problem is, buttons "look wrong" when .Enabled = False
What follows is an example of a list of properties which may be similarly applied to all buttons.
.BackColor = Color.Goldenrod
.Flatstyle = FlatStyle.Flat
.FlatAppearance.MouseOverBackColor = Color.White
.FlatAppearance.BorderSize = 0
.BackgroundImageLayout = ImageLayout.Stretch
.BackGroundImage = My.Resources.Resources.ButtonFade 'This image is translucent, giving the rounded 3D look as shown below.
.ForeColor = Color.Black
.Image = My.Resources.Resources.refresh 'May be other images.
.Text = "RELOAD"
The .BackColor property may be all kinds of colors, as set by the user via a "theme".
To illustrate my concern, below is a screenshot of three buttons. "NEW" is enabled. "SAVE" is disabled. Although "NEW" AND "SAVE" look similar, "SAVE" is washed out with low contrast colors for the text and image.
I'd like all disabled buttons to look more like "RELOAD". That is, I would like the text and image to remain solid black, for better legibility, but I can set BackgroundImage = Nothing so it won't look 3D. (To the user, the model is "If it isn't 3D, it's not clickable.") I will probably also modify the background color of disabled buttons, but that part is easy. I just need the system to stop "greying out" the text and image when I set Enabled = False.
To get this screenshot, "RELOAD" is actually enabled, but I've removed its background image. Problem is, it can still be clicked.
How can I get the look I'm looking for?
You cannot achieve what you want by using the Enabled property, the Button class implements the Windows GUI style guide that disabled controls should look disabled by graying out their appearance. A further restriction is that the button renderers cannot be tinkered with, they are not overridable.
You need to achieve your goal by making the control act disabled. Add a new class to your project and paste the code shown below. Compile. Drag the new control from the top of the toolbox to your form, replacing the existing button controls. Set the Disabled property to True in your code when you want to disable the button. You probably want to tinker with the code that changes the appearance.
Imports System.ComponentModel
Public Class MyButton
Inherits Button
<DefaultValue(False)> _
Public Property Disabled As Boolean
Get
Return IsDisabled
End Get
Set(value As Boolean)
If Value = IsDisabled Then Return
IsDisabled = Value
MyBase.SetStyle(ControlStyles.Selectable, Not IsDisabled)
If IsDisabled And Me.Focused Then Me.Parent.SelectNextControl(Me, True, True, True, True)
'' Change appearance...
If IsDisabled Then
Me.FlatStyle = Windows.Forms.FlatStyle.Flat
Else
Me.FlatStyle = Windows.Forms.FlatStyle.Standard
End If
End Set
End Property
Protected Overrides Sub OnMouseEnter(e As EventArgs)
If Not IsDisabled Then MyBase.OnMouseEnter(e)
End Sub
Protected Overrides Sub OnMouseDown(mevent As MouseEventArgs)
If Not IsDisabled Then MyBase.OnMouseDown(mevent)
End Sub
Protected Overrides Sub OnKeyDown(kevent As KeyEventArgs)
If Not IsDisabled Then MyBase.OnKeyDown(kevent)
End Sub
Private IsDisabled As Boolean
End Class
The way i do it in c (is way more powerfull for extreme gui stuff. This example is trivial!) to override the disabled state and draw my image (in c):
NMHDR *nmr;
NMCUSTOMDRAW *nmcd;
case WM_NOTIFY:
nmr = (NMHDR *)lParam;
nmcd = (NMCUSTOMDRAW *)lParam;
if(nmr->idFrom == IDC_BUTTON && nmr->code == NM_CUSTOMDRAW){
if(nmcd->dwDrawStage == CDDS_PREERASE){
if(nmcd->uItemState & 0x1) {StretchBlt(nmcd->hdc,...);} //Down
else if(nmcd->uItemState & 0x40){StretchBlt(nmcd->hdc,...);} //Enter
else if(nmcd->uItemState & 0x4) {StretchBlt(nmcd->hdc,...);} //Disable
else {StretchBlt(nmcd->hdc,...);} //Leave
return CDRF_SKIPDEFAULT;
}
}
break;
The WM_NOTIFY is sent to your main form so you can catch it. The nmcd->hdc
is your button hdc, and you draw on it your image depending on the state (Down, Enter,
Disable or Leave). I know it is difficult to write vb from c but you have a start point if you are patient enough.
Valter

VB.Net 2008 Buttons acts as Tab Controls

I am looking for a way to design things differently in my project. Instead of using TabControls I wish to use Buttons (Instead of pressing the tabs on the top I would like to press the Buttons on the left-side). These buttons when pressed they have their own Panel where each has their own respective content.
Select Case tabAdmin.SelectedIndex
Case 0
If txtCode_Patient.Text = "" Then
txtCode_Patient.Focus()
Else
cmdAdminister.Focus()
End If
Case 1
If txtD_Patient.Text = "" Then
txtD_Patient.Focus()
Else
cmdRefresh.Focus()
End If
Case 2
If txtI_Patient.Text = "" Then
txtI_Patient.Focus()
Else
cmdI_CUser.Focus()
End If
Case 3
If txtStat_CS.Text = "" Then
txtStat_CS.Focus()
Else
cmdStat_Refresh.Focus()
End If
End Select
The code above is similar to what my project acts and it works with TabControls. I want to do a similar thing but this time, like I said before, pressing Buttons on the left-side. How can I do a similar thing ?
UPDATE:
I found a way for this one but now my concern is how do I make it look like one of its default button 3D look-alike?
Public Class Tab
Inherits TabControl
Private Property DoubledBuffered As Boolean
Sub New()
SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.OptimizedDoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
DoubledBuffered = True
SizeMode = TabSizeMode.Fixed
ItemSize = New Size(30, 110)
End Sub
Protected Overrides Sub CreateHandle()
MyBase.CreateHandle()
Alignment = TabAlignment.Left
End Sub
Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
Dim B As New Bitmap(Width, Height)
Dim G As Graphics = Graphics.FromImage(B)
G.Clear(Color.AliceBlue)
For i = 0 To TabCount - 1
Dim TabRectangle As Rectangle = GetTabRect(i)
If i = SelectedIndex Then
'//Selected
G.FillRectangle(Brushes.DarkSlateGray, TabRectangle)
Else
'//Not Selected
G.FillRectangle(Brushes.AntiqueWhite, TabRectangle)
End If
G.DrawString(TabPages(i).Text, Font, Brushes.Black, TabRectangle, New StringFormat With {.Alignment = StringAlignment.Center, .LineAlignment = StringAlignment.Center})
Next
e.Graphics.DrawImage(B.Clone, 0, 0)
G.Dispose() : B.Dispose()
MyBase.OnPaint(e)
End Sub
End Class
Use the CheckBox control instead of Button, but set Appearance = Button, that way it looks exactly like a button can remains in the "pressed" state when clicked.
To shift between content, put each of your sub-forms into their own UserControl instances, then host them within a Panel control, then switch the .Visibility property of each sub-form according to which CheckBox was clicked.
There is an Outlook-style side bar available on Code Project. It has a VB version as well as C# and although it's knocking on a bit now, you could always adapt this to look a bit nicer. I have used it in the past and it worked pretty well as I recall.
You can set the selected tab via tabAdmin.SelectedIndex = 0 (or 1, 2, etc, but remember it is 0 based)
You may also set the tab by the tab's name via tabAdmin.SelectedTab = TabName
Use a common click event handler for the buttons. Store the relevant tabindex in the Tag property of the buttons. Then tabAdmin.SelectedIndex equals the tag of the clicked button cast as integer.

Color-picker showing color names

Does anyone know of a color-picker for Visual Studio (Visual Basic) that shows the names of the standard colors?
For example, in Visual Studio, you can alter the color of a control using a color-picker that has tabs of "Custom", "Web" and "System". The Web & System options show a list of the color names, whereas Custom supplies (mainly) RGB (which is what the VB ColorPicker control does).
Thanks!
there is precious little to one of these until you want to do like VS and present System Colors apart from Named Colors, make it a popup or some such. Example using colors as the BackGround:
' capture the names
Private _Colors As String()
' get the names
' add qualifiers to skip SystemCOlors or
' Transparent as needed
Function GetColorNames As String()
For Each colorName As String In KnownColor.GetNames(GetType(KnownColor))
_Colors.Add(colorName)
End If
Next
' post the names to a CBO:
cboBackColor.Items.AddRange(_Colors)
On the form CBO, set the DrawMode to OwnerDrawFixed, then:
Private Sub cboSheetBackColor_DrawItem(ByVal sender As Object,
ByVal e As System.Windows.Forms.DrawItemEventArgs)
Handles cboSheetBackColor.DrawItem
Dim Bclr As Color, Fclr As Color
' get the colors to use for this item for this
Bclr = Color.FromName(_Colors(e.Index).ToString)
Fclr = GetContrastingColor(Bclr) ' see below
With e.Graphics
Using br As New SolidBrush(Bclr)
.FillRectangle(br, e.Bounds)
End Using
Using br As New SolidBrush(Fclr)
.DrawString(cboSheetBackColor.Items(e.Index).ToString,
cboSheetBackColor.Font, br,
e.Bounds.X, e.Bounds.Y)
End Using
End With
e.DrawFocusRectangle()
End Sub
You can just draw a swatch like Windows/VS does by defining a rectangle to fill. Generally, thats swell, but in the case where you are doing something like defining a background color it rather helps to show how it looks with text on it and more of the color than the little bitty swatch - hence the filled CBO Item rect.
The standard window Text color will not show up on all of them. For a "light" theme, Violet and Black etc will hide/make the color name impossible to read. GetContrastingColor is a function which evaluates the Brightness of the current color and then returns either White or Black:
Public Function GetContrastingColor(ByVal clrBase As Color) As Color
' Y is the "brightness"
Dim Y As Double = (0.299 * clrBase.R) _
+ (0.587 * clrBase.G) _
+ (0.114 * clrBase.B)
If (Y < 140) Then
Return Color.White
Else
Return Color.Black
End If
End Function
You can then use all this in a Class which inherits from ComboBox, or build a UserControlif you like distinct controls. You can also leave it as code in a DLL which is called on those occasions. I should mention there are also perhaps a dozen such critters on CodeProject.
I don't know about an existing control but you can use the KnownColor enumeration and the SystemColors class to get all the names of those Color values. You can then build your own control, e.g. custom ComboBox, with that data.