I've searched and not found this question answered on SO, so I'm asking it here directly.
Does anyone have a clean method to create an infinitely scrolling gradient background? (the gradient shifts, so you can follow the colors from one side/corner to the other)
I've done this in VB like 15 years ago, but it's been so long since I touched VB it's all greek to me.
Assuming someone has done something like this in C# before-- Think demo scene kind of animation.
The VB code snippet is from a working form background I did many years ago, it doesn't scroll so much as bounce back and forth from edge to edge.
Private Sub picCanvas_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
Dim rect As New Rectangle(-10, -10, Me.ClientSize.Width + 20, Me.ClientSize.Height + 20)
Dim halfw As Integer = CType(Me.ClientSize.Width, Integer)
Dim br As New LinearGradientBrush(New Point(-120, 500), New Point(Me.ClientSize.Width + 120, 0), Color.Red, Color.Blue)
Dim color_blend As New ColorBlend
color_blend.Colors = New Color() {Color.Black, Color.Purple, Color.Teal, Color.Purple, Color.Black}
m_Theta += m_Delta
color_blend.Positions = New Single() {0, 0.01, m_Theta, 0.99, 1}
br.InterpolationColors = color_blend
e.Graphics.FillRectangle(br, rect)
br.Dispose()
If (m_Theta > 0.75) Or (m_Theta < 0.25) Then m_Delta = -m_Delta
End Sub
I would greatly appreciate any help in getting this kind of thing to work in WinForms using only GDI and brushes, no XML or anything please ^^/
I'm not exactly sure this is what you're trying to do, anyway, from the semi-pseudo code presented here, it appears you want to shift the position of a gradient fill along an axis.
It appears the fill is meant to be inclined, so I've added means to determine a rotation angle.
I've kept the LinearGradientBrush to generate the blended fill, though the combination of GraphicsPath and PathGradientBrush is probably more flexible.
To move the gradient fill, I've used a standard System.Windows.Forms.Timer. It's used to translate the fill, incrementing a value that is then set to the translation components of a Matrix in the OnPaint override of a double-buffered Form used as canvas (of course, you can use a PictureBox instead)
The Matrix is also used to rotate the fill, in case it's needed
The Timer's Tick handler also verifies other conditions (bool Fields), that can be used to alter the fill:
useThetaShift enables semi-dynamic motions of the blend intervals (the Position Property)
useTriangular enables and alternate blending feature, generated by the SetBlendTriangularShape() method, which considers only the starting and ending Colors of the LinearGradientBrush and defines the center point of the Colors' fall-off
The sample Form shown here can also be set to auto-scroll, the blending is extended to the DisplayRectangle
The blend is animated also when a modal Dialog is shown (you mentioned an About Window...)
internal class SomeForm : Form {
private System.Windows.Forms.Timer gradientTimer = null;
public SomeForm() {
InitializeComponent();
if (components is null) components = new Container();
ResizeRedraw = true;
startColor = blendColors[0];
meanColor = blendColors[1];
endColor = blendColors[blendColors.Length - 1];
gradientTimer = new System.Windows.Forms.Timer(components) { Interval = 100 };
gradientTimer.Tick += GradientTimer_Tick;
gradientTimer.Start();
}
float theta = .0f;
float delta = .005f;
float tringularShift = .25f;
float tringularShiftDelta = .015f;
float speed = 7.5f;
float rotation = 0f;
private Color[] blendColors = new[]{
Color.Black, Color.Purple, Color.Teal, Color.Purple, Color.Black
};
Color startColor = Color.Empty;
Color endColor = Color.Empty;
Color meanColor = Color.Empty;
PointF translateMx = PointF.Empty;
bool useThetaShift = false;
bool useTriangular = false;
private void GradientTimer_Tick(object sender, EventArgs e)
{
if (useTriangular) {
tringularShift += tringularShiftDelta;
tringularShift = Math.Max(Math.Min(tringularShift, 1.0f), .35f);
if ((tringularShift >= 1.0f) | (tringularShift <= .35f)) tringularShiftDelta*= -1;
}
if (useThetaShift) {
theta += delta;
theta = Math.Max(Math.Min(theta, .15f), 0f);
if ((theta >= .15f) | (theta <= 0f)) delta*= -1;
}
translateMx = PointF.Add(translateMx, new SizeF(speed, speed));
if (Math.Abs(translateMx.X) >= short.MaxValue) translateMx = PointF.Empty;
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
var display = DisplayRectangle;
using (var mx = new Matrix(1f, 0f, 0f, 1f, translateMx.X, translateMx.Y))
using (var brush = new LinearGradientBrush(display, startColor, endColor, rotation)) {
var colorBlend = new ColorBlend(blendColors.Length) {
Colors = blendColors,
Positions = new float[] { .0f, .25f + theta, .5f + theta, .75f + theta, 1.0f },
};
brush.InterpolationColors = colorBlend;
mx.Rotate(rotation);
brush.Transform = mx;
if (useTriangular) brush.SetBlendTriangularShape(.5f, tringularShift);
e.Graphics.FillRectangle(brush, display);
}
base.OnPaint(e);
}
protected override void OnFormClosing(FormClosingEventArgs e) {
// Move to OnFormClosed() if this action can be canceled
gradientTimer.Stop();
base.OnFormClosing(e);
}
}
I cannot post an animation here, because of the size. You can see how it work directly on Imgur:
Animated LinearGradientPath
Related
I am new at stackoverflow so I hope I am not opening a question that has already been answered somewhere already.
I am trying to achieve this effect of displaying some objects exactly as seen on this video:
visual example
This example is from the game Binding of Isaac.
In order to do so I figured as much as I would have to define a ellipse or circle in c# so that I can place objects on the circle's periferi. I would do this by simply dividing my amount of display objects that we will call n with 360* from here I would simply create n points on the circle and make the display objects rotate along the circles periferi until they reach their destination point, in the meantime I just resize the scale as they move.
My question I need answered to start this though is how I should define the ellipse. I've found tutorials on drawing it but I don't really need the visual representation of the ellipse but rather the code that defines the ellipse so I can move these display objects in a circular/ellipse motion.
Thank you.
What you want is the perspective projection of a circle. This is achieved below by defining a circle on the XZ plane (rotation about Y) and viewing it from a vantage point translated in the Y axis a bit.
I was able to create a quick sample that mimics this behavior. I had to create a continuously updating form, although my approach was heavy-handed, I could have done it with a Timer.
I am using System.Numerics to generate the 3D geometry, and apply the rotation and view transformations.
Code
public partial class RunningForm1 : Form
{
float posAngle;
Queue<PointF> tail;
#region Windows API - User32.dll
[StructLayout(LayoutKind.Sequential)]
public struct WinMessage
{
public IntPtr hWnd;
public Message msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public System.Drawing.Point p;
}
[System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
[DllImport("User32.dll", CharSet = CharSet.Auto)]
static extern bool PeekMessage(out WinMessage msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
#endregion
public RunningForm1()
{
InitializeComponent();
//Initialize the machine
posAngle = 0f;
tail = new Queue<PointF>();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
pictureBox1.Paint += pic_Paint;
pictureBox1.SizeChanged += pic_SizeChanged;
MainLoop();
}
void UpdateMachine()
{
posAngle += 0.002f;
pictureBox1.Refresh();
}
#region Main Loop
public void MainLoop()
{
// Hook the application's idle event
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
//System.Windows.Forms.Application.Run(TrackForm);
}
private void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
UpdateMachine();
}
}
private bool AppStillIdle
{
get
{
WinMessage msg;
return !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
}
}
#endregion
private void pic_SizeChanged(object sender, EventArgs e)
{
pictureBox1.Refresh();
}
private void pic_Paint(object sender, PaintEventArgs e)
{
// Show FPS counter
// Draw the machine
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
var s = Math.Min(ClientSize.Width, ClientSize.Height) / 2f;
var view = Matrix4x4.CreatePerspective(1f, 1f, 1f, 10f);
view = Matrix4x4.Multiply(view, Matrix4x4.CreateTranslation(0, 0.24f, 0));
var q = Quaternion.CreateFromAxisAngle(Vector3.UnitY, posAngle);
var pts = new Vector3[] {
new Vector3(s/2, 0, 0),
new Vector3(s/2, -20f, 0),
new Vector3(s/2, -20f, -18f),
new Vector3(s/2, -20f, 18f),
new Vector3(s/2, -40f, 18f),
new Vector3(s/2, -40f, -18f),
new Vector3(s/2, -20f, -18f),
new Vector3(s/2, -20f, 0f),
};
for (int i = 0; i < pts.Length; i++)
{
pts[i] = Vector3.Transform(pts[i], q);
pts[i] = Vector3.Transform(pts[i], view);
}
e.Graphics.TranslateTransform(ClientSize.Width / 2f, ClientSize.Height / 2f);
using (var fill = new SolidBrush(Color.Gray))
{
foreach (var pt in tail.Reverse())
{
e.Graphics.FillEllipse(fill, pt.X - 4, pt.Y - 4, 8, 8);
fill.Color = Color.FromArgb(Math.Max(0, fill.Color.A-1), fill.Color);
}
}
var px = pts.Select((p) => new PointF(p.X, p.Y)).ToArray();
e.Graphics.FillPolygon(SystemBrushes.ActiveCaption, px);
e.Graphics.DrawPolygon(Pens.Black, px);
e.Graphics.FillEllipse(Brushes.Black, px[0].X - 4, px[0].Y - 4, 8, 8);
tail.Enqueue(px[0]);
while (tail.Count >= 255)
{
tail.Dequeue();
}
}
}
I added a tail object that draws a tail for a better motion effect.
Let center coordinate is (CX, CY), scene half-width is R, and vertical contraction (ratio of vertical elipse axis and horizontal one) is V. Number of objects is N
So you can calculate coordinates of object centers at the circle and make vertical contraction.
Angle = 2 * Math.Pi / N + Shift
X[i] = CX + R * Cos(Angle)
Y[i] = CY + V * R * Sin(Angle)
where i is object number and Shift is parameter of carousel rotation (in range 0..2*Pi)
Perhaps for exact positioning you have to add -ObjWidth/2, -ObjHeight/2 (if you drawing dunction takes left top corner rather than center).
Also to provide proper Z-order you have to draw "back" objects first
according to angle range.
I tried to find information on how to use a radial gauge in a windows form report.
I really can't find anything on this. Not sure if there is not much info on this.
Is there anyone who can get me some info on this? How would I be able to use a value from a text box in a report viewer to show this on a radial gauge and even using a track bar to get some idea how to use it.
Even if getting a small example to build on this would be really great :-)
You have several options even without any external stuff.
You can draw a gauge needle onto a gauge image. Here is an example.
You can draw the needle onto an image by either calulating the outer point and drawing a line to the center or by rotating the canvas as in the link.
Or you can use the built-in MSChart control and its Doughnut charttype.
Here is an example for this:
The code is simple:
first we set up the chart by adding three DataPoints; then we code a function to update the value.
The points are for
the open, transparent part
the value of the gauge in green
the rest of the scale in red
For testing I use these variables:
double valMin = 0; // user data minimum
double valMax = 100; // ~ maximum
float angle = 60; // open pie angle at the bottom
string valFmt = "{0}°"; // a format string
My current value is pulled from a trackbar.
Setup code:
void setupChartGauge(double val, double vMin, double vMax, float a)
{
valMin = vMin;
valMax = vMax;
angle = a;
Series s = gaugeChart.Series[0];
s.ChartType = SeriesChartType.Doughnut;
s.SetCustomProperty("PieStartAngle", (90 - angle/2) + "");
s.SetCustomProperty("DoughnutRadius", "10");
s.Points.Clear();
s.Points.AddY(angle);
s.Points.AddY(0);
s.Points.AddY(0);
setChartGauge(0);
s.Points[0].Color = Color.Transparent;
s.Points[1].Color = Color.Chartreuse;
s.Points[2].Color = Color.Tomato;
}
and setting a value:
void setChartGauge(double val)
{
Series s = gaugeChart.Series[0];
double range = valMax - valMin;
double aRange = 360 - angle;
double f = aRange / range;
double v1 = val * f;
double v2 = (range - val) * f;
s.Points[1].YValues[0] = v1;
s.Points[2].YValues[0] = v2;
gaugeChart.Titles[0].Text = String.Format(valFmt, val);
gaugeChart.Refresh();
}
I have added minimal styling:
The Chart has a Title docked centered bottom which I also update
I have set a back color
I paint an inner circle in the Paint event like so:
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle r = chart1.ClientRectangle;
r.Inflate(-10, -10);
using (SolidBrush brush = new SolidBrush(Color.FromArgb(55, Color.Beige)))
e.Graphics.FillEllipse(brush, r);
Note that Pie and Doughnut charts can have only one series. To show a 2nd one you would need an overlapping 2nd chartarea with the exact same Position.
There are infinite ways to draw stuff, both from scratch or updating the MsChart control. Various gradient brushes come to mind. Adding ticks and a needle will involve rotation code, which basically consists of 3 lines of code..
Update:
Here is an example of drawing a gauge needle.
The code should be called from a Paint event and should pass out a valid Graphics object (read: e.Graphics), a float for the data value, a Rectangle to place the gauge in, a Color and a float for the percentage of the rectangle size to use.
private void drawNeedle(Graphics g, float val, Rectangle r, Color c, float length)
{
Point pc = new Point(r.X + r.Width / 2, r.Y + r.Height / 2);
Point p2 = new Point((int)( pc.X + r.Width / 2 * length / 100f), pc.Y);
using (Pen pen = new Pen(c, 3f)
{ StartCap = LineCap.RoundAnchor, EndCap = LineCap.ArrowAnchor })
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TranslateTransform(pc.X, pc.Y);
g.RotateTransform(val - (270 - angle / 2));
g.TranslateTransform(-pc.X, -pc.Y);
g.DrawLine(pen, pc, p2);
g.ResetTransform();
}
}
You can use it in any control that support owner-drawing including the chart..:
drawNeedle(e.Graphics, (float)gaugeChart.Series[0].Points[1].YValues[0], r, Color.White, 70f);
Here is a simple example with a TrackBar:
private Syncfusion.Windows.Forms.Gauge.RadialGauge radialGauge1;
private System.Windows.Forms.TrackBar trackBar1;
private Syncfusion.Windows.Forms.Gauge.Needle needle1;
private void InitializeComponent()
{
this.needle1 = new Syncfusion.Windows.Forms.Gauge.Needle();
this.needle1.Value = 0F;
this.trackBar1 = new System.Windows.Forms.TrackBar();
this.radialGauge1 = new Syncfusion.Windows.Forms.Gauge.RadialGauge();
this.trackBar1.Value = (int) needle1.Value;
this.radialGauge1.EnableCustomNeedles = true;
this.radialGauge1.NeedleCollection.Add(needle1);
this.radialGauge1.Size = new System.Drawing.Size(230, 230);
this.radialGauge1.TabIndex = 0;
this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll);
}
And a scroll event which sync between gauge and trackBar:
private void trackBar1_Scroll(object sender, EventArgs e)
{
needle1.Value = trackBar1.Value;
}
I am having some trouble with a custom circular progress bar control. I am trying to overlap the two of them at the lower right corner. It has a transparent background, which obviously in WinForms is showing the background, but has no effect on each other.
Here is what I am seeing:
I have been researching on stackoverflow, and have found a few answers to people having this issue with custom picturebox controls. Most of the solutions, seem to have no effect on the circular progress bar control. Some of the solutions I have tried is.
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
I also have the code on the custom control for allowing transparent backgrounds. Obviously, as I stated, this does not effect overlapping controls.
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
There is also a TransparentControl solution on stackoverflow which I saw people using. I have created the control, but either have no idea how to use it, or it doesn't work in my situation. Here is the code from that control.
public class TransparentControl : Panel
{
public bool drag = false;
public bool enab = false;
private int m_opacity = 100;
private int alpha;
public TransparentControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Opaque, true);
this.BackColor = Color.Transparent;
}
public int Opacity
{
get
{
if (m_opacity > 100)
{
m_opacity = 100;
}
else if (m_opacity < 1)
{
m_opacity = 1;
}
return this.m_opacity;
}
set
{
this.m_opacity = value;
if (this.Parent != null)
{
Parent.Invalidate(this.Bounds, true);
}
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | 0x20;
return cp;
}
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle bounds = new Rectangle(0, 0, this.Width - 1, this.Height - 1);
Color frmColor = this.Parent.BackColor;
Brush bckColor = default(Brush);
alpha = (m_opacity * 255) / 100;
if (drag)
{
Color dragBckColor = default(Color);
if (BackColor != Color.Transparent)
{
int Rb = BackColor.R * alpha / 255 + frmColor.R * (255 - alpha) / 255;
int Gb = BackColor.G * alpha / 255 + frmColor.G * (255 - alpha) / 255;
int Bb = BackColor.B * alpha / 255 + frmColor.B * (255 - alpha) / 255;
dragBckColor = Color.FromArgb(Rb, Gb, Bb);
}
else
{
dragBckColor = frmColor;
}
alpha = 255;
bckColor = new SolidBrush(Color.FromArgb(alpha, dragBckColor));
}
else
{
bckColor = new SolidBrush(Color.FromArgb(alpha, this.BackColor));
}
if (this.BackColor != Color.Transparent | drag)
{
g.FillRectangle(bckColor, bounds);
}
bckColor.Dispose();
g.Dispose();
base.OnPaint(e);
}
protected override void OnBackColorChanged(EventArgs e)
{
if (this.Parent != null)
{
Parent.Invalidate(this.Bounds, true);
}
base.OnBackColorChanged(e);
}
protected override void OnParentBackColorChanged(EventArgs e)
{
this.Invalidate();
base.OnParentBackColorChanged(e);
}
}
Any assistance would be appreciated. This has been driving me nuts for hours. Thanks :)
UPDATE 1: I tried using the following code snippet from examples posted below. This yielded the same results. I still have that blank space between the circular progress bars (as seen in the picture).
Parent.Controls.Cast<Control>()
.Where(c => Parent.Controls.GetChildIndex(c) > Parent.Controls.GetChildIndex(this))
.Where(c => c.Bounds.IntersectsWith(this.Bounds))
.OrderByDescending(c => Parent.Controls.GetChildIndex(c))
.ToList()
.ForEach(c => c.DrawToBitmap(bmp, c.Bounds));
Still stumped. :(
UPDATE 2: I tried setting the front circularprogressbar to use the back circularprogressbar as it's parent in the FormLoad. That didn't work out either. It made them transparent to each other, but cut off any part of the top circularprogressbar that wasn't within' the boundaries of the back.
var pts = this.PointToScreen(circularprogressbar1.Location);
pts = circularprogressbar2.PointToClient(pts);
circularprogressbar1.Parent = circularprogressbar2;
circularprogressbar1.Location = pts;
I'm going to give you just a couple of suggestions on how to proceed.
Start off with this bare-bones transparent control (TransparentPanel).
This class is derived from Panel. That's the first choice to make: is Panel the right control to inherit from/extend for this task? Maybe it is, maybe not.
For example, a Panel is a container. Do you need the features of a container, here? Container means a lot. It inherits ScrollableControl and has ContainerControl among its Window styles. It comes with a baggage already.
You could opt for a Label instead, it's light-weight. Or build a UserControl.
I don't think there's an absolute best choice. It depends of what this custom control is used for. You need to try it out.
Note:
To create the rotation effect with the code shown here, you need the TransparentPanel Control shown below, it won't work the same way drawing on the surface of a standard Control.
This Control generates sort of a persistence in the drawn shapes, which won't exist using another type of Control as canvas (not without tweaking it heavily, that is).
class TransparentPanel : Panel
{
internal const int WS_EX_TRANSPARENT = 0x00000020;
public TransparentPanel() => InitializeComponent();
protected void InitializeComponent()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.Opaque |
ControlStyles.ResizeRedraw |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
}
protected override CreateParams CreateParams
{
get {
var cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}
}
Other notes:
Here, ControlStyles.SupportsTransparentBackColor is set explicitly. The Panel class already supports this. It's specified anyway because it gives the idea of what this custom control is for just reading at its constructor.
Also, ControlStyles.OptimizedDoubleBuffer is set to false.
This prevents the System to interfere in any way with the painting of the control. There's no caching, the Custom Control is painted new when it's Invalidated. The container Form should preferably have its DoubleBuffer property set to true, but you might want test it without, to see if there's a difference.
This Custom Control (not to be confused with a UserControl) is completely transparent. It doesn't draw its background. But you can paint anything on its surface.
Take the links posted before:
This Translucent Label (no BackGround painting, disabled DoubleDuffering)
Reza Aghaei's transparent Panel (using Opacity in a different way)
TaW's Grid Panel (Color.Transparent and DoubleBuffer)
These notes: Reasons for why a WinForms label does not want to be transparent?
4 different ways to get to the same result. Which one to choose depends on the context/destination.
A design-time advice: when you are testing a custom control functionalities, remember to always rebuild the project. It can happen that a CustomControl, droppen on a Form from the Toolbox, is not updated with the new changes when the project is run.
Also, if you add or remove properties, you need to delete the control, rebuild and drop a new one on the Form.
If you don't, there's a really good chance that your modification/addition are completely ignored and you keep on testing features that never get into play.
An example, using 2 overlapping custom controls.
(using the bare-bones custom TransparentPanel)
This is the test code used to generate these drawings:
Create a new Custom Control using the TransparentPanel class shown before:
Drop two TransparentPanel objects on a test Form
Assign to TransparentPanel1 and TransparentPanel2 the transparentPanel1_Paint and transparentPanel2_Paint event handlers.
Overlap the two transparent Panels, making sure you don't nest them by mistake.
Adapt the rest of the code (you need just a Button, here named btnRotate, assign the btnRotate_Click handler)
private System.Windows.Forms.Timer RotateTimer = null;
private float RotationAngle1 = 90F;
private float RotationAngle2 = 0F;
public bool RotateFigures = false;
public form1()
{
InitializeComponent();
RotateTimer = new Timer();
RotateTimer.Interval = 50;
RotateTimer.Enabled = false;
RotateTimer.Tick += new EventHandler(this.RotateTick);
}
protected void RotateTick(object sender, EventArgs e)
{
RotationAngle1 += 10F;
RotationAngle2 += 10F;
transparentPanel1.Invalidate();
transparentPanel2.Invalidate();
}
private void btnRotate_Click(object sender, EventArgs e)
{
RotateTimer.Enabled = !RotateTimer.Enabled;
if (RotateTimer.Enabled == false)
{
RotateFigures = false;
RotationAngle1 = 90F;
RotationAngle2 = 0F;
}
else
{
RotateFigures = true;
}
}
private void transparentPanel1_Paint(object sender, PaintEventArgs e)
{
if (!RotateFigures) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
Rectangle rect = transparentPanel1.ClientRectangle;
Rectangle rectInner = rect;
using (Pen transpPen = new Pen(transparentPanel1.Parent.BackColor, 10))
using (Pen penOuter = new Pen(Color.SteelBlue, 8))
using (Pen penInner = new Pen(Color.Teal, 8))
using (Matrix m1 = new Matrix())
using (Matrix m2 = new Matrix())
{
m1.RotateAt(-RotationAngle1, new PointF(rect.Width / 2, rect.Height / 2));
m2.RotateAt(RotationAngle1, new PointF(rect.Width / 2, rect.Height / 2));
rect.Inflate(-(int)penOuter.Width, -(int)penOuter.Width);
rectInner.Inflate(-(int)penOuter.Width * 3, -(int)penOuter.Width * 3);
e.Graphics.Transform = m1;
e.Graphics.DrawArc(transpPen, rect, -4, 94);
e.Graphics.DrawArc(penOuter, rect, -90, 90);
e.Graphics.ResetTransform();
e.Graphics.Transform = m2;
e.Graphics.DrawArc(transpPen, rectInner, 190, 100);
e.Graphics.DrawArc(penInner, rectInner, 180, 90);
}
}
private void transparentPanel2_Paint(object sender, PaintEventArgs e)
{
if (!RotateFigures) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
Rectangle rect = transparentPanel2.ClientRectangle;
Rectangle rectInner = rect;
using (Pen transpPen = new Pen(transparentPanel2.Parent.BackColor, 10))
using (Pen penOuter = new Pen(Color.Orange, 8))
using (Pen penInner = new Pen(Color.DarkRed, 8))
using (Matrix m1 = new Matrix())
using (Matrix m2 = new Matrix())
{
m1.RotateAt(RotationAngle2, new PointF(rect.Width / 2, rect.Height / 2));
m2.RotateAt(-RotationAngle2, new PointF(rect.Width / 2, rect.Height / 2));
rect.Inflate(-(int)penOuter.Width, -(int)penOuter.Width);
rectInner.Inflate(-(int)penOuter.Width * 3, -(int)penOuter.Width * 3);
e.Graphics.Transform = m1;
e.Graphics.DrawArc(transpPen, rect, -4, 94);
e.Graphics.DrawArc(penOuter, rect, 0, 90);
e.Graphics.ResetTransform();
e.Graphics.Transform = m2;
e.Graphics.DrawArc(transpPen, rectInner, 190, 100);
e.Graphics.DrawArc(penInner, rectInner, 180, 90);
}
}
I'm newbie to C# and I'm trying to do a simple application which have elements that move a lot on the screen. After some research I found a code that moved a button. The problem is the button returns to it's original state (although invisible). When I click the button it moves outside the screen (just as I wanted), but when I click it back (it should do the reverse animation) but instead, it just magically appears on the screen again.
I also tried to make it change position after the animation ended, but that didn't work either. Here's my code:
private void ButtonOnClick(object sender, RoutedEventArgs e)
{
if (nextSlideMoving)
return;
nextSlideMoving = true;
KinectTileButton target = (KinectTileButton)sender;
Vector offset = VisualTreeHelper.GetOffset(target);
if (nextSlideHidden)
moveAnimation(target, 0, offset.Y);
else
moveAnimation(target, -target.ActualWidth, offset.Y);
}
private void moveAnimation(KinectTileButton target, double newX, double newY)
{
Vector offset = VisualTreeHelper.GetOffset(target);
var top = offset.Y;
var left = offset.X;
TranslateTransform trans = new TranslateTransform();
target.RenderTransform = trans;
DoubleAnimation anim1 = new DoubleAnimation(0, newY - top, TimeSpan.FromSeconds(0.5));
trans.BeginAnimation(TranslateTransform.YProperty, anim1);
DoubleAnimation anim2 = new DoubleAnimation(0, newX - left, TimeSpan.FromSeconds(0.5));
anim2.Completed += new EventHandler(finishedAnimation);
trans.BeginAnimation(TranslateTransform.XProperty, anim2);
}
public void finishedAnimation(Object sender, EventArgs e)
{
nextSlideMoving = false;
nextSlideHidden = !nextSlideHidden;
Console.WriteLine(nextSlideHidden);
if (nextSlideHidden)
nextSlide.Margin = new Thickness(-(SystemParameters.VirtualScreenWidth * 0.2), SystemParameters.VirtualScreenHeight * 0.2, SystemParameters.VirtualScreenWidth * 0.8, SystemParameters.VirtualScreenHeight * 0.2); // (LEFT, TOP, RIGHT, BOTTOM)
else
nextSlide.Margin = new Thickness(0, SystemParameters.VirtualScreenHeight * 0.2, SystemParameters.VirtualScreenWidth * 0.8, SystemParameters.VirtualScreenHeight * 0.2); // (LEFT, TOP, RIGHT, BOTTOM)
}
You seem to be asking for FillBehavior. Take a look at following link:
http://msdn.microsoft.com/en-us/library/system.windows.media.animation.timeline.fillbehavior(v=vs.110).aspx
Also take a look at AutoReverse property:
http://msdn.microsoft.com/en-us/library/system.windows.media.animation.timeline.autoreverse(v=vs.110).aspx
If those properties doesn't help you any futher I would gladly take a look at your example just please upload it online.
Currently I am using ZedGraph to display my curve. I want to mark the particular regions of the curve over the ZedGraph control and label it like follows.
Note: I need different type of markings in the X and Y axis based on the text size.
Thanks for your help in advance.
You have two options,
1) Use BoxObject to draw at a specific region as follows
and you can use the source code as follows:
private void Form1_Load(object sender, EventArgs e)
{
// Create an instance of Graph Pane
GraphPane myPane = zedGraphControl1.GraphPane;
// Build a PointPairList with points based on Sine wave
PointPairList list = new PointPairList();
for (double i = 0; i < 36; i++)
{
double x = i * 10.0 + 50.0;
double y = Math.Sin(i * Math.PI / 15.0) * 16.0;
list.Add(x, y);
}
// Hide the legend
myPane.Legend.IsVisible = false;
// Add a curve
LineItem curve = myPane.AddCurve("label", list, Color.Red, SymbolType.Circle);
curve.Line.Width = 1.5F;
curve.Symbol.Fill = new Fill(Color.White);
curve.Symbol.Size = 5;
// Make the XAxis start with the first label at 50
myPane.XAxis.Scale.BaseTic = 50;
// Fill the axis background with a gradient
myPane.Chart.Fill = new Fill(Color.White, Color.SteelBlue, 45.0F);
// Draw Region 1
drawRegion(list[0].X, list[10].X,"Positive Cycle");
// Calculate the Axis Scale Ranges
zedGraphControl1.AxisChange();
// Refresh to paint the graph components
Refresh();
}
private void drawRegion(double xMin, double xMax, string regName)
{
GraphPane pane = zedGraphControl1.GraphPane;
BoxObj box = new BoxObj(xMin,20, xMax, 40.0, Color.Empty, Color.LightSteelBlue);// Color.FromArgb(225, 245, 225));
box.Location.CoordinateFrame = CoordType.AxisXYScale;
box.Location.AlignH = AlignH.Left;
box.Location.AlignV = AlignV.Top;
// place the box behind the axis items, so the grid is drawn on top of it
box.ZOrder = ZOrder.E_BehindCurves;//.D_BehindAxis;//.E_BehindAxis;
pane.GraphObjList.Add(box);
// Add Region text inside the box
TextObj myText = new TextObj(regName, 160, -15);
myText.Location.CoordinateFrame = CoordType.AxisXYScale;
myText.Location.AlignH = AlignH.Right;
myText.Location.AlignV = AlignV.Center;
myText.FontSpec.IsItalic = true;
myText.FontSpec.IsBold = false;
myText.FontSpec.FontColor = Color.Red;
myText.FontSpec.Fill.IsVisible = false;
myText.FontSpec.Border.IsVisible = false;
pane.GraphObjList.Add(myText);
zedGraphControl1.Refresh();
}
2) This is a bit difficult but do-able, Draw individual vertical lines discussed here: 1, 2 and add the required text etc.
I suggest you to use the option 1, which is lot easier than 2 !