Michael Lin Michael Lin - 20 days ago 8
C# Question

EllipseGeometry Shrink & Fade Without Exceeding Canvas Bounds in C# WPF

How to make animation stay within the canvas at bigger sizes when the user clicks around the edge of the canvas? Currently, if sizes are too big and if user clicks near the edge of the canvas, the ellipse will grow outside of the canvas to cover the buttons. I need the animation to stay within the canvas to make it look like a slice of pizza essentially.

Should look like this:
Size 50 where user clicks near top left of canvas

Currently looks like this:
Size 50 where user clicks near top left of canvas

Xaml:

<Window.Resources>
<Storyboard x:Key="anim">
<DoubleAnimation
Storyboard.TargetName="myCircle"
Storyboard.TargetProperty="RadiusX"
AutoReverse="True"/>
<DoubleAnimation
Storyboard.TargetName="myCircle"
Storyboard.TargetProperty="RadiusY"
AutoReverse="True"/>
<DoubleAnimation
Storyboard.TargetName="path"
Storyboard.TargetProperty="Opacity"
AutoReverse="True"/>
</Storyboard>
</Window.Resources>

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="23"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Margin="0,0,0,1">
<Menu DockPanel.Dock="Top" Height="23">
<MenuItem Header="Main" RenderTransformOrigin="-1.896,0.643" HorizontalAlignment="Left" Width="39" Height="23">
<MenuItem Header="Exit, Esc" Click="MenuItem_Click_Exit"/>
</MenuItem>
</Menu>
</DockPanel>

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1" Name="pane">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" Name="pane2">
<Grid.RowDefinitions>
<RowDefinition Height="35"/>
<RowDefinition Height="35"/>
<RowDefinition Height="35"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>

<Label Content="Size" Grid.Row="0" Grid.Column="0" Height="25" VerticalAlignment="Stretch"/>
<Label Content="Fill Color" Grid.Row="1" Grid.Column="0" Height="25" VerticalAlignment="Stretch"/>
<Label Content="Stroke Thickness" Grid.Row="2" Grid.Column="0" Height="25" VerticalAlignment="Stretch"/>
<Label Content="Stroke Color" Grid.Row="3" Grid.Column="0" VerticalAlignment="Top" Height="25"/>

<Slider x:Name="Slider_Size" Grid.Row="0" Grid.Column="1" Height="20" Width="45"
Minimum="5" Maximum="50"
AutoToolTipPlacement="BottomRight"
TickFrequency="1"
IsSnapToTickEnabled="True"
PreviewMouseUp="Slider_Size_PreviewMouseUp"/>
<Label Name="tempSize" Content="{Binding Path=Value, ElementName=Slider_Size}" Margin="0,25,0,131" Grid.Row="3" Visibility="Hidden"/>
<ComboBox Name="ComboBox_FillColor" Grid.Row="1" Grid.Column="1" Height="20" Width="45" SelectionChanged="ComboBox_FillColor_Selected"/>
<TextBox Name="textBox" Grid.Row="2" Grid.Column="1" Height="20" Width="45" TextChanged="textBox_TextChanged"/>
<ComboBox Name="ComboBox_StrokeColor" Grid.Row="3" Grid.Column="1" VerticalAlignment="Top" Height="20" Width="45" SelectionChanged="ComboBox_StrokeColor_Selected"/>
</Grid>

<Border Name ="border" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="Black" Grid.Column="1" BorderThickness="2">
<Canvas Name="canvas" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="Canvas_MouseDown">
<Path x:Name="path">
<Path.Data>
<EllipseGeometry x:Name="myCircle"/>
</Path.Data>
</Path>
<Canvas.Background>
<SolidColorBrush Color="White" Opacity="0"/>
</Canvas.Background>
</Canvas>
</Border>
</Grid>
</Grid>


C#:

