问题
I have an WinForms app built with vb .net to which I've added a WPF user control. The WPF user control consists of only a progressbar. I can drag the WPF control from the toolbax and add it to the Main Form in WinForms vb .net. But I don't know how to let my WinForms app dynamically set the value for the WPF progress bar. Anyway I can dynamically set the WPF control progress bar's value from my WinForms app?
Note: The reason Im using WPF progress bar instead of using WinForms progress bar is so that I can have blue colored progress bar in my WinForms app.
回答1:
Since it may not be as straightforward as it may look like on paper, here's a custom ProgressBar that allows to set the Color of the bar and also change its style on the fly.
The ProgressBarStyle
property sets the current style: the BarStyle.Standard
style uses the ProgressBarRenderer.DrawHorizontalBar() method to draw its background, while the BarStyle.Flat
selects the Parent.BackColor
as background color and uses a fixed white border to draw the ProgressBar bounds and SystemColors.Highlight as the bar color. Of course it can be changed to support any other color and the Standard style.
The StringFormat class is used to center the text of the ProgressBar (in Standard
style only. This can also be easily changed), setting both Horizontal and Vertical alignment to StringAlignment.Center
.
The text color changes automatically to adapt to the Brightness of the ProgressBar color (it's just a simple adjustment, the HSL
value on its own cannot always determine what text color better fits a background color).
Some magic values are just offsets used to adapt the drawing rectangles to the shapes designed by ProgressBarRenderer
This is how it works:
VB.Net version of the Custom Control:
Imports System.ComponentModel
Imports System.Drawing.Drawing2D
Imports System.Drawing
Imports System.Windows.Forms
<DesignerCategory("Code")>
Public Class ProgressBarCustomColor
Inherits ProgressBar
Private m_ParentBackColor As Color = SystemColors.Window
Private m_ProgressBarStyle As BarStyle = BarStyle.Standard
Private m_FlatBorderColor As Color = Color.White
Public Sub New()
SetStyle(ControlStyles.AllPaintingInWmPaint Or
ControlStyles.UserPaint Or
ControlStyles.OptimizedDoubleBuffer, True)
End Sub
Public Enum BarStyle
Standard
Flat
End Enum
Public Property ProgressBarStyle As BarStyle
Get
Return m_ProgressBarStyle
End Get
Set
m_ProgressBarStyle = Value
If DesignMode Then Me.Parent?.Refresh()
End Set
End Property
Public Property FlatBorderColor As Color
Get
Return m_FlatBorderColor
End Get
Set
m_FlatBorderColor = Value
If DesignMode Then Me.Parent?.Refresh()
End Set
End Property
Protected Overrides Sub OnParentChanged(e As EventArgs)
MyBase.OnParentChanged(e)
m_ParentBackColor = If(Me.Parent IsNot Nothing, Me.Parent.BackColor, SystemColors.Window)
End Sub
Protected Overrides Sub OnPaintBackground(e As PaintEventArgs)
MyBase.OnPaintBackground(e)
Dim rect = Me.ClientRectangle
If m_ProgressBarStyle = BarStyle.Standard Then
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, rect)
Dim baseColor = Color.FromArgb(240, Me.BackColor)
Dim highColor = Color.FromArgb(160, baseColor)
Using baseBrush = New SolidBrush(baseColor),
highBrush = New SolidBrush(highColor)
e.Graphics.FillRectangle(highBrush, 1, 2, rect.Width, 9)
e.Graphics.FillRectangle(baseBrush, 1, 7, rect.Width, rect.Height - 1)
End Using
Else
Using pen = New Pen(m_FlatBorderColor, 2),
baseBrush = New SolidBrush(m_ParentBackColor)
e.Graphics.FillRectangle(baseBrush, 0, 0, rect.Width - 1, rect.Height - 1)
e.Graphics.DrawRectangle(pen, 1, 1, Me.ClientSize.Width - 2, Me.ClientSize.Height - 2)
End Using
End If
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim rect = New RectangleF(PointF.Empty, Me.ClientSize)
rect.Width = CType(rect.Width * (CType(Me.Value, Single) / Me.Maximum), Integer)
rect.Size = New SizeF(rect.Width - 2, rect.Height)
Dim hsl As Single = Me.ForeColor.GetBrightness()
If m_ProgressBarStyle = BarStyle.Standard Then DrawStandardBar(e.Graphics, rect, hsl)
If m_ProgressBarStyle = BarStyle.Flat Then DrawFlatBar(e.Graphics, rect, hsl)
End Sub
Private Sub DrawStandardBar(g As Graphics, rect As RectangleF, hsl As Single)
g.SmoothingMode = SmoothingMode.AntiAlias
g.CompositingQuality = CompositingQuality.HighQuality
Dim baseColor = Color.FromArgb(240, Me.ForeColor)
Dim highColor = Color.FromArgb(160, baseColor)
Using baseBrush = New SolidBrush(baseColor),
highBrush = New SolidBrush(highColor),
sf = New StringFormat(StringFormatFlags.MeasureTrailingSpaces)
sf.LineAlignment = StringAlignment.Center
sf.Alignment = StringAlignment.Center
g.FillRectangle(highBrush, 1, 2, rect.Width, 9)
g.FillRectangle(baseBrush, 1, 7, rect.Width, rect.Height - 1)
g.DrawString($"{Me.Value} %", Me.Parent.Font,
If(hsl > 0.49F, Brushes.Black, Brushes.White), Me.ClientRectangle, sf)
End Using
End Sub
Private Sub DrawFlatBar(g As Graphics, rect As RectangleF, hsl As Single)
Using baseBrush = New SolidBrush(SystemColors.Highlight)
g.FillRectangle(baseBrush, 2, 2, rect.Width - 2, rect.Height - 4)
End Using
End Sub
End Class
C# version:
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
[DesignerCategory("Code")]
public class ProgressBarCustomColor : ProgressBar
{
private Color m_ParentBackColor = SystemColors.Window;
private Color m_FlatBorderColor = Color.White;
private BarStyle m_ProgressBarStyle = BarStyle.Standard;
public ProgressBarCustomColor()
{
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
}
public enum BarStyle { Standard, Flat }
public BarStyle ProgressBarStyle {
get => m_ProgressBarStyle;
set {
m_ProgressBarStyle = value;
if (DesignMode) this.Parent?.Refresh();
}
}
public Color FlatBorderColor {
get => m_FlatBorderColor;
set {
m_FlatBorderColor = value;
if (DesignMode) this.Parent?.Refresh();
}
}
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
m_ParentBackColor = this.Parent?.BackColor ?? SystemColors.Window;
}
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
var rect = this.ClientRectangle;
if (m_ProgressBarStyle == BarStyle.Standard) {
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, rect);
var baseColor = Color.FromArgb(240, this.BackColor);
var highColor = Color.FromArgb(160, baseColor);
using (var baseBrush = new SolidBrush(baseColor))
using (var highBrush = new SolidBrush(highColor)) {
e.Graphics.FillRectangle(highBrush, 1, 2, rect.Width, 9);
e.Graphics.FillRectangle(baseBrush, 1, 7, rect.Width, rect.Height - 1);
}
}
else {
using (var pen = new Pen(m_FlatBorderColor, 2))
using (var baseBrush = new SolidBrush(m_ParentBackColor)) {
e.Graphics.FillRectangle(baseBrush, 0, 0, rect.Width - 1, rect.Height - 1);
e.Graphics.DrawRectangle(pen, 1, 1, this.ClientSize.Width - 2, this.ClientSize.Height - 2);
}
}
}
protected override void OnPaint(PaintEventArgs e)
{
var rect = new RectangleF(PointF.Empty, this.ClientSize);
rect.Width = (int)(rect.Width * ((float)this.Value / this.Maximum));
rect.Size = new SizeF(rect.Width - 2, rect.Height);
float hsl = this.ForeColor.GetBrightness();
if (m_ProgressBarStyle == BarStyle.Standard) DrawStandardBar(e.Graphics, rect, hsl);
if (m_ProgressBarStyle == BarStyle.Flat) DrawFlatBar(e.Graphics, rect, hsl);
}
private void DrawStandardBar(Graphics g, RectangleF rect, float hsl)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.CompositingQuality = CompositingQuality.HighQuality;
var baseColor = Color.FromArgb(240, this.ForeColor);
var highColor = Color.FromArgb(160, baseColor);
using (var baseBrush = new SolidBrush(baseColor))
using (var highBrush = new SolidBrush(highColor))
using (var sf = new StringFormat(StringFormatFlags.MeasureTrailingSpaces)) {
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
g.FillRectangle(highBrush, 1, 2, rect.Width, 9);
g.FillRectangle(baseBrush, 1, 7, rect.Width, rect.Height - 1);
g.DrawString($"{this.Value} %", this.Parent.Font,
hsl > .49f ? Brushes.Black : Brushes.White, this.ClientRectangle, sf);
}
}
private void DrawFlatBar(Graphics g, RectangleF rect, float hsl)
{
using (var baseBrush = new SolidBrush(SystemColors.Highlight)) {
g.FillRectangle(baseBrush, 2, 2, rect.Width - 2, rect.Height - 4);
}
}
}
来源:https://stackoverflow.com/questions/62043526/control-wpf-progress-bar-from-winforms-app