How to animate a DropShadowEffect's color that has been already applied to an element with XAML without the need to re-apply a new DropShadowEffect?
I tried this:
private void test()
{
DropShadowEffect DS_Moon = (DropShadowEffect)Application.Current.Resources["DS_Moon"];
ColorAnimation DS_Moonlight = new ColorAnimation();
DS_Moonlight.From = new Color()
{
A = (byte)1,
R = (byte)0,
G = (byte)0,
B = (byte)0
};
DS_Moonlight.To = new Color()
{
A = (byte)1,
R = (byte)255,
G = (byte)255,
B = (byte)255
};
DS_Moon.BeginAnimation(SolidColorBrush.ColorProperty, (AnimationTimeline)DS_Moonlight);
}
But DS_Moon returns Null!!
I just realized that i can do this:
Moon.Effect.BeginAnimation(DropShadowEffect.ColorProperty, (AnimationTimeline)DS_Moonlight);
Related
I am doing C# application, and I want to change the style of a message box. Is it possible or not?
Example: change button style, fore color, etc.
You can't restyle the default MessageBox as that's dependant on the current Windows OS theme, however you can easily create your own MessageBox. Just add a new form (i.e. MyNewMessageBox) to your project with these settings:
FormBorderStyle FixedToolWindow
ShowInTaskBar False
StartPosition CenterScreen
To show it use myNewMessageBoxInstance.ShowDialog();. And add a label and buttons to your form, such as OK and Cancel and set their DialogResults appropriately, i.e. add a button to MyNewMessageBox and call it btnOK. Set the DialogResult property in the property window to DialogResult.OK. When that button is pressed it would return the OK result:
MyNewMessageBox myNewMessageBoxInstance = new MyNewMessageBox();
DialogResult result = myNewMessageBoxInstance.ShowDialog();
if (result == DialogResult.OK)
{
// etc
}
It would be advisable to add your own Show method that takes the text and other options you require:
public DialogResult Show(string text, Color foreColour)
{
lblText.Text = text;
lblText.ForeColor = foreColour;
return this.ShowDialog();
}
MessageBox::Show uses function from user32.dll, and its style is dependent on Windows, so you cannot change it like that, you have to create your own form
Here is the code needed to create your own message box:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyStuff
{
public class MyLabel : Label
{
public static Label Set(string Text = "", Font Font = null, Color ForeColor = new Color(), Color BackColor = new Color())
{
Label l = new Label();
l.Text = Text;
l.Font = (Font == null) ? new Font("Calibri", 12) : Font;
l.ForeColor = (ForeColor == new Color()) ? Color.Black : ForeColor;
l.BackColor = (BackColor == new Color()) ? SystemColors.Control : BackColor;
l.AutoSize = true;
return l;
}
}
public class MyButton : Button
{
public static Button Set(string Text = "", int Width = 102, int Height = 30, Font Font = null, Color ForeColor = new Color(), Color BackColor = new Color())
{
Button b = new Button();
b.Text = Text;
b.Width = Width;
b.Height = Height;
b.Font = (Font == null) ? new Font("Calibri", 12) : Font;
b.ForeColor = (ForeColor == new Color()) ? Color.Black : ForeColor;
b.BackColor = (BackColor == new Color()) ? SystemColors.Control : BackColor;
b.UseVisualStyleBackColor = (b.BackColor == SystemColors.Control);
return b;
}
}
public class MyImage : PictureBox
{
public static PictureBox Set(string ImagePath = null, int Width = 60, int Height = 60)
{
PictureBox i = new PictureBox();
if (ImagePath != null)
{
i.BackgroundImageLayout = ImageLayout.Zoom;
i.Location = new Point(9, 9);
i.Margin = new Padding(3, 3, 2, 3);
i.Size = new Size(Width, Height);
i.TabStop = false;
i.Visible = true;
i.BackgroundImage = Image.FromFile(ImagePath);
}
else
{
i.Visible = true;
i.Size = new Size(0, 0);
}
return i;
}
}
public partial class MyMessageBox : Form
{
private MyMessageBox()
{
this.panText = new FlowLayoutPanel();
this.panButtons = new FlowLayoutPanel();
this.SuspendLayout();
//
// panText
//
this.panText.Parent = this;
this.panText.AutoScroll = true;
this.panText.AutoSize = true;
this.panText.AutoSizeMode = AutoSizeMode.GrowAndShrink;
//this.panText.Location = new Point(90, 90);
this.panText.Margin = new Padding(0);
this.panText.MaximumSize = new Size(500, 300);
this.panText.MinimumSize = new Size(108, 50);
this.panText.Size = new Size(108, 50);
//
// panButtons
//
this.panButtons.AutoSize = true;
this.panButtons.AutoSizeMode = AutoSizeMode.GrowAndShrink;
this.panButtons.FlowDirection = FlowDirection.RightToLeft;
this.panButtons.Location = new Point(89, 89);
this.panButtons.Margin = new Padding(0);
this.panButtons.MaximumSize = new Size(580, 150);
this.panButtons.MinimumSize = new Size(108, 0);
this.panButtons.Size = new Size(108, 35);
//
// MyMessageBox
//
this.AutoScaleDimensions = new SizeF(8F, 19F);
this.AutoScaleMode = AutoScaleMode.Font;
this.ClientSize = new Size(206, 133);
this.Controls.Add(this.panButtons);
this.Controls.Add(this.panText);
this.Font = new Font("Calibri", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.Margin = new Padding(4);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.MinimumSize = new Size(168, 132);
this.Name = "MyMessageBox";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.ResumeLayout(false);
this.PerformLayout();
}
public static string Show(Label Label, string Title = "", List<Button> Buttons = null, PictureBox Image = null)
{
List<Label> Labels = new List<Label>();
Labels.Add(Label);
return Show(Labels, Title, Buttons, Image);
}
public static string Show(string Label, string Title = "", List<Button> Buttons = null, PictureBox Image = null)
{
List<Label> Labels = new List<Label>();
Labels.Add(MyLabel.Set(Label));
return Show(Labels, Title, Buttons, Image);
}
public static string Show(List<Label> Labels = null, string Title = "", List<Button> Buttons = null, PictureBox Image = null)
{
if (Labels == null) Labels = new List<Label>();
if (Labels.Count == 0) Labels.Add(MyLabel.Set(""));
if (Buttons == null) Buttons = new List<Button>();
if (Buttons.Count == 0) Buttons.Add(MyButton.Set("OK"));
List<Button> buttons = new List<Button>(Buttons);
buttons.Reverse();
int ImageWidth = 0;
int ImageHeight = 0;
int LabelWidth = 0;
int LabelHeight = 0;
int ButtonWidth = 0;
int ButtonHeight = 0;
int TotalWidth = 0;
int TotalHeight = 0;
MyMessageBox mb = new MyMessageBox();
mb.Text = Title;
//Image
if (Image != null)
{
mb.Controls.Add(Image);
Image.MaximumSize = new Size(150, 300);
ImageWidth = Image.Width + Image.Margin.Horizontal;
ImageHeight = Image.Height + Image.Margin.Vertical;
}
//Labels
List<int> il = new List<int>();
mb.panText.Location = new Point(9 + ImageWidth, 9);
foreach (Label l in Labels)
{
mb.panText.Controls.Add(l);
l.Location = new Point(200, 50);
l.MaximumSize = new Size(480, 2000);
il.Add(l.Width);
}
int mw = Labels.Max(x => x.Width);
il.ToString();
Labels.ForEach(l => l.MinimumSize = new Size(Labels.Max(x => x.Width), 1));
mb.panText.Height = Labels.Sum(l => l.Height);
mb.panText.MinimumSize = new Size(Labels.Max(x => x.Width) + mb.ScrollBarWidth(Labels), ImageHeight);
mb.panText.MaximumSize = new Size(Labels.Max(x => x.Width) + mb.ScrollBarWidth(Labels), 300);
LabelWidth = mb.panText.Width;
LabelHeight = mb.panText.Height;
//Buttons
foreach (Button b in buttons)
{
mb.panButtons.Controls.Add(b);
b.Location = new Point(3, 3);
b.TabIndex = Buttons.FindIndex(i => i.Text == b.Text);
b.Click += new EventHandler(mb.Button_Click);
}
ButtonWidth = mb.panButtons.Width;
ButtonHeight = mb.panButtons.Height;
//Set Widths
if (ButtonWidth > ImageWidth + LabelWidth)
{
Labels.ForEach(l => l.MinimumSize = new Size(ButtonWidth - ImageWidth - mb.ScrollBarWidth(Labels), 1));
mb.panText.Height = Labels.Sum(l => l.Height);
mb.panText.MinimumSize = new Size(Labels.Max(x => x.Width) + mb.ScrollBarWidth(Labels), ImageHeight);
mb.panText.MaximumSize = new Size(Labels.Max(x => x.Width) + mb.ScrollBarWidth(Labels), 300);
LabelWidth = mb.panText.Width;
LabelHeight = mb.panText.Height;
}
TotalWidth = ImageWidth + LabelWidth;
//Set Height
TotalHeight = LabelHeight + ButtonHeight;
mb.panButtons.Location = new Point(TotalWidth - ButtonWidth + 9, mb.panText.Location.Y + mb.panText.Height);
mb.Size = new Size(TotalWidth + 25, TotalHeight + 47);
mb.ShowDialog();
return mb.Result;
}
private FlowLayoutPanel panText;
private FlowLayoutPanel panButtons;
private int ScrollBarWidth(List<Label> Labels)
{
return (Labels.Sum(l => l.Height) > 300) ? 23 : 6;
}
private void Button_Click(object sender, EventArgs e)
{
Result = ((Button)sender).Text;
Close();
}
private string Result = "";
}
}
This is what I did in the constructor:
drawPoints.Clear();
paintToCalaculate = false;
chart1.Invalidate();
Series S0 = chart1.Series[0];
S0.ChartType = SeriesChartType.Column;
S0.IsValueShownAsLabel = true;
chart1.Series["Series1"]["PixelPointWidth"] = "0.6";
chart1.Series["Series1"]["DrawingStyle"] = "Cylinder";
S0.Color = Color.Transparent;
S0.LegendText = "";
area.BackColor = Color.White;
area.BackSecondaryColor = Color.LightSteelBlue;
area.BackGradientStyle = GradientStyle.DiagonalRight;
area = chart1.ChartAreas[0];
chart1.Series["Series1"].Points.AddXY(10, 10);
area.AxisX.Minimum = 1;
area.AxisX.Maximum = 30;
area.AxisY.Minimum = 1;
area.AxisY.Maximum = 120;
area.AxisX.MajorGrid.LineColor = Color.LightSlateGray;
area.AxisY.MajorGrid.LineColor = Color.LightSlateGray;
The problem is that I'm using the chart paint event to draw points and lines:
Pen pen = new Pen(Color.Blue, 2.5f);
SolidBrush myBrush = new SolidBrush(Color.Red);
private void chart1_Paint(object sender, PaintEventArgs e)
{
if (paintToCalaculate)
{
Series s = chart1.Series.FindByName("dummy");
if (s == null) s = chart1.Series.Add("dummy");
drawPoints.Clear();
s.Points.Clear();
foreach (PointF p in valuePoints)
{
s.Points.AddXY(p.X, p.Y);
DataPoint pt = s.Points[0];
double x = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(pt.XValue);
double y = chart1.ChartAreas[0].AxisY.ValueToPixelPosition(pt.YValues[0]);
drawPoints.Add(new Point((int)x, (int)y));
s.Points.Clear();
}
paintToCalaculate = false;
chart1.Series.Remove(s);
}
foreach (Point p in drawPoints)
{
e.Graphics.FillEllipse(Brushes.Red, p.X - 2, p.Y - 2, 4, 4);
}
if (drawPoints.Count > 1)
{
e.Graphics.DrawLines(pen, drawPoints.ToArray());
}
}
I wanted it to look like this style:
It should look like in the example. But since I'm using the paint event maybe it's not possible this way.
Edit tried this solution i added a new chart control for the test in the form1 designer called chart2. Then in the constructor i did:
chart2.Titles.Add(("Introducing Chart Controls"));
ChartArea chartarea2 = new ChartArea("Main");
chart2.ChartAreas.Add(chartarea2);
Series seriesColumns = new Series("RandomColumns");
seriesColumns.Color = Color.Blue;
chart2.Series.Add(seriesColumns);
Random rnd = new Random(10);
for (int i = 0; i < 10; i++)
{
seriesColumns.Points.Add((rnd.Next(100)));
}
DataPoint dp = new DataPoint(seriesColumns);
dp.Color = Color.Red;
dp.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.LeftRight;
seriesColumns.Points.Add(dp);
But no fade in/out color change. Nothing happen.
This is how chart2 look like:
To get the gradient effect you don't necessarily have to use the Paint event. The DataPoint has the BackGradientStyle property that will generate the gradient automatically for you. It will use the colour of the DataPoint. You set it like in the sample below:
var dp = new DataPoint(8D, 12D);
dp.Color = Color.Red;
dp.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.LeftRight;
var series = this.chart1.Series[0];
series.Points.Add(dp);
Here the gradient is fading out. If you want it to pass into another color set the BackSecondaryColor property.
dp.BackSecondaryColor = Color.Green;
I am trying to create an animation but am having problems executing some code after the animation has occured. The animation code is as follows...
public static void Friend(Canvas canvas)
{
foreach (var element in canvas.Children.OfType<Image>())
{
var elementName = Regex.Split(element.Name, "_");
if (elementName[0] == "friend")
{
var slideDown = new DoubleAnimation
{
From = Canvas.GetBottom(element),
To = Canvas.GetBottom(element) - element.Height,
Duration = new Duration(TimeSpan.FromSeconds(1)),
AutoReverse = true
};
element.BeginAnimation(Canvas.BottomProperty, slideDown);
slideDown.Completed += (sender, e) => Test(sender, e, element, canvas);
}
}
}
The event to happen afterwards is...
var random = new Random();
element.Source = Core.StreamImage(Wardrobe.Friends[Wardrobe.RandomFriend()]);
Canvas.SetLeft(element, random.Next(0, (int)(canvas.ActualWidth - element.Width)));
// then reverse the previous animation.
As you can see, the event needs to keep the context of the animation in order for it to work but event handlers don't allow this. I have tried adding this code directly underneath the element.BeginAnimation but it is executed prematurely.
I have also tried splitting the parts of the animation up into seperate functions but of course you can't have multiple animations on one object as the functions don't get executed in order resulting in only the last section being played.
Here is the code i used to fix the problem i was having...
public static void Friend(Canvas canvas)
{
var random = new Random();
foreach (var element in canvas.Children.OfType<Image>())
{
var elementName = Regex.Split(element.Name, "_");
if (elementName[0] == "friend")
{
var slideDown = new DoubleAnimation
{
From = Canvas.GetBottom(element),
To = Canvas.GetBottom(element) - element.Height,
Duration = new Duration(TimeSpan.FromSeconds(1))
};
slideDown.Completed += (sender, e) =>
{
element.Source = Core.StreamImage(Wardrobe.Friends[Wardrobe.RandomFriend()]);
Canvas.SetLeft(element, random.Next(0, (int)(canvas.ActualWidth - element.Width)));
var slideUp = new DoubleAnimation
{
From = Canvas.GetBottom(element),
To = Canvas.GetBottom(element) + element.Height,
Duration = new Duration(TimeSpan.FromSeconds(1))
};
element.BeginAnimation(Canvas.BottomProperty, slideUp);
};
element.BeginAnimation(Canvas.BottomProperty, slideDown);
}
}
}
Try moving the event above the execution
public static void Friend(Canvas canvas)
{
foreach (var element in canvas.Children.OfType<Image>())
{
var elementName = Regex.Split(element.Name, "_");
if (elementName[0] == "friend")
{
var slideDown = new DoubleAnimation
{
From = Canvas.GetBottom(element),
To = Canvas.GetBottom(element) - element.Height,
Duration = new Duration(TimeSpan.FromSeconds(1)),
AutoReverse = true
};
slideDown.Completed += (sender, e) => Test(sender, e, element, canvas);
element.BeginAnimation(Canvas.BottomProperty, slideDown);
}
}
}
I'm not 100% but I think the Animation becomes Freezable after it executes, so we cant modify after
BTW, you can have multiple animations on a object but you need to use "StoryBoard".
Storyboard example:
var slideDown = new DoubleAnimation { From = 100, To = 200, Duration = new Duration(TimeSpan.FromSeconds(5)), AutoReverse = true };
var slideLeft = new DoubleAnimation { From = 100, To = 200, BeginTime = TimeSpan.FromSeconds(5), Duration = new Duration(TimeSpan.FromSeconds(5)), AutoReverse = true };
Storyboard storyBoard = new Storyboard();
storyBoard.Children.Add(slideDown);
storyBoard.Children.Add(slideLeft);
Storyboard.SetTargetName(slideDown, myCanvas.Name);
Storyboard.SetTargetName(slideLeft, myCanvas.Name);
Storyboard.SetTargetProperty(slideLeft, new PropertyPath(Canvas.LeftProperty));
Storyboard.SetTargetProperty(slideDown, new PropertyPath(Canvas.TopProperty));
myCanvas.BeginStoryboard(storyBoard);
How can I programatically change the Color of a Rectangle in my Grid?
ColorAnimation myColorAnimation = new ColorAnimation();
myColorAnimation.From = Colors.Red;
myColorAnimation.To = Colors.Blue;
myColorAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(500));
myColorAnimation.AutoReverse = false;
myStoryboard = new Storyboard();
myStoryboard.Children.Add(myColorAnimation);
Storyboard.SetTargetName(myColorAnimation, ?); // What do I put here
Storyboard.SetTargetProperty(myColorAnimation, new PropertyPath //What do I put here?
OK, I found a way to do this:
I create a StoryBoard for each Grid item:
List<Storyboard> _animatableGridRectToGray = new List<Storyboard>();
List<Storyboard> _animatableGridRectToWhite = new List<Storyboard>();
and populate:
private void initAnimatableGridRectangles()
{
int index = 1;
foreach (Rectangle rect in SequenceGrid.Children)
{
SolidColorBrush tempBrush = new SolidColorBrush();
rect.Fill = tempBrush;
string brushName = "Brush" + index;
_gridBrushes.Add(brushName, tempBrush);
this.RegisterName(brushName, tempBrush);
Storyboard tempSBToGray = new Storyboard();
Storyboard tempSBToWhite = new Storyboard();
ColorAnimation tempColAnimToGray = getAnimToGray();
ColorAnimation tempColAnimToWhite = getAnimToWhite();
tempSBToGray.Children.Add(tempColAnimToGray);
tempSBToWhite.Children.Add(tempColAnimToWhite);
Storyboard.SetTargetName(tempColAnimToGray, brushName);
Storyboard.SetTargetName(tempColAnimToWhite, brushName);
Storyboard.SetTargetProperty(tempColAnimToGray, new PropertyPath(SolidColorBrush.ColorProperty));
Storyboard.SetTargetProperty(tempColAnimToWhite, new PropertyPath(SolidColorBrush.ColorProperty));
_animatableGridRectToGray.Add(tempSBToGray);
_animatableGridRectToWhite.Add(tempSBToWhite);
index++;
}
}
private ColorAnimation getAnimToGray()
{
ColorAnimation colAnim = new ColorAnimation();
colAnim.To = Colors.Gray;
colAnim.Duration = new Duration(TimeSpan.FromMilliseconds(500));
colAnim.AutoReverse = false;
return colAnim;
}
private ColorAnimation getAnimToWhite()
{
ColorAnimation colAnim = new ColorAnimation();
colAnim.To = Colors.White;
colAnim.Duration = new Duration(TimeSpan.FromMilliseconds(500));
colAnim.AutoReverse = false;
return colAnim;
}
Then I can animate like so:
_animatableGridRectToGray[index].Begin(this);
I use the following code to connect two ScatterViewItems. Unfortunately this does not work because the center property isn't asingle value. But I can't read out values x and y from the CenterProperty:
Line l = new Line();
l.Stroke = Brushes.Green;
l.StrokeThickness = 10;
Binding x1 = new Binding(); x1.Path = new PropertyPath(ScatterViewItem.CenterProperty);
x1.Converter = new MyConverter();
x1.ConverterParameter = root;
Binding y1 = new Binding(); y1.Path = new PropertyPath(ScatterViewItem.CenterProperty);
y1.Converter = new MyConverter();
y1.ConverterParameter = root;
Binding x2 = new Binding(); x2.Path = new PropertyPath(ScatterViewItem.CenterProperty);
x2.Converter = new MyConverter();
x2.ConverterParameter = level1;
Binding y2 = new Binding(); y2.Path = new PropertyPath(ScatterViewItem.CenterProperty);
y2.Converter = new MyConverter();
y2.ConverterParameter = level1;
x1.Source = y1.Source = root;
x2.Source = y2.Source = level1;
l.SetBinding(Line.X1Property, x1);
l.SetBinding(Line.Y1Property, y1);
l.SetBinding(Line.X2Property, x2);
l.SetBinding(Line.Y2Property, y2);
Dependencies.Children.Add(l);
l.Tag = new Call(focus, file);
Contacts.AddPreviewContactDownHandler(l, OnLineDown);
SizeChangedEventHandler act = (Object s, SizeChangedEventArgs args) =>
{
BindingOperations.GetBindingExpressionBase(l, Line.X1Property).UpdateTarget();
BindingOperations.GetBindingExpressionBase(l, Line.Y1Property).UpdateTarget();
BindingOperations.GetBindingExpressionBase(l, Line.X2Property).UpdateTarget();
BindingOperations.GetBindingExpressionBase(l, Line.Y2Property).UpdateTarget();
};
root.SizeChanged += act;
level1.SizeChanged += act;
I'm now using the followng solution, proposed in the Microsoft Surface Development forum by Sebastian:
XAML:
<s:SurfaceWindow
x:Class="Lines.SurfaceWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://schemas.microsoft.com/surface/2008"
Title="Lines"
>
<Grid>
<Canvas x:Name="LineHost"/>
<s:ScatterView x:Name="ScatterView"/>
</Grid>
</s:SurfaceWindow>
Code-behind:
private void BindLineToScatterViewItems(Line line, ScatterViewItem origin,
ScatterViewItem destination)
{
// Bind line.(X1,Y1) to origin.ActualCenter
BindingOperations.SetBinding(line, Line.X1Property, new Binding {
Source = origin, Path = new PropertyPath("ActualCenter.X") });
BindingOperations.SetBinding(line, Line.Y1Property, new Binding {
Source = origin, Path = new PropertyPath("ActualCenter.Y") });
// Bind line.(X2,Y2) to destination.ActualCenter
BindingOperations.SetBinding(line, Line.X2Property, new Binding {
Source = destination, Path = new PropertyPath("ActualCenter.X") });
BindingOperations.SetBinding(line, Line.Y2Property, new Binding {
Source = destination, Path = new PropertyPath("ActualCenter.Y") });
}
Then if you want to create a line between two ScatterViewItems, simply do this:
var origin = new ScatterViewItem();
var destination = new ScatterViewItem();
Line line = new Line { Stroke = Brushes.Black, StrokeThickness = 2.0 };
BindLineToScatterViewItems(line, origin, destination);
ScatterView.Items.Add(origin);
ScatterView.Items.Add(destination);
LineHost.Children.Add(line);