Scale lines in wpf grid - c#

I have user control:
<UserControl x:Class="WpfExt.ColorLine.TimeLineControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="40" d:DesignWidth="400">
<Grid x:Name="DynamicGrid">
</Grid>
</UserControl>
In code behind:
public readonly static DependencyProperty TotalHoursProperty = DependencyProperty.Register("TotalHours",
typeof(int),
typeof(TimeLineControl),
new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsParentMeasure, TotalHoursChangedCallback));
private static void TotalHoursChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
((TimeLineControl)dependencyObject).ChangeTimeLineItems((int)e.NewValue);
}
public int TotalHours
{
get { return (int)GetValue(TotalHoursProperty); }
set { SetValue(TotalHoursProperty, value); }
}
private void ChangeTimeLineItems(int totalHours)
{
if (totalHours < 1 || totalHours > 24) throw new InvalidOperationException("TotalHours should be in 1..24 range.");
DynamicGrid.Children.Clear();
AddExtremeLine(0, HorizontalAlignment.Left);
for (var index = 1; index < totalHours * 2 - 1; index += 2)
{
AddLine(index, 30);
AddLine(index + 1, 40);
}
AddLine(totalHours * 2 - 1, 30);
AddExtremeLine(totalHours * 2, HorizontalAlignment.Right);
}
private void AddExtremeLine(int column, HorizontalAlignment horizontalAlignment)
{
var columnDefinition = new ColumnDefinition();
var gridLength = new GridLength(0.5, GridUnitType.Star);
columnDefinition.Width = gridLength;
DynamicGrid.ColumnDefinitions.Add(columnDefinition);
var line = new Line
{
X1 = 0,
X2 = 0,
Y1 = 20,
Y2 = 40,
Stroke = Brushes.Black,
StrokeThickness = 1,
HorizontalAlignment = horizontalAlignment
};
Grid.SetColumn(line, column);
DynamicGrid.Children.Add(line);
}
private void AddLine(int column, double y2)
{
var columnDefinition = new ColumnDefinition();
var gridLength = new GridLength(1, GridUnitType.Star);
columnDefinition.Width = gridLength;
DynamicGrid.ColumnDefinitions.Add(columnDefinition);
var line = new Line
{
X1 = 0,
X2 = 0,
Y1 = 20,
Y2 = y2,
Stroke = Brushes.Black,
StrokeThickness = 1,
HorizontalAlignment = HorizontalAlignment.Center
};
Grid.SetColumn(line, column);
DynamicGrid.Children.Add(line);
}
So if i use it like:
<colorLine:TimeLineControl Height="100" TotalHours="6" />
It looks like:
So question is:
How can i change my code, to make my lines scale to fill controls height, but keep existing behavior when width changes (only space between them will scale, but not lines).

If it is only about a control that draws ticks in the shown manner I think I'd do it differently and create a very small custom control. This is all you need and very obvious how it works. You can add dependency properties as you like (like the hours of course). Just by using this way it fills up all given space.
public class HourTicks : FrameworkElement
{
static HourTicks ()
{
}
protected override void OnRender (DrawingContext drawingContext)
{
int hours = 10;
Pen pen = new Pen(Brushes.Black, 1);
drawingContext.DrawLine (pen, new Point (0, 0), new Point (0, ActualHeight));
drawingContext.DrawLine (pen, new Point (ActualWidth, 0), new Point (ActualWidth, ActualHeight));
int numTicks = hours * 2;
double delta = ActualWidth / numTicks;
double x = delta;
for (int i = 0; i <numTicks; i++)
{
drawingContext.DrawLine (pen, new Point (x, 0), new Point (x, ActualHeight / 3));
x += delta;
drawingContext.DrawLine (pen, new Point (x, 0), new Point (x, ActualHeight / 2));
x += delta;
}
}
}

