Non-client area form modification issues - vb.net

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!

Related

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

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

Changing the solid desktop background color in VB

I'm trying to change the solid desktop background color, and i'm using a RegistryKey to do that like so :
Dim CD As New ColorDialog
If CD.ShowDialog = DialogResult.OK Then
Dim RK As RegistryKey = Registry.CurrentUser.OpenSubKey("Control Panel\Colors", True)
RK.SetValue("Background", CD.Color.R & " " & CD.Color.G & " " & CD.Color.B)
End If
I'v seen this question, but it didn't help in my case.
The code above is working because the value in the registry editor is changing, but the background color is not, if i edited the color from the control panel, it will change the same value in the registry editor and the background color will change, anyone have explaining for that, or is there any other way to do it?
I finally got it to work, it can't be done by only editing the registry key, in fact you need to use the user32.dll API to do so, and you can use the registry key to get the value of the color only, but not to set it, thanks to Steve (↑).
Here is what worked for me :
First > Declare this function to use the API :
Private Declare Function SetSysColors Lib "user32.dll" (ByVal one As Integer, ByRef element As Integer, ByRef color As Integer) As Boolean
Second > Use this to call the function and change the color :
Dim CD As New ColorDialog
If CD.ShowDialog = DialogResult.OK Then
Dim BackgroundColor As Integer = ColorTranslator.ToWin32(CD.Color)
SetSysColors(1, 1, BackgroundColor)
End If
Hope that was useful to someone :)

Add clickable buttons to a custom DataGridViewCell control

I made a custom DataGridViewColumn control together with its DataGridViewCell controls.
The idea is to dynamically create the contents of the cell, which consists of a series of clickable function buttons, upon databinding. The number and kinds of buttons depend on the data value passed.
For this, I override the Paint method of the DataGridViewCell and check the formattedValue on its contents and draw buttons accordingly. However, these buttons are "dead" and not clickable, so the question is how to make them clickable, i.e. how do I add a handler for the click event?
Do I have to override the cell's OnClick method and then try to pinpoint which button exactly is clicked? Is this even possible? Are there better ways?
This is what I've got so far:
Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, cellState As DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts)
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
Dim cellBackground As New SolidBrush(cellStyle.BackColor)
graphics.FillRectangle(cellBackground, cellBounds)
cellBackground.Dispose()
PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle)
Dim sValue As String = formattedValue.ToString()
If (sValue.Contains("ViewAsPDF")) Then
Dim buttonArea As Rectangle = cellBounds
Dim buttonAdjustment As Rectangle = Me.BorderWidths(advancedBorderStyle)
buttonArea.X += buttonAdjustment.X
buttonArea.Y += buttonAdjustment.Y
buttonArea.Height -= buttonAdjustment.Height
buttonArea.Width -= buttonAdjustment.Width
buttonArea.Width = buttonArea.Width / 4
ButtonRenderer.DrawButton(graphics, buttonArea, PushButtonState.Default)
TextRenderer.DrawText(graphics, "PDF", Me.DataGridView.Font, buttonArea, SystemColors.ControlText)
End If
'etcetera
End Sub
I think you may have wandered down the wrong road. Based on the code provided, you are simply drawing the cells to look like they contain buttons. Since they are not actually objects, they are incapable of raising events.
I don't understand ButtonRenderer, if you can't create actual Buttons with it
The ButtonRender does not create a new button object, it is meant to be used by Button objects for drawing. Often a subclassed a button, will not use it because it employs the existing theme and style which is may be what a you wants to do differently (even the DataGridViewButtonCell does not use it -- at least not directly).
From the code provided, it seems to work out each button on the fly each time rather than drawing from some collection or definition. What if the "action" list needs to vary based on the row (e.g. different actions for a DOC, XLS or Image row)? Doing so, would seem to take a great deal of code.
Your current course may not be impossible, but it is not trivial either. You might be able to create a collection of virtual buttons (basically the Rect from when it was drawn) and render them as you have done. Then in the cell-click event, translate/adjust the X position to see which rectangle contains thisPt.X to determine which related action to take.
There are "issues" still such as what happens when the user resizes the column? What about when the button list varies by some other cell value (DOC vs XLS vs IMG vs PDF)? This would require a collection of button sets...and a fair amount of code.
This is not to say it cant be done, but it seems like a great deal of code would be required to make it even a little flexible.
Are there better ways?
I think so.
A simpler, existing solution might be to use the existing DataGridViewComboBoxColumn to store "Actions" or "Activities". It seems a bit less cluttered and more user friendly:
It takes only a small amount of code to provide a different list for each animal:
' dogs like to go for walks
Private ActsCan() As String = {"Feed", "Pet", "Bathe", "Brush", "Take for Walk"}
' no walks or baths for cats
Private ActsFel() As String = {"Feed", "Pet", "Baby-Talk To", "Brush"}
' never bathe a Mugwai, comb rather than brush
Private ActsMug() As String = {"Feed", "Pet", "Baby-Talk To", "Comb"}
Private ActsGrem() As String = {"Hide From", "Strangle"}
...
Private Sub dgv_RowEnter(sender As Object,
e As DataGridViewCellEventArgs) Handles dgv.RowEnter
Dim dgvCBO As DataGridViewComboBoxCell
dgvCBO = CType(dgv.Rows(e.RowIndex).Cells("ColActs"), DataGridViewComboBoxCell)
dgvCBO.Items.Clear()
Select Case dgv.Rows(e.RowIndex).Cells("colSpecies").Value.ToString
Case "Canine"
dgvCBO.Items.AddRange(ActsCan)
Case "Feline"
dgvCBO.Items.AddRange(ActsFel)
Case "Mugwai"
dgvCBO.Items.AddRange(ActsMug)
Case "Gremlin"
dgvCBO.Items.AddRange(ActsGrem)
End Select
End Sub
A class to encapsulate most of that might be nice for unbound DGVs. It could be optimized not to rebuild the list when the trigger value for thisRow is the same as the last.
What about this approach. Only implementing the ui.

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.