public partial class MainWindow : Window
{
private int size;
private SolidColorBrush fillColor;
private SolidColorBrush strokeColor;
private List<SolidColorBrush> colors;
private int fillIndex;
private int strokeIndex;
private int strokeThickness = 1;
private int fillColorDefault;
private int strokeColorDefault;
private Point? _start = null;
public MainWindow()
{
InitializeComponent();
addColors();
textBox.Text = strokeThickness.ToString();
parse();
}
private void MenuItem_Click_Exit(object sender, RoutedEventArgs e) { Environment.Exit(1); }

private void Window_KeyUp_ESC(object sender, KeyEventArgs e)
{
if (Key.Escape == e.Key)
MenuItem_Click_Exit(sender, e);
}
private void addColors()
{
colors = typeof(Brushes).GetProperties().Select(p => p.GetValue(null, null) as SolidColorBrush).ToList();

int count = 0;
foreach (SolidColorBrush color in colors)
{
ComboBox_FillColor.Items.Add(new Rectangle() { Height = 12, Width = 17.5, Fill = color });
ComboBox_StrokeColor.Items.Add(new Rectangle() { Height = 12, Width = 17.5, Fill = color });

if (color.Color == Colors.Red)
{
fillIndex = count;
fillColor = colors[fillIndex];
ComboBox_FillColor.SelectedIndex = count;
fillColorDefault = count;
}

if (color.Color == Colors.Black)
{
strokeIndex = count;
strokeColor = colors[strokeIndex];
ComboBox_StrokeColor.SelectedIndex = count;
strokeColorDefault = count;
}

count++;
}
}
private void ComboBox_FillColor_Selected(object sender, RoutedEventArgs e) { fillIndex = ComboBox_FillColor.SelectedIndex; fillColor = colors[fillIndex]; }

private void ComboBox_StrokeColor_Selected(object sender, RoutedEventArgs e) { strokeIndex = ComboBox_StrokeColor.SelectedIndex; strokeColor = colors[strokeIndex]; }

private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
path.Stroke = strokeColor;
path.StrokeThickness = strokeThickness;
path.Fill = fillColor;
path.HorizontalAlignment = HorizontalAlignment.Stretch;
path.VerticalAlignment = VerticalAlignment.Stretch;
path.Stretch = Stretch.None;
path.SetValue(Grid.ColumnProperty, 1);

_start = Mouse.GetPosition((UIElement)sender);
myCircle.Center = (Point)_start;

var sb = FindResource("anim") as Storyboard;

var x = sb.Children.First() as DoubleAnimation;
x.To = 2 * size;
x.Duration = new Duration(TimeSpan.FromSeconds(0.5));

var y = sb.Children.ElementAt(1) as DoubleAnimation;
y.To = 2 * size;
y.Duration = new Duration(TimeSpan.FromSeconds(0.5));

var z = sb.Children.Last() as DoubleAnimation;
z.From = 0.0;
z.To = 1.0;
z.Duration = new Duration(TimeSpan.FromSeconds(0.5));

sb.Begin(path);
}
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
//regex where any string of chars besides numbers
Regex pattern = new Regex(@"^([^0-9]*)$", RegexOptions.Compiled);


Match result = pattern.Match(textBox.Text);
if (textBox.Text.ToString() == string.Empty)
return;
else if (result.Success)
{
MessageBox.Show("Invalid character entered. Integer numbers only. Stroke Thickness will be reseted to a default of 1.");
strokeThickness = 1;
textBox.Text = strokeThickness.ToString();
textBox.SelectAll();
}
else
{
int x;
if (int.TryParse(textBox.Text, out x))
strokeThickness = int.Parse(textBox.Text);
}
}
private void Slider_Size_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
parse();
}
private void parse()
{
int x;
if (int.TryParse(tempSize.Content.ToString(), out x))
size = x;
}
}


}

Answer

So you don't need the ellipse to stay within the Canvas, but you want to clip away the parts leaving it, right? Just set ClipToBounds (of Canvas) to true (can be done in Xaml).

Comments