Change the setting of the Y1, Y2's to something based on RenderSize.Height. i.e. something like:
Y1 = Grid.RenderHeight - 40;
Y2 = Grid.RenderHeight - 20;
Obviously the 20 & 40 switch as your now 'measuring' the amount of white space to leave, not the length of the line.

Related

How to use AddArc() method in C#

I have this little code to use AddArc() method in a label, but when I execute the code the label disappears. I believe it is the numbers I have used, I followed instructions from the Windows documentation and it had these parameters there too.
GraphicsPath gp = new GraphicsPath();
Rectangle rec = new Rectangle(20, 20, 50, 100);
gp.AddArc(rec, 0 , 180);
label2.Region = new Region(gp);
label2.Invalidate();
I used another code to make the correct way or curve in a text
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var center = new Point(Width / 2, Height / 2);
var radius = Math.Min(Width, Height) / 3;
var text = "Hello";//txtUp.Text;
var font = new Font(FontFamily.GenericSansSerif, 24, FontStyle.Bold);
for (var i = 0; i < text.Length; ++i)
{
var c = new String(text[i], 1);
var size = e.Graphics.MeasureString(c, font);
var charRadius = radius + size.Height;
var angle = (((float)i / text.Length) - 2);
var x = (int)(center.X + Math.Cos(angle) * charRadius);
var y = (int)(center.Y + Math.Sin(angle) * charRadius);
e.Graphics.TranslateTransform(x, y);
e.Graphics.RotateTransform((float)(90 + 360 * angle / (2 * Math.PI)));
e.Graphics.DrawString(c, font, Brushes.Red, 0, 0);
e.Graphics.ResetTransform();
e.Graphics.DrawArc(new Pen(Brushes.Transparent, 2.0f), center.X - radius, center.Y - radius, radius * 2, radius * 2, 0, 360);
}
}
but it wont show in front of a panel is it possible.
This is what it looks like:
Is it possible to move that text in front of the green circle?

Chart: issue with stacked areas order