Is there some kind of display control in .NET that can handle color codes?

It seems the only options available to do multi-color on a string is either a bunch of label controls cleverly grouped together or to use a RichTextBox and play with the font properties as text is added to the control.
What I am looking for instead is some kind of control that can render some style of control codes out as color. Consider bash codes:
NORMAL='\e[0m'
GREEN='\e[0;32m'
BLUE='\e[0;34m'
echo -e "This text is ${GREEN}green${NORMAL} and this text is ${BLUE}blue${NORMAL}"
In the above, the words 'green' and 'blue' will be colorized with their respective colors. I was wondering if there was a control with some kind of feature like this, or will I have to code something myself?
Note, I only have the Express copy of VB 2010, and I would very much like to avoid third-party controls.
Are you specifically looking for something that understands ANSI control codes, or just something that accepts markup? If you just want something that accepts markup, you can use the RichTextBox.Rtf property to set all the control codes and text with a single string.
See http://msdn.microsoft.com/en-us/library/aa140277(v=office.10).aspx for the RTF specifications.
I would recommend programmatically generating a sample document, then reading the Rtf property and using the resulting RTF code as a template for what you should generate. For reference, here's a simple RTF document that has two color of text (plus the default) in Consolas (which fallback to Courier New):
{\rtf1\deff0{\fonttbl{\f0\fmodern\fcharset0 Consolas {\*\falt Courier New};}}
{\colortbl ;\red255\green0\blue0;\red0\green176\blue80;}
\cf1 Hello\cf0 , \cf2 world\cf0 .
}
There are a couple of other options. first you can paint text using the graphics object and DrawString method using any color font and style you want. This however can be a pain. The easiest way is to use a web browser control and use plain old html.
If you don't want to use RTF I wrote this little sample which will allow you to use RGB codes this is not complete solution as you would have to figure out a way to delmit the control chars. If you wanted to test it create a form and drop a button and a rich text box on it.
Imports System.Drawing
Imports System.Text.RegularExpressions
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim str As String = "This text is {#00FF00}green{#000000} and this text is {#0000FF}blue{#000000}"
PrintToRtf(str, RichTextBox1)
End Sub
Private Shared Sub PrintToRtf(Str As String, RTB As RichTextBox)
Dim mc As MatchCollection = Regex.Matches(Str, "\{\#(?<Red>[0-9A-Fa-f]{2})(?<Green>[0-9A-Fa-f]{2})(?<Blue>[0-9A-Fa-f]{2})\}")
Dim lp As Int32 = 0
For Each mtc As Match In mc
Dim subStr As String = Str.Substring(lp, mtc.Index - lp)
Dim R, G, B As Byte
R = Integer.Parse(mtc.Groups("Red").Value, Globalization.NumberStyles.AllowHexSpecifier)
G = Integer.Parse(mtc.Groups("Green").Value, Globalization.NumberStyles.AllowHexSpecifier)
B = Integer.Parse(mtc.Groups("Blue").Value, Globalization.NumberStyles.AllowHexSpecifier)
Dim clr As Color = Color.FromArgb(255, R, G, B)
RTB.SelectedText = subStr
RTB.SelectionColor = clr
lp = mtc.Index + mtc.Length
RTB.Select(RTB.TextLength, 0)
Next
End Sub
End Class