I got a working code for scaling frameworkelements in WPF via the ManipulationDelta method. It works with all kind of elements, as buttons, shapes or textblock, but not with textboxes.
Does anybody know how I can fix it?
Edit: Here´s a simpified Version of my Code:
private void canvas_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
var element = e.Source as FrameworkElement;
var transformation = element.RenderTransform as MatrixTransform;
var matrix = transformation == null ? Matrix.Identity : transformation.Matrix;
matrix.ScaleAt(e.DeltaManipulation.Scale.X,
e.DeltaManipulation.Scale.Y,
1,
1);
}
matrix.RotateAt(e.DeltaManipulation.Rotation,
e.ManipulationOrigin.X,
e.ManipulationOrigin.Y);
matrix.Translate(e.DeltaManipulation.Translation.X,
e.DeltaManipulation.Translation.Y);
element.RenderTransform = new MatrixTransform(matrix);
e.Handled = true;
}
The elements are created genericly, but it´s the same as this xaml:
<Canvas Name="SomeCanvas" ManipulationDelta="canvas_ManipulationDelta">
<TextBox Canvas.Left="400" Canvas.Top="200" Height="50" Name="s3" IsManipulationEnabled = "true" Background="#57FF3ACB" />
</Canvas>
This is because TextBox handles MouseDown events internally. They never get called, so the manipulation can't work. Here is the explanation:
http://msdn.microsoft.com/es-es/library/ms750580(v=vs.85).aspx
Alternatively, you could wrap the TextBox in a Border:
<Canvas Name="SomeCanvas" ManipulationDelta="canvas_ManipulationDelta">
<Border Canvas.Left="400" Canvas.Top="200" Background="Transparent" IsManipulationEnabled="True">
<TextBox Height="50" Name="s3" Background="#57FF3ACB" IsHitTestVisible="False" />
</Border>
</Canvas>
Put the IsHitTestVisible property to False in order to let the Mouse events pass from the TextBox to the Border.
Furthermore, you need to set the Border's Background to make it hit test visible.
Related
I am implementing a scrolling text that when pointer enters it, it starts scrolling its content.
I am able to get it scrolling using the code below:
private DispatcherTimer ScrollingTextTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(16) };
ScrollingTextTimer.Tick += (sender, e) =>
{
MainTitleScrollViewer.ChangeView(MainTitleScrollViewer.HorizontalOffset + 3, null, null);
if (MainTitleScrollViewer.HorizontalOffset == MainTitleScrollViewer.ScrollableWidth)
{
MainTitleScrollViewer.ChangeView(0, null, null);
ScrollingTextTimer.Stop();
}
};
XAML:
<ScrollViewer
x:Name="MainTitleScrollViewer"
Grid.Row="0"
Grid.Column="1"
Margin="10,5"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Disabled">
<TextBlock
x:Name="MainTitleTextBlock"
VerticalAlignment="Bottom"
FontSize="24"
Foreground="White" />
</ScrollViewer>
However, there is an additional feature that I want to implement. When the text scrolls to its end, I don't want it to scroll back to the start. I want it to keep scrolling to the start. You can see what I mean from the screenshots I posted below. The screenshots are from Groove Music. You may need to check it out if I didn't explain my question well.
A possible solution might be doubling the text and putting some space between them. But I don't know when to stop scrolling if so.
The effect of this kind of marquee is recommended to use Storyboard. The timer may cause lack due to time interval.
Here is a complete demo, I hope to help you.
xaml
<Grid>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="Gray" BorderThickness="1" Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="ms-appx:///Assets/StoreLogo.png" Width="100" Height="100" VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" Margin="20,0,0,0" VerticalAlignment="Center">
<ScrollViewer Width="200"
PointerEntered="ScrollViewer_PointerEntered"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
PointerExited="ScrollViewer_PointerExited">
<TextBlock FontSize="25" x:Name="TitleBlock">
<TextBlock.RenderTransform>
<TranslateTransform X="0"/>
</TextBlock.RenderTransform>
</TextBlock>
</ScrollViewer>
<TextBlock FontSize="20" FontWeight="Bold" Text="Gotye" Margin="0,10,0,0"/>
</StackPanel>
</Grid>
</Grid>
xaml.cs
Storyboard _scrollAnimation;
public ScrollTextPage()
{
this.InitializeComponent();
string text = "How about you?";
TitleBlock.Text = text + " " + text;
}
private void ScrollViewer_PointerEntered(object sender, PointerRoutedEventArgs e)
{
AnimationInit();
_scrollAnimation.Begin();
}
private void ScrollViewer_PointerExited(object sender, PointerRoutedEventArgs e)
{
_scrollAnimation.Stop();
}
public void AnimationInit()
{
_scrollAnimation = new Storyboard();
var animation = new DoubleAnimation();
animation.Duration = TimeSpan.FromSeconds(5);
animation.RepeatBehavior = new RepeatBehavior(1);
animation.From = 0;
// Here you need to calculate based on the number of spaces and the current FontSize
animation.To = -((TitleBlock.ActualWidth/2)+13);
Storyboard.SetTarget(animation, TitleBlock);
Storyboard.SetTargetProperty(animation, "(UIElement.RenderTransform).(TranslateTransform.X)");
_scrollAnimation.Children.Add(animation);
}
Simply put, scrolling the TextBlock horizontally is more controllable than scrolling the ScrollViewer.
The idea is similar to yours, using a string stitching method to achieve seamless scrolling, and calculate the width of the space by the current font size, so as to accurately scroll to the beginning of the second string.
Best regards.
This is my way of doing it and source code is here(xaml) and here(csharp):
I created a UserControl called ScrollingTextBlock.
This is XAML content of the UserControl.
<Grid>
<ScrollViewer x:Name="TextScrollViewer">
<TextBlock x:Name="NormalTextBlock" />
</ScrollViewer>
<ScrollViewer x:Name="RealScrollViewer">
<TextBlock x:Name="ScrollTextBlock" Visibility="Collapsed" />
</ScrollViewer>
</Grid>
Basically, you need two ScrollViewers that overlaps.
The first ScrollViewer is for detecting if the text is scrollable. And the TextBlock in it is for putting the text.
The second ScrollViewer is the real ScrollViewer. You will be scrolling this one not the first one. And the TextBlock in it will have its Text equal to
ScrollTextBlock.Text = NormalTextBlock.Text + new string(' ', 10) + NormalTextBlock.Text
The new string(' ', 10) is just some blank space to make your text not look concatenated tightly, which you can see from the image in the question. You can change it into whatever you want.
Then in the csharp code you need (explanations are in the comments):
// Using 16ms because 60Hz is already good for human eyes.
private readonly DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(16) };
public ScrollingTextBlock()
{
this.InitializeComponent();
timer.Tick += (sender, e) =>
{
// Calculate the total offset to scroll. It is fixed after your text is set.
// Since we need to scroll to the "start" of the text,
// the offset is equal the length of your text plus the length of the space,
// which is the difference of the ActualWidth of the two TextBlocks.
double offset = ScrollTextBlock.ActualWidth - NormalTextBlock.ActualWidth;
// Scroll it horizontally.
// Notice the Math.Min here. You cannot scroll more than offset.
// " + 2" is just the distance it advances,
// meaning that it also controls the speed of the animation.
RealScrollViewer.ChangeView(Math.Min(RealScrollViewer.HorizontalOffset + 2, offset), null, null);
// If scroll to the offset
if (RealScrollViewer.HorizontalOffset == offset)
{
// Re-display the NormalTextBlock first so that the text won't blink because they overlap.
NormalTextBlock.Visibility = Visibility.Visible;
// Hide the ScrollTextBlock.
// Hiding it will also set the HorizontalOffset of RealScrollViewer to 0,
// so that RealScrollViewer will be scrolling from the beginning of ScrollTextBlock next time.
ScrollTextBlock.Visibility = Visibility.Collapsed;
// Stop the animation/ticking.
timer.Stop();
}
};
}
public void StartScrolling()
{
// Checking timer.IsEnabled is to avoid restarting the animation when the text is already scrolling.
// IsEnabled is true if timer has started, false if timer is stopped.
// Checking TextScrollViewer.ScrollableWidth is for making sure the text is scrollable.
if (timer.IsEnabled || TextScrollViewer.ScrollableWidth == 0) return;
// Display this first so that user won't feel NormalTextBlock will be hidden.
ScrollTextBlock.Visibility = Visibility.Visible;
// Hide the NormalTextBlock so that it won't overlap with ScrollTextBlock when scrolling.
NormalTextBlock.Visibility = Visibility.Collapsed;
// Start the animation/ticking.
timer.Start();
}
I am new in coding and atm trying to understand events what is an annoying stage but super important I guess. I just made a tic tac toe game and it is working but not really "beautiful" coded. I really have problems in using the events. well I am reading 3 different books, google is my best friend and I guess I red all the StackOverflow posts about events but the bulb in my head is never shining :P so I will give you boys a part of my code and I added some comments for the understanding:
/*I have 9 buttons(3x3) which are the play field */
private void Feld1_Click(object sender, RoutedEventArgs e)
{
// in my game each player have 1 Radiobutton so they check a RButton and then it's their turn
if (Player1RButton.IsChecked == true)
{
// i dont wanted to use "X" or "O" so i chose the colors green and yellow
Feld1.Background = Brushes.Green;
// Feld1G is for example that Player1 (green) is "owning" this
// field/button so i can later check who won the game
Feld1G = 1;
Feld1Y = 0;
}
if (Player2RButton.IsChecked == true)
{
//here is the same thing happening like in the example of green
Feld1.Background = Brushes.Yellow;
Feld1Y = 1;
Feld1G = 0;
}
}
private void Feld2_Click(object sender, RoutedEventArgs e)
{
if (Player1RButton.IsChecked == true)
{
Feld2.Background = Brushes.Green;
Feld2G = 1;
Feld2Y = 0;
}
if (Player2RButton.IsChecked == true)
{
Feld2.Background = Brushes.Yellow;
Feld2Y = 1;
Feld2G = 0;
}
}
here is an example how the ui looks like:tic tac toe exampe
now what I would like to do in my words cause I don't know how to code it:
// I have no idea if this is the right start
public void OnClick (EventArgs e)
{
/* now I guess here have to happen something like this, for example, field9 was clicked and radiobutton2 is checked: know that button9 have been clicked know radiobutton is checked and now brush (this.button?) button/field9 and set Feld9Y=1;
}
*/
I want to make it a bit more clearly here: I want all the functions run from the method above and not in each button event for itself
so my questions:
1. what do I have to do to make this work the way i explained above to make 1 method for all of my buttons
and it would be great if you boys could make a good story why I have to use it this way and how it works so a brainless ape like me can understand the event stuff and the bulb will finally shine bright like a diamond :P
Edit:here is the link for my whole code:
https://codereview.stackexchange.com/questions/164462/c-events-in-a-tic-tac-toe-game
Here is a quick example to get you started. I only implemented changing the background and nothing more.
Below is the xaml. I set up a very simple board with 9 regular buttons and 2 radio buttons. I did not implement anything else.
<Grid x:Name="board">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Content="Button"/>
<Button Content="Button"
Grid.Column="1" />
<Button Content="Button"
Grid.Column="2"/>
<Button Content="Button"
Grid.Row="1" />
<Button Content="Button"
Grid.Row="1"
Grid.Column="1" />
<Button Content="Button"
Grid.Row="1"
Grid.Column="2" />
<Button Content="Button"
Grid.Row="2" />
<Button Content="Button"
Grid.Row="2"
Grid.Column="1" />
<Button Content="Button"
Grid.Row="2"
Grid.Column="2" />
<RadioButton x:Name="playerOneRadioButton"
IsChecked="True"
Content="Player 1"
Grid.Column="3"
HorizontalAlignment="Left"
Margin="10,10,0,0"
Grid.Row="1"
VerticalAlignment="Top" />
<RadioButton x:Name="playerTwoRadioButton"
Content="Player 2"
Grid.Column="3"
HorizontalAlignment="Left"
Margin="10,30,0,0"
Grid.Row="1"
VerticalAlignment="Top" />
</Grid>
Below is the code behind.
I hooked up each buttons click event to point to the Button_Click method.
In that method I first cast the sender to type Button. I then change the background color of the button to either yellow or green.
public partial class MainWindow: Window
{
public MainWindow( )
{
InitializeComponent( );
// Iterate through all of the child elements
// contained in the Grid control which I named "board".
foreach( var control in board.Children.OfType<Button>( ) )
{
// Hook up the event handler of each button.
control.Click += Button_Click;
}
}
private void Button_Click( object sender, RoutedEventArgs e )
{
// Safe cast the sender to type Button.
var button = sender as Button;
if( button == null ) return;
// Change the background color of the button
// yellow or green based on which radio button
// is checked.
button.Background = playerOneRadioButton.IsChecked.Value ? Brushes.Green : Brushes.Yellow;
}
}
EDIT:
Question 1: The Grid which I have on the design surface is named "board". Children is a property of the Grid control. All child elements (elements that reside inside of the grid, like the buttons) are added to the Children property of the grid control. The Children property is a collection, or you could say a list, of all child elements that reside in the grid control. I loop through each child control in the grid that is of type button.
Question 2: The ?: is called a ternary operator. It is used for writing a conditional statement (an if statement). You can also write it as follows:
if( playerOneRadioButton.IsChecked.Value )
{
button.Background = Brushes.Green;
}
else
{
button.Background = Brushes.Yellow;
}
Question 3: I'm currently casting the object sender to type button using whats called a "safe cast". In other words, if the cast fails (say sender wasn't a button and was some other control instead) then null is returned. I check for this null condition to ensure that the cast was successful. If the button variable is null then the cast was not successful and I want to exit (return) out of that method. No code below the
if(button == null) return;
will execute.
The single method you want to use should look like this:
private void Feld_Click(object sender, RoutedEventArgs e)
{
var currentButton = (Button)sender;
if (Player1RButton.IsChecked == true)
{
currentButton.Background = Brushes.Green;
}
}
Add this as OnClick handler for all the buttons.
From there you can calculate the Feld color whenever you need it, by accessing the Background property in a separate method.
Im trying to bind my usercontrols (that have a move on mouse left btn logic inside its code behind) margin inside a datatemplate of an itemscontrol. However when being bound inside the datatemplate it doesnt update itself when a move on the grid behind it (which itself is a usercontrol aswell and has a move on mouse middle button logic inside its code behind).
The code behind of those is: (where in the grid it reacts to middle mouse)
private void Control_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
isDragging = true;
var draggableControl = sender as UserControl;
lasttransform = new Point(0, 0);
clickPosition = e.GetPosition(this.Parent as UIElement);
draggableControl.CaptureMouse();
}
private void Control_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (isDragging == true)
{
isDragging = false;
var draggable = sender as UserControl;
draggable.ReleaseMouseCapture();
completetransform = Point.Add(completetransform,new Vector( lasttransform.X, lasttransform.Y));
lasttransform = new Point(0, 0);
}
}
private void Control_MouseMove(object sender, MouseEventArgs e)
{
var draggableControl = sender as UserControl;
if (isDragging && draggableControl != null && draggableControl.GetType() == typeof(BaseNode))
{
Point currentPosition = e.GetPosition(this.Parent as UIElement);
currentPosition = new Point(currentPosition.X, currentPosition.Y);
var transform = draggableControl.RenderTransform as TranslateTransform;
if (transform == null)
{
transform = new TranslateTransform();
draggableControl.RenderTransform = transform;
}
transform.X = completetransform.X + (currentPosition.X - clickPosition.X);
transform.Y = completetransform.Y + (currentPosition.Y - clickPosition.Y);
lasttransform = new Point((currentPosition.X - clickPosition.X), (currentPosition.Y - clickPosition.Y));
}
}
}
When i now want to show my controls in some window like:
<Grid>
<my:EventGrid x:Name="XDisplayedEventGrid" Margin="-20" DataContext="{Binding DisplayedEventGrid}"/>
<Grid Background="Red" Width="100" Height="100" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="{Binding DisplayedEventGrid.ActualTransform, Converter={StaticResource ResourceKey=PointToMarginConverter}}"/>
<my:BaseNode HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100" Margin="{Binding DisplayedEventGrid.ActualTransform, Converter={StaticResource ResourceKey=PointToMarginConverter}}"/>
<ItemsControl ItemsSource="{Binding DisplayedNodes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<my:BaseNode HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100" Margin="{Binding ElementName=XDisplayedEventGrid, Path=ActualTransform, Converter={StaticResource ResourceKey=PointToMarginConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Where 'my:EventGrid 'is the movable grid, 'my:BaseNode' is a control to test everything and DataTemplate> my:BaseNode .../> /DataTemplate> is the actual displaying control for these usercontrols.
What should happen:
1) When you move the grid behind the visual brush makes it look like you can scroll unlimitedly.
2) The 'Grid Background="Red"' stays at its place on the eventgrid.
3) The Margin is bound to the eventgrid's moved coordinates which is translated to a margin by a converter, so for the user it looks like the controls stay on place on the grid and get moved out of view if the user looks at another portion of the grid.
4) When a node is moved its RenderTransform is set so it can be placed by and bound to a margin while being able to reposition it locally with the RenderTransform.
My Problem now is, that when the test-node has no DataContext bound it has the behavior of the grid and moves accordingly, but if it has one set it acts like the node inside the datatemplate and stays at 0,0 of the window.
The Datacontext of the node is an empty class deriving of a standard implementation of INotifyPropertyChanged.
When not having a datacontext bound inside the datatemplate it still has the same wrong behavior.
Where is my error and
are there any better controls to store externally marged usercontrols?
Thanks
ShinuSha
I'm developing a Windows Phone 8.1 app with a MapControl as the main focal point of my app. I basically want to integrate a similar experience design wise as the Nokia Here Maps App.
The bottom black Frame can be pulled upwards to reveal its content.
How am I able to do this?
EDIT
I now have:
ExtraInfo.RenderTransform = new TranslateTransform();
ExtraInfo.ManipulationDelta += OnManipulationDelta;
ExtraInfo.ManipulationMode = Windows.UI.Xaml.Input.ManipulationModes.TranslateY;
in my constructor
The eventhandler
private void OnManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
{
try
{
Storyboard myStoryboard = (Storyboard)this.Resources["TestStoryboard"];
TranslateTransform myTranslate = new TranslateTransform();
myTranslate.Y = e.Delta.Translation.Y;
ExtraInfo.RenderTransform = myTranslate;
Storyboard.SetTarget(myStoryboard.Children[0] as DoubleAnimation, ExtraInfo);
myStoryboard.Begin();
}
catch (Exception)
{
Debug.WriteLine("Animation called");
}
}
My XAML
<Grid>
<StackPanel>
<Maps:MapControl Height="{Binding ActualHeight, ElementName=pageRoot}" x:Name="Map" LandmarksVisible="False" ZoomLevel="{Binding zoomlevel, Mode=TwoWay, FallbackValue=8}" MapServiceToken="#######" TrafficFlowVisible="True">
<Image x:Name="NewCheckImage" Visibility="Collapsed" Maps:MapControl.Location="{Binding Center, ElementName=Map}" Maps:MapControl.NormalizedAnchorPoint=".5,.5"></Image>
</Maps:MapControl>
<StackPanel x:Name="ExtraInfo" Height="{Binding ActualHeight, ElementName=pageRoot}" Background="Black" Margin="0,-250,0,0" Canvas.ZIndex="1">
<StackPanel.RenderTransform>
<TranslateTransform X="0" Y="0">
</TranslateTransform>
</StackPanel.RenderTransform>
</StackPanel>
</StackPanel>
</Grid>
The storyboard
<Page.Resources>
<Storyboard x:Key="TestStoryboard">
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"
To="0">
</DoubleAnimation>
</Storyboard>
</Page.Resources>
But the panel does some jumpy unpredictable moves.
Set RenderTransform = new TranslateTransform() for your StackPanel, handle Page ManipulationDelta event and there change your (StackPanel.RenderTransform as TranslateTransform).Y value. Use Storyboard (animation on RenderTransform) to achieve effect of pulling up/down on touch release.
You should do something like this: (pseudocode)
void OnStackPanelLoaded(..)
{
StackPanel.VerticalAlingment = VerticalAlingment.Bottom;
StackPanel.RenderTransform = new TranslateTransform(0, StackPanel.ActualHeight);
// translate stackpanel out of page, be sure stackpanel has bottom alingment of grid
}
void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs args)
{
var stackPanelTransform = MyStackPanel.RenderTransform as TranslateTransform;
stackPanelTransform.Y += args.Delta.Translation.Y;
}
You should also register to ManipulationCompleted event and there run close/open animation.
void OnManipulationCompleted(object sender, ManipulationCompletedEventArgs args)
{
// you can also add additional logic here to reverse open/close logic
// for example: if user touch translation delta is too small then instead of opening panel - close it like in Here
if (IsPanelOpened())
Resources["ClosePanelStoryboard"].BeginStoryboard();
else
Resources["OpenPanelStoryboard"].BeginStoryboard();
}
bool IsPanelOpened()
{
var translateTransform = myStackPanel.RenderTransform as TranslateTransform;
return translateTransform.Y > double.Epsilon;
}
Check DoubleAnimation.EasingFunction - to achieve same animation effect like in Here Drive (animated open/close).
Implementing good panel takes time. Initially it should have Opacity = 0, IsHitTest = false (because it can blink on page start - before RenderTransform is set) - you should also register to SizeChanged event in StackPanel to ensure that TranslateTransform is set correctly (sometimes you can get StackPanel.ActualHeight value of 0 - most likely in release build because they're faster).
I have a canvas, and I need to put an (for example) ellipse on it, not from XAML but from code. So I do
Ellipse e1;
public MainWindow()
{
...
...
e1 = new Ellipse();
e1.Height = 100;
e1.Width = 100;
e1.Stroke = Brushes.Red;
e1.StrokeThickness = 5;
Canvas.SetLeft(e1,40);
Canvas.SetTop(e1,50);
e1.MouseDown += ellipse_MouseDown;
Canvas1.Children.Add(e1);
}
private void ellipse_MouseDown(object sender, MouseButtonEventArgs e)
{
Ellipse el = (Ellipse)sender;
el.Stroke = Brushes.Green;
buttonAdd.Content = "New_TEXT";
}
But it doesn't react on clicking. Anyway, I tried to add this ellipse_MouseDownmethod to ellipse that was created from XAML - and it works.
<Canvas x:Name="Canvas1" HorizontalAlignment="Left" Height="421" Margin="10,10,0,0" VerticalAlignment="Top" Width="346">
<Ellipse x:Name="ellipse" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="111" Margin="117,152,0,0" Stroke="Black" VerticalAlignment="Top" Width="131" MouseDown="ellipse_MouseDown" MouseMove="ellipse_MouseMove" MouseUp="ellipse_MouseUp"/>
</Canvas>
Where can be a problem?
UPD.
According to Rohit Vats's answer just add
e1.Fill = Brushes.Transparent;
or
e1.Fill = new SolidColorBrush((Color)ColorConverter
.ConvertFromString("#FFF4F4F5"));
'cause by default Fill is null which doesn't respond to mouse events
You need to set Fill to Transparent so that it can react to mouse events. By default Fill is null which doesn't respond to mouse events -
e1.Stroke = Brushes.Red;
e1.Fill = Brushes.Transparent; <-- HERE
UPDATE
As evident from XAML code, you are setting Fill to #FFF4F4F5 but not setting it from code behind.
e1.Fill = new SolidColorBrush((Color)ColorConverter
.ConvertFromString("#FFF4F4F5"));