I would like to display the 2 different stacked area elements according to their parameters. But the chart area displays it not as specified and puts the second block at the top right corner of the first stacked area. They should be displayed side by side not stacked.
...
using System.Windows.Forms.DataVisualization.Charting;
namespace Gantt_Tool
{
public partial class ReadModel : Form
{
public ReadModel()
{
InitializeComponent();
CreateChart();
}
private void ReadModel_Load(object sender, EventArgs e)
{
}
private void CreateChart()
{
chart1.Series.Add($"a");
chart1.Series[$"a"].Points.Add(new DataPoint(0, 2));
chart1.Series[$"a"].Points.Add(new DataPoint(2, 2));
chart1.Series[$"a"].ChartType = SeriesChartType.StackedArea;
chart1.Series.Add($"b");
chart1.Series[$"b"].Points.Add(new DataPoint(2, 3));
chart1.Series[$"b"].Points.Add(new DataPoint(5, 3));
chart1.Series[$"b"].ChartType = SeriesChartType.StackedArea;
}
}
How can I set the blocks to a side by side order or placed freely? And how can I get unfilled rectangles?
Update: Here is an example of how it should look like:
From your comments, I take that you want to have a chart with freely-placed, unfilled rectangles and labels.
None of the MSChart types will do that.
Here is how to use a Point chart with a few lines of owner-drawing. Note how nicely this will behave when resizing the chart...
Here is the setup:
Axis ax = chart1.ChartAreas[0].AxisX;
Axis ay = chart1.ChartAreas[0].AxisY;
ax.Maximum = 9; // pick or calculate
ay.Maximum = 6; // minimum and..
ax.Interval = 1; // maximum values..
ay.Interval = 1; // .. needed
ax.MajorGrid.Enabled = false;
ay.MajorGrid.Enabled = false;
Series s1 = chart1.Series.Add("A");
s1.ChartType = SeriesChartType.Point;
Now we add your five boxes. I use a sepcial function that adds the points and stuffs the box size into the Tag of each point..:
AddBox(s1, 1, 0, 3, 1, "# 1");
AddBox(s1, 2, 1, 2, 2, "# 2");
AddBox(s1, 4, 0, 4, 2, "# 3");
AddBox(s1, 4, 2, 2, 2, "# 4");
AddBox(s1, 4, 4, 1, 1, "# 5");
int AddBox(Series s, float x, float y, float w, float h, string label)
{
return AddBox(s, new PointF(x, y), new SizeF(w, h), label);
}
int AddBox(Series s, PointF pt, SizeF sz, string label)
{
int i = s.Points.AddXY(pt.X, pt.Y);
s.Points[i].Tag = sz;
s.Points[i].Label = label;
s.Points[i].LabelForeColor = Color.Transparent;
s.Points[i].Color = Color.Transparent;
return i;
}
The drawing is also simple; only the use of the Axes function ValueToPixelPosition is noteworthy..:
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
if (chart1.Series[0].Points.Count <= 0) return;
Axis ax = chart1.ChartAreas[0].AxisX;
Axis ay = chart1.ChartAreas[0].AxisY;
Graphics g = e.ChartGraphics.Graphics;
using (StringFormat fmt = new StringFormat()
{ Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center})
foreach (Series s in chart1.Series)
{
foreach (DataPoint dp in s.Points)
{
if (dp.Tag == null) break;
SizeF sz = (SizeF)dp.Tag;
double vx2 = dp.XValue + sz.Width;
double vy2 = dp.YValues[0] + sz.Height;
int x1 = (int)ax.ValueToPixelPosition(dp.XValue);
int y1 = (int)ay.ValueToPixelPosition(dp.YValues[0]);
int x2 = (int)ax.ValueToPixelPosition(vx2);
int y2 = (int)ay.ValueToPixelPosition(vy2);
Rectangle rect = Rectangle.FromLTRB(x1, y2, x2, y1);
using (Pen pen = new Pen(s.Color, 2f))
g.DrawRectangle(pen, rect);
g.DrawString(dp.Label, Font, Brushes.Black, rect, fmt);
}
}
}
Here is a little Linq to calculate the Minimum and Maximum values for the Axes to hold just the right size; chart won't do it by itself since the size in the tags of the points is not known...
private void setMinMax(Chart chart, ChartArea ca)
{
var allPoints = chart.Series.SelectMany(x => x.Points);
double minx = allPoints.Select(x => x.XValue).Min();
double miny = allPoints.Select(x => x.YValues[0]).Min();
double maxx = allPoints.Select(x => x.XValue + ((SizeF)x.Tag).Width).Max();
double maxy = allPoints.Select(x => x.YValues[0] + ((SizeF)x.Tag).Height).Max();
ca.AxisX.Minimum = minx;
ca.AxisX.Maximum = maxx;
ca.AxisY.Minimum = miny;
ca.AxisY.Maximum = maxy;
}

How to optimise Canvas drawing in WPF?

