Recently I was working on .NET Framework 4.8 and decided to change it to .NET 6
At .NET Framework 4.8 I was using the code below to draw a rectangle around the Listbox and to make the event DrawItem:
using (Pen penBorder = new Pen(Color.FromArgb(66, 66, 66), 2))
{
penBorder.Alignment = PenAlignment.Inset;
graph.DrawRectangle(penBorder, ModifiersLB.Location.X - 2, ModifiersLB.Location.Y - 2, ModifiersLB.Width + 4F, ModifiersLB.Height + 4F);
}
private void LB_DrawItem(DrawItemEventArgs e, ListBox LB)
{
Color backgroundColor = Color.FromArgb(50, 50, 50);
Color horizontalColor = Color.FromArgb(100, 100, 100);
if (e.Index >= 0)
{
SolidBrush sb = new SolidBrush(((e.State & DrawItemState.Selected) == DrawItemState.Selected) ? horizontalColor : backgroundColor);
e.Graphics.FillRectangle(sb, e.Bounds);
string text = LB.Items[e.Index].ToString();
SolidBrush tb = new SolidBrush(e.ForeColor);
e.Graphics.DrawString(text, e.Font, tb, LB.GetItemRectangle(e.Index).Location);
}
}
The problem is this code is only supported by Windows.
I decided to make this question because I was receiving a warning. I never really intended to make my app supported on all platforms. I just wanted to ask if there is a better way to do what I was doing so that I don't get the warning.
Is there a better method to do this code or is there a ListBox replacement that I could use?
Related
sorry if this has been asked, I was unable to find a solution after I searched google for about 3 days.
I'm a n00b, sorry.
With the little background on programming I have I managed to add a custom control from this project:
FilesListBox from codeproject, the small program I'm trying to make is to manage sessions of files so that they can be opened in bulk, a general file session manager.
Anyway, my question is how can I customize the way the listbox's items strings are viewed, currently they are like this:
The final goal would be to open a txt file on the left, see the filenames listed on the listbox on the right and open them all at one with the default app
As of the code, I believe the important part is somewhere in here:
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.DrawBackground();
e.DrawFocusRectangle();
Rectangle bounds = e.Bounds;
if (e.Index > -1 && e.Index < Items.Count)
{
Size imageSize;
string fileNameOnly = Items[e.Index].ToString();
string fullFileName = GetFullName(fileNameOnly);
Icon fileIcon = null;
Rectangle imageRectangle = new Rectangle(bounds.Left + 1, bounds.Top + 1, ItemHeight - 2, ItemHeight - 2);
if (fileNameOnly.Equals(".."))
{
// When .. is the string - draws directory icon
fileIcon = IconExtractor.GetFileIcon(Application.StartupPath, _fileIconSize);
e.Graphics.DrawIcon(fileIcon, imageRectangle);
}
else
{
fileIcon =
IconExtractor.GetFileIcon(fullFileName, _fileIconSize);
// Icon.ExtractAssociatedIcon(item);
e.Graphics.DrawIcon(fileIcon, imageRectangle);
}
imageSize = imageRectangle.Size;
fileIcon.Dispose();
Rectangle fileNameRec = new Rectangle(bounds.Left + imageSize.Width + 3, bounds.Top, bounds.Width - imageSize.Width - 3, bounds.Height);
StringFormat format = new StringFormat();
format.LineAlignment = StringAlignment.Center;
e.Graphics.DrawString(fileNameOnly, e.Font, new SolidBrush(e.ForeColor),
fileNameRec, format);
}
base.OnDrawItem(e);
}
The full code of the class can be obtained on the codeproject page, but I paste the full code here: full FilesListBox.cs anyway, maybe a kind soul can take a look.
I am currently working on a chat window and have created tiles for messages.
I have a problem because the text in tiles draws using the DrawString method and I`m not really sure if there is any such possibility that this text can be copied? How can it enable the user to select and copy text? Below is part of the source code.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var graphics = e.Graphics;
...
using (SolidBrush brush = new SolidBrush(this.ForeColor))
{
if (_BoxPosition == BoxPositionEnum.Left)
{
graphics.DrawString(Text, Font, brush, new Rectangle(20 , Height / 2, renderWidth - 5, Height / 2 - 5));
}
else
{
StringFormat format = new StringFormat()
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Far
};
graphics.DrawString(Text, Font, brush,
new Rectangle(_mc.BoxIndent - 10 , Height / 2, renderWidth - 5, Height / 2 - 5),format);
}
}
For simple: just use TextBox or RichTextBox and set ReadOnly = true and color as what you want.
For more advanced: create your own message box user control, and you can do many thing with it (react, select all, ...).
Here the tutorial for create your own user control: https://www.c-sharpcorner.com/UploadFile/7d3362/user-control-in-C-Sharp/
I want to create a toggle button similar to this or to this. Animation does not matter to me. I tried to create a toggle button with the code below. However I cannot get it to be smooth curves and edges. I am using windows forms application and a total beginner in C# UI design.
My question is that is it possible to make the curves smooth, or it will still stay like this? I imported the code in the second link, but still the button did not appear smooth.
I also used -
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
Here is full code for the button -
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace MyWorkspace
{
public class ToggleButton : Control
{
#region variables
public enum ButtonState { ON, OFF };
private ButtonState toggleState = ButtonState.OFF;
private Rectangle contentRectangle = Rectangle.Empty;
#endregion
#region properties
public ButtonState ToggleState
{
get
{
return toggleState;
}
set
{
if (toggleState != value)
{
toggleState = value;
Invalidate();
this.Refresh();
}
}
}
#endregion
public ToggleButton() : base()
{
this.MinimumSize = new Size(50, 25);
this.MaximumSize = new Size(50, 25);
contentRectangle = new Rectangle(0, 0, this.Width, this.Height);
this.BackColor = Application.RenderWithVisualStyles ? Color.Azure : this.Parent.BackColor;
}
// Draw the large or small button, depending on the current state.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
Rectangle rect = new Rectangle(0, contentRectangle.Y, contentRectangle.Height, contentRectangle.Height);
GraphicsPath gp = new GraphicsPath();
int d = this.Height;
gp.AddArc(contentRectangle.X, contentRectangle.Y, d, d, 180, 90);
gp.AddArc(contentRectangle.X + contentRectangle.Width - d, contentRectangle.Y, d, d, 270, 90);
gp.AddArc(contentRectangle.X + contentRectangle.Width - d, contentRectangle.Y + contentRectangle.Height - d, d, d, 0, 90);
gp.AddArc(contentRectangle.X, contentRectangle.Y + contentRectangle.Height - d, d, d, 90, 90);
this.Region = new Region(gp);
Rectangle ar2 = new Rectangle(rect.X, contentRectangle.Y, (rect.X + rect.Width / 2) + contentRectangle.Right, contentRectangle.Height);
LinearGradientBrush br;
Rectangle ellipse_rect;
if (toggleState == ButtonState.ON)
{
br = new LinearGradientBrush(ar2, Color.FromArgb(0, 127, 234), Color.FromArgb(96, 174, 241), LinearGradientMode.Vertical);
ellipse_rect = new Rectangle(contentRectangle.Right - (contentRectangle.Height -2),
contentRectangle.Y, contentRectangle.Height - 4, contentRectangle.Height);
}
else
{
br = new LinearGradientBrush(ar2, Color.FromArgb(120, 120, 120), Color.Silver, LinearGradientMode.Vertical);
ellipse_rect = rect;
}
e.Graphics.FillRectangle(br, ar2);
e.Graphics.DrawEllipse(new Pen(Color.Gray, 2f), ellipse_rect);
LinearGradientBrush br2 = new LinearGradientBrush(rect, Color.White, Color.Silver, LinearGradientMode.Vertical);
e.Graphics.FillEllipse(br2, ellipse_rect);
Color c = this.Parent != null ? this.Parent.BackColor : Color.White;
e.Graphics.DrawPath(new Pen(c, 2f), gp);
}
protected override void OnClick(EventArgs e)
{
if (toggleState == ButtonState.ON)
toggleState = ButtonState.OFF;
else
toggleState = ButtonState.ON;
Invalidate();
}
}
}
Please post an image of what your solution looks like, but from what you have described I would guess you do not have anti-aliasing enabled. Here is a MSDN article about how to enable anti-aliasing. If you are going to be changing the look of many controls in your application, you may want to look into Windows Presentation Foundation or the new Universal Windows Platform.
In contrast to Windows Forms, both WPF and UWP are vector based interface layers that are designed using XAML. Because of the way WPF and UWP implement their designing system, it is very easy to completely customize the look and feel of your application. In addition both platforms have built in functionality for animations.
I applied the solution provided by an user to solve the problem, but it's happening another problem. Previously I owned an icon along with the text, but after I used the code described here, my icon no longer appears. What can it be?
And how can I use the icon while using a different color other than the default on tab header?
The solution I used is:
private void tabControl1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
TabPage CurrentTab = tabControl1.TabPages[e.Index];
Rectangle ItemRect = tabControl1.GetTabRect(e.Index);
SolidBrush FillBrush = new SolidBrush(Color.Red);
SolidBrush TextBrush = new SolidBrush(Color.White);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
//If we are currently painting the Selected TabItem we'll
//change the brush colors and inflate the rectangle.
if (System.Convert.ToBoolean(e.State & DrawItemState.Selected))
{
FillBrush.Color = Color.White;
TextBrush.Color = Color.Red;
ItemRect.Inflate(2, 2);
}
//Set up rotation for left and right aligned tabs
if (tabControl1.Alignment == TabAlignment.Left || tabControl1.Alignment == TabAlignment.Right)
{
float RotateAngle = 90;
if (tabControl1.Alignment == TabAlignment.Left)
RotateAngle = 270;
PointF cp = new PointF(ItemRect.Left + (ItemRect.Width / 2), ItemRect.Top + (ItemRect.Height / 2));
e.Graphics.TranslateTransform(cp.X, cp.Y);
e.Graphics.RotateTransform(RotateAngle);
ItemRect = new Rectangle(-(ItemRect.Height / 2), -(ItemRect.Width / 2), ItemRect.Height, ItemRect.Width);
}
//Next we'll paint the TabItem with our Fill Brush
e.Graphics.FillRectangle(FillBrush, ItemRect);
//Now draw the text.
e.Graphics.DrawString(CurrentTab.Text, e.Font, TextBrush, (RectangleF)ItemRect, sf);
//Reset any Graphics rotation
e.Graphics.ResetTransform();
//Finally, we should Dispose of our brushes.
FillBrush.Dispose();
TextBrush.Dispose();
}
You need to paint the Icon yourself also. An example would be to add something like the following after the painting of the tabs Background in you code (i assume that an image list was used here)
int imageLeftOffset = 4;
Point imagePos = new Point(imageLeftOffset, ItemRect.Top + (ItemRect.Height - tabControl1.ImageList.ImageSize.Height + 1) / 2);
tabControl1.ImageList.Draw(e.Graphics, imagePos, CurrentTab.ImageIndex);
You may need to reajust the drawing of the Text so that text and image aren't overlapping.
I'm creating a custom ToolTip that will bold the first line of text if the text is multi-line. I'm also using the VisualStyleRenderer to draw the tool tip correctly with styles. However, when I draw the text (even with TextFormatFlags.VerticalCenter set), it draws at the top of the box. I was going to just bump the bounding box down 2 pixels (which fixed it on Windows 7) but I wasn't 100% sure how portable that would be to another OS. Does anyone know how to draw the text vertically centered correctly?
EDIT: To make this clear, I know this code doesn't bold the first line. I'm trying to first replicate a standard tooltip, and then afterwards do the bolding.
public class BoldedFirstLineToolTip : ToolTip
{
public BoldedFirstLineToolTip()
{
this.OwnerDraw = true;
this.Draw += new DrawToolTipEventHandler(OnDraw);
}
private void OnDraw(object sender, DrawToolTipEventArgs e)
{
// Try to draw using the visual style renderer.
if (VisualStyleRenderer.IsElementDefined(VisualStyleElement.ToolTip.Standard.Normal))
{
var renderer = new VisualStyleRenderer(VisualStyleElement.ToolTip.Standard.Normal);
renderer.DrawBackground(e.Graphics, e.Bounds);
var b = e.Bounds;
// b.Y + 2 // This works when using e.Graphics.DrawString.
renderer.DrawText(e.Graphics, b, e.ToolTipText, false /*drawDisabled*/,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
}
else
{
// Fall back to non-visual style drawing.
e.DrawBackground();
e.DrawBorder();
e.DrawText();
}
}
}
I've decided to just use padding fixes. I've provided my full solution below. I tested on both XP and Windows 7.
public class BoldedFirstLineToolTip : ToolTip
{
public BoldedFirstLineToolTip()
{
this.OwnerDraw = true;
this.Draw += new DrawToolTipEventHandler(OnDraw);
}
private void OnDraw(object sender, DrawToolTipEventArgs e)
{
// Try to draw using the visual style renderer.
if (VisualStyleRenderer.IsSupported && VisualStyleRenderer.IsElementDefined(VisualStyleElement.ToolTip.Standard.Normal))
{
var bounds = e.Bounds;
var renderer = new VisualStyleRenderer(VisualStyleElement.ToolTip.Standard.Normal);
renderer.DrawBackground(e.Graphics, bounds);
var color = renderer.GetColor(ColorProperty.TextColor);
var text = e.ToolTipText;
using (var textBrush = new SolidBrush(renderer.GetColor(ColorProperty.TextColor)))
using (var font = e.Font)
{
// Fix the positioning of the bounds for the text rectangle.
var rendererBounds = new Rectangle(e.Bounds.X + 6, e.Bounds.Y + 2, e.Bounds.Width - 6 * 2, e.Bounds.Height - 2 * 2);
if (!text.Contains('\n'))
{
renderer.DrawText(e.Graphics, rendererBounds, text);
}
else
{
var lines = text.Split('\n').Select(l => l.Trim());
var first = lines.First();
var otherLines = Environment.NewLine + String.Join(Environment.NewLine, lines.Skip(1).ToArray());
// Draw the first line.
using (var boldFont = new Font(font, FontStyle.Bold))
{
e.Graphics.DrawString(first, boldFont, textBrush, rendererBounds.X - 1, rendererBounds.Y - 1);
}
renderer.DrawText(e.Graphics, rendererBounds, otherLines, false /*drawDisabled*/, TextFormatFlags.Left);
}
}
}
else
{
// Fall back to non-visual style drawing.
e.DrawBackground();
e.DrawBorder();
using (var sf = new StringFormat())
{
sf.LineAlignment = StringAlignment.Center;
e.Graphics.DrawString(e.ToolTipText, SystemFonts.DialogFont, Brushes.Black, e.Bounds, sf);
}
}
}
}