How to optimise Canvas drawing in WPF, when i have 10000 Line like in program "Paint"? When I draw in "Paint" i can use how much I need lines and circles, but in my program agter +-10000 i have lags.
I create a test program with 10000 lines and when I move mouse on canvas rectangle is change position to a cursor.
here code
for (int i=0; i < 10000; i++)
{
Line l = new Line();
l.Stroke = Brushes.Black;
l.StrokeThickness = 1;
l.X1 = 50+ privi;
l.Y1 = 50 + privi;
l.X2 = 100 ;
l.Y2 = 100 + privi;
MainCanvas.Children.Add(l);
privi += 5;
}
and here i moving
if (clicked)
{
Point p = Mouse.GetPosition(MainCanvas);
rect.Margin = new Thickness(p.X-25, p.Y - 25, 0, 0);
}
enter code here
UPDATE
privi = 5;
Rectangle rect = new Rectangle();
rect.Fill = Brushes.Black;
rect.Width = 50;
rect.Height = 50;
MainCanvas.Children.Add(rect)
I don't know if you need lines and rect to be in the same canvas, otherwise I found that adding the rectangle in a second transparent canvas over the MainCanvas improves the reactivity.
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="1080" Width="1024">
<Canvas Name="MainCanvas" MouseMove="MainCanvas_MouseMove">
<Canvas Name="RectCanvas" Background="Transparent" MouseMove="RectCanvas_MouseMove">
</Canvas>
</Canvas>
</Window>
public partial class MainWindow : Window
{
double privi = 5;
Rectangle rect;
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 10000; i++)
{
Line l = new Line();
l.Stroke = Brushes.Black;
l.StrokeThickness = 1;
l.X1 = 50 + privi;
l.Y1 = 50 + privi;
l.X2 = 100;
l.Y2 = 100 + privi;
MainCanvas.Children.Add(l);
privi += 5;
}
rect = new Rectangle();
rect.Width = 50;
rect.Height = 50;
rect.Fill = Brushes.Black;
Canvas.SetLeft(rect, 0);
Canvas.SetTop(rect, 0);
SecondCanvas.Children.Add(rect);
}
private void RectCanvas_MouseMove(object sender, MouseEventArgs e)
{
//if (clicked)
{
Point p = Mouse.GetPosition(MainCanvas);
rect.Margin = new Thickness(p.X - 25, p.Y - 25, 0, 0);
}
}
}

Comparing two sets of data (x,y)

I have stored numerical data in lists with its coordinates (xValues, yValues), and if I want to compare (add, subtract, divide...) that set of data to another I have to be aware of that I can't compare if the xValues don't match (because there is nothing to compare with). So I need to interpolate linearly between the "missing" xValues, that actually exist in the other set and generate new points. Please check this picture:
The cyan squares on the red line represent the stored points (xValues2), and (generally) they won't match the other's set xValues (xValues1). The two squares on the green line are examples of the desired generated points. With them I can work with this two graphs without problem.
For linear interpolation It's pretty straightforward: If I have two points (x0,y0) and (x1,y1) and I want to add a new point between them given a "x2":
y2=y0+(x2-x0)*(y1-y0)/(x1-x0)
To make this work I think I have to implement something like this:
Create new lists (xValuesNew, yValuesNew).
Make a union between xValues1 and xValues2 (xValuesNew).
Check what are the differences between the original xValues1 and the xValuesNew.
For each new value found generate the "y" using the formula written above.
Put that 4 steps in a method and use it again but now with the set2.
I've been on this all day, trying to find an easy solution, maybe using Linq or lambda expressions but I'm not used to work with them and my lack of knowledge on that topics ishuge. Note that this operation will be made pretty often so I have to make it not too heavy. I've thought that it will be a good idea to generate a new list instead inserting points in the middle of the original for that reason.
Please if someone could guide me a little bit or tell me if there is a math library actually doing this would be great. Thank you.
EDIT: Sorry if I haven't explained me properly.
Here I have an example (done in Excel):
Note that I can't directly add together Series1 and Series2 (+) or any other operation because the X spacing in them is different. So what I want is to generate a new point in the Series1 when is needed.
For that I would like to simple use a linear interpolation. Say that I have P1(0,40) and P2(0,60) in series1, but in series2 I have a point (1,10). I need to generate a point P3 between P1 and P2 with (1,50) coordinates.
I was trying to do this with SkipWhile and comparing the next X value of both series, if XValue of series1 is lower, then add that XValue and corresponding YValue in the newSeries. Else use the XValue2 for generating an Y and add it to the newSeries. Here is one of my attempts (doesn't work):
List<double> series1X = new List<double> { 0, 2, 4, 6, 8 };
List<double> series1Y = new List<double> { 120, 100, 110, 105, 70 };
List<double> series2X = new List<double> { 0, 1, 7, 8,9 };
List<double> newSeries1X = new List<double>();
List<double> newSeries1Y = new List<double>();
double lastX1 = series1X[series1X.Count()-1];
int i = 0;
while (next1X <= lastX1)
{
next2X = series2X.SkipWhile(p => p <= next1X).First();
Console.WriteLine(next2X.ToString());
if (next1X <= next2X)
{
newSeries1X.Add(series1X[i]);
newSeries1Y.Add(series1Y[i]);
}
if (next2X < next1X)
{
while (next2X < next1X)
{
newSeries1X.Add(next2X);
newY = series1Y[i] + (next2X - series1X[i]) * (series1Y[i + 1] - series1Y[i]) / (series1X[i + 1] - series1X[i]);
newSeries1Y.Add(newY);
next2X = series2X.SkipWhile(p => p <= next2X).First();
}
}
next1X = series1X.SkipWhile(p => p <= next2X).First();
Console.WriteLine(next1X.ToString());
i++;
}
It would be AWESOME to do this with your Zip method. But I have no idea how to write that condition in the predicate.
First off, I'd probably use an appropriate 'point' class that contains both the x and y coordinates instead of two separate lists for each coordinate. Then you can use the Zip method to quickly iterate through them:
IEnumerable<PointF> points0 = ...
IEnumerable<PointF> points0 = ...
float x2 = ...
IEnumerable<PointF> newPoints = point0.Zip(points1,
(p0, p1) => new PointF(p0.X, p0.Y + (x2-p0.X) * (p1.Y-p0.Y) / (p1.X-p0.X)));
This makes it easy to calculate a new set of points from your input data. If you just care about a single y-value, you can still do this with your current data, it will just look weird:
IEnumerable<double> y2values =
xValues1.Zip(yValues1, (x, y) => new { x, y }).Zip(
xValues2.Zip(yValues2, (x, y) => new { x, y }),
(p0, p1) => p0.y + (x2-p0.x) * (p1.y-p0.y) / (p1.x-p0.x));
I appologize if in the process of coding this answer I somehow mangled your math.
Update
Now that I have a better grasp on what you're trying to do, I don't think any Linq method will work out quite right. Here what I've come up with using indexes:
List<double> series1X = new List<double> { 0, 2, 4, 6, 8 };
List<double> series1Y = new List<double> { 120, 100, 110, 105, 70 };
List<double> series2X = new List<double> { 0, 1, 7, 8, 9 };
// in the worst case there are n + m new points
List<double> newSeries1X = new List<double>(series1X.Count + series2X.Count);
List<double> newSeries1Y = new List<double>(series1X.Count + series2X.Count);
int i = 0, j = 0;
for ( ; i < series1X.Count && j < series2X.Count; )
{
if (series1X[i] <= series2X[j])
{
newSeries1X.Add(series1X[i]);
newSeries1Y.Add(series1Y[i]);
if (series1X[i] == series2X[j])
{
j++;
}
i++;
}
else
{
int k = (i == 0) ? i : i - 1;
// interpolate
double y0 = series1Y[k];
double y1 = series1Y[k + 1];
double x0 = series1X[k];
double x1 = series1X[k + 1];
double y = y0 + (y1 - y0) * (series2X[j] - x0) / (x1 - x0);
newSeries1X.Add(series2X[j]);
newSeries1Y.Add(y);
j++;
}
}
for ( ; i < series1X.Count; i++)
{
newSeries1X.Add(series1X[i]);
newSeries1Y.Add(series1Y[i]);
}
for ( ; j < series2X.Count; j++)
{
// interpolate
double y0 = series1Y[i - 2];
double y1 = series1Y[i - 1];
double x0 = series1X[i - 2];
double x1 = series1X[i - 1];
double y = y0 + (y1 - y0) * (series2X[j] - x0) / (x1 - x0);
newSeries1X.Add(series2X[j]);
newSeries1Y.Add(y);
}
Output is
newSeries1X = { 0, 1, 2, 4, 6, 7, 8, 0 }
newSeries1Y = { 120, 110, 100, 110, 105, 87.5, 70, 52.5 }
This solution handles cases where the first series2X[0] < series1X[0] and when series2X[n] > series1X[m] by linearly 'projecting' the data outward from the first / last pair of points.
Here's another solution using enumerators (mostly), but it's not nearly as elegant as I'd hoped it would be. It could probably be improved a bit:
bool hasS1 = true, hasS2 = true, preinterp = true;
double x0 = 0, y0 = 0, x1 = 0, y1 = 0, x = 0, y = 0;
using(var s1xEnumerator = series1X.GetEnumerator())
using(var s1yEnumerator = series1Y.GetEnumerator())
using(var s2xEnumerator = series2X.GetEnumerator())
{
hasS1 = s1xEnumerator.MoveNext();
hasS2 = s2xEnumerator.MoveNext();
s1yEnumerator.MoveNext();
while(hasS1 && hasS2)
{
x1 = s1xEnumerator.Current;
y1 = s1yEnumerator.Current;
x = s2xEnumerator.Current;
if (x1 <= x)
{
newSeries1X.Add(x1);
newSeries1Y.Add(y1);
hasS1 = s1xEnumerator.MoveNext();
s1yEnumerator.MoveNext();
preinterp = false;
if (hasS1)
{
x0 = x1;
y0 = y1;
}
if (x1 == x)
{
hasS2 = s2xEnumerator.MoveNext();
}
}
else
{
// we have to look ahead to get the next interval to interpolate before x0
if (preinterp)
{
x0 = x1;
y0 = y1;
x1 = series1X[1]; // can't peek with enumerator
y1 = series1Y[1];
preinterp = false;
}
y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
newSeries1X.Add(x);
newSeries1Y.Add(y);
hasS2 = s2xEnumerator.MoveNext();
}
}
while(hasS1)
{
newSeries1X.Add(s1xEnumerator.Current);
newSeries1Y.Add(s1yEnumerator.Current);
hasS1 = s1xEnumerator.MoveNext();
s1yEnumerator.MoveNext();
}
while(hasS2)
{
x = s2xEnumerator.Current;
y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
newSeries1X.Add(x);
newSeries1Y.Add(y);
hasS2 = s2xEnumerator.MoveNext();
}
}
For working with two series with different spacing I first need to generate points in the first set, then in the second (with the same method) and finally sum point to point.
Here is the code for that method:
using OxyPlot.Series;
using OxyPlot;
namespace Algorithm1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<DataPoint> S1 = new List<DataPoint> ();
List<DataPoint> S2 = new List<DataPoint>();
List<DataPoint> NS1 = new List<DataPoint>();
S1.Add(new DataPoint(4, 10));
S1.Add(new DataPoint(6, 20));
S1.Add(new DataPoint(8, 15));
S1.Add(new DataPoint(9, 70));
S1.Add(new DataPoint(10, 5));
S2.Add(new DataPoint(1, 0));
S2.Add(new DataPoint(2, 0));
S2.Add(new DataPoint(3, 0));
S2.Add(new DataPoint(6, 0));
S2.Add(new DataPoint(7, 0));
S2.Add(new DataPoint(8.1, 0));
S2.Add(new DataPoint(8.2, 0));
S2.Add(new DataPoint(8.3, 0));
S2.Add(new DataPoint(8.4, 0));
S2.Add(new DataPoint(9, 0));
S2.Add(new DataPoint(9.75, 0));
S2.Add(new DataPoint(11, 0));
S2.Add(new DataPoint(12, 0));
S2.Add(new DataPoint(16, 0));
NS1 = GetMiddlePoints(S1, S2);
foreach (DataPoint pointin NS1)
{
MessageBox.Show( point.X.ToString()+" : "+ point.Y.ToString());
}
}
#region GetMiddlePoints
private List<DataPoint> GetMiddlePoints(List<DataPoint> S1, List<DataPoint> S2)
{
List<DataPoint> NS1 = new List<DataPoint>();
int i = 0;
int j = S2.TakeWhile(p => p.X < S1[0].X).Count();
int PointsInS1 = S1.Count;
int PointsInS2 = S2.Count;
DataPoint newPoint = new DataPoint();
while (i < PointsInS1 )
{
if (j < PointsInS2 )
{
if (S1[i].X < S2[j].X)
{
newPoint = S1[i];
NS1.Add(newPoint );
i++;
}
else if (S1[i].X == S2[j].X)
{
newPoint = S1[i];
NS1.Add(newPoint );
i++;
j++;
}
else if (S1[i].X > S2[j].X)
{
newPoint .X = S2[j].X;
newPoint .Y = S1[i-1].Y + (S2[j].X - S1[i-1].X) * (S1[i].Y - S1[i-1].Y) / (S1[i].X - S1[i-1].X);
NS1.Add(newPoint );
j++;
}
}
if (j == PointsInS2 )
{
newPoint = S1[i];
NS1.Add(newPoint );
i++;
}
}
return NS1;
}
#endregion
}
}

Animated bar in progress bar winform

I'm writing an extended progress bar control at present, 100% open source and I've created some basic styles with gradients and solid colours.
One of the options I wanted to add was animation to the bar, prety much like the windows 7 and vista green progress bar. So I need to add a moving "Glow" to the % bar, however my attempt at this looks terrible.
My method is to draw an ellipse with set size and move it's x position until it reaches the end were the animation starts again.
First of does anyone have nay links or code to help me achieve the current windows 7 glow effect using GDI or some similar method?
I have several other animations that will also be added the the bar hence the GDI.
private void renderAnimation(PaintEventArgs e)
{
if (this.AnimType == animoptions.Halo)
{
Rectangle rec = e.ClipRectangle;
Rectangle glow = new Rectangle();
//SolidBrush brush = new SolidBrush(Color.FromArgb(100, Color.White));
//int offset = (int)(rec.Width * ((double)Value / Maximum)) - 4;
int offset = (int)(rec.Width / Maximum) * Value;
if (this.animxoffset > offset)
{
this.animxoffset = 0;
}
glow.Height = rec.Height - 4;
if (this.animxoffset + glow.X > offset)
{
glow.Width = offset - (this.animxoffset + 50);
}
else
{
glow.Width = 50;
}
glow.X = this.animxoffset;
LinearGradientBrush brush = new LinearGradientBrush(glow, Color.FromArgb(0, Color.White), Color.FromArgb(100, Color.White), LinearGradientMode.Horizontal);
e.Graphics.FillEllipse(brush, this.animxoffset, 2, glow.Width, glow.Height);
brush.Dispose();
string temp = offset.ToString();
e.Graphics.DrawString(temp + " : " + glow.X.ToString(), DefaultFont, Brushes.Black, 2, 2);
animTimer = new System.Timers.Timer();
animTimer.Interval = 10;
animTimer.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
animTimer.Start();
}
}
void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
this.animTimer.Stop();
this.animxoffset += 2;
Invalidate();
}
This is just an example glow iterating through a pen array.
You could also use a transparent image (although it could have a performance impact).
Pen[] gradient = { new Pen(Color.FromArgb(255, 200, 200, 255)), new Pen(Color.FromArgb(150, 200, 200, 255)), new Pen(Color.FromArgb(100, 200, 200, 255)) };
int x = 20;
int y = 20;
int sizex = 200;
int sizey = 10;
int value = 25;
//draw progress bar basic outline (position - 1 to compensate for the outline)
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(x-1, y-1, sizex, sizey));
//draw the percentage done
e.Graphics.FillRectangle(Brushes.AliceBlue, new Rectangle(x, y, (sizex/100)*value, sizey));
//to add the glow effect just add lines around the area you want to glow.
for (int i = 0; i < gradient.Length; i++)
{
e.Graphics.DrawRectangle(gradient[i], new Rectangle(x - (i + 1), y - (i + 1), (sizex / 100) * value + (2 * i), sizey + (2 * i)));
}

Categories

Resources