WPF Changing fill colour of ellipse - c#

So I'm trying to make 8 circles which all have different fill colours and all have different blinking speeds. So far I have been able to make them blink at different speeds, but I'm having trouble with making them all have different colours. My code so far:
private void Appear(Ellipse element, double duration, Brush colour)
{
element.Fill = colour;
DoubleAnimation db = new DoubleAnimation();
db.From = 0.0;
db.To = 1.0;
db.Duration = new Duration(TimeSpan.FromSeconds(duration));
db.RepeatBehavior = RepeatBehavior.Forever;
element.BeginAnimation(Ellipse.OpacityProperty, db);
}
private Brush SetEllipseColour(Ellipse element)
{
Random rnd = new Random();
int red = rnd.Next(0, 255);
int green = rnd.Next(0, 255);
int blue = rnd.Next(0, 255);
Brush fillColour = new SolidColorBrush(Color.FromRgb((byte)red, (byte)green, (byte)blue));
return fillColour;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
List<Ellipse> elements = new List<Ellipse>();
elements.Add(Circle1);
elements.Add(Circle2);
elements.Add(Circle3);
elements.Add(Circle4);
elements.Add(Circle5);
elements.Add(Circle6);
elements.Add(Circle7);
elements.Add(Circle8);
Random rnd = new Random();
foreach (Ellipse element in elements)
{
int r = rnd.Next(1, 10);
double duration = (Double)r / 10;
Appear(element, duration, SetEllipseColour(element));
}
}
And my WPF:
<Canvas Margin="10">
<Ellipse
x:Name="Circle1"
Fill="Black"
Height="100"
Width="100"/>
<Ellipse
x:Name="Circle2"
Fill="Black"
Height="100"
Width="100"
Margin="120,0,0,0"/>
<Ellipse
x:Name="Circle3"
Fill="Black"
Height="100"
Width="100"
Margin="240,0,0,0"/>
<Ellipse
x:Name="Circle4"
Fill="Black"
Height="100"
Width="100"
Margin="360,0,0,0"/>
<Ellipse
x:Name="Circle5"
Fill="Black"
Height="100"
Width="100"
Margin="0,120,0,0"/>
<Ellipse
x:Name="Circle6"
Fill="Black"
Height="100"
Width="100"
Margin="120,120,0,0"/>
<Ellipse
x:Name="Circle7"
Fill="Black"
Height="100"
Width="100"
Margin="240,120,0,0"/>
<Ellipse
x:Name="Circle8"
Fill="Black"
Height="100"
Width="100"
Margin="360,120,0,0"/>
</Canvas>
<Button x:Name="button1" Content="Start" Width="80" Height="20" Margin="0,200,0,0" Click="button1_Click"/>
Note: I know I can compress / change my code to make it neater or better, but for now I just want to get the colours working.
So currently the code I have changes the fill colour of all Ellipse elements, but I want to change it to just affect each Circle. How would I go about doing this?
Edit:
For those who are confused what Im trying to ask, I do not know how to individually change the fill colour of every Circle.

Set the instance of the Random class at the class level, check the below example, by clicking on the the Button that says Blink Em! the animation is triggered.
The XAML
<Window x:Class="Blink.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Blink"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" WindowState="Maximized">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button x:Name="BlinkEm" Content="Blink Em!" Height="30" Click="BlinkEm_Click"/>
<StackPanel x:Name="Container" Orientation="Horizontal" Loaded="Container_Loaded" Grid.Row="1"/>
</Grid>
</Window>
The code-behind
namespace Blink
{
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public Random random = new Random();
public MainWindow()
{
InitializeComponent();
}
public List<Ellipse> CreateCircles(int count)
{
List<Ellipse> circles = new List<Ellipse>();
for (int i = 0; i < count; i++)
{
var circle = new Ellipse
{
Height = 100,
Width = 100,
Margin = new Thickness(10),
Fill = Brushes.SkyBlue
};
circles.Add(circle);
}
return circles;
}
public void AddCircles()
{
var circles = this.CreateCircles(8);
foreach (var circle in circles)
{
Container.Children.Add(circle);
}
}
private void Container_Loaded(object sender, RoutedEventArgs e)
{
AddCircles();
}
private void BlinkEm_Click(object sender, RoutedEventArgs e)
{
foreach (Ellipse circle in Container.Children)
{
circle.Fill = GetRandomColor();
circle.BeginAnimation(Ellipse.OpacityProperty, GetBlinkAnimation());
}
}
public Brush GetRandomColor()
{
var red = Convert.ToByte(random.Next(0, 255));
var green = Convert.ToByte(random.Next(0, 255));
var blue = Convert.ToByte(random.Next(0, 255));
return new SolidColorBrush(Color.FromRgb(red, green, blue));
}
public DoubleAnimation GetBlinkAnimation()
{
var duration = random.NextDouble();
var animation = new DoubleAnimation
{
From = 0.0,
To = 1.0,
Duration = new Duration(TimeSpan.FromSeconds(duration)),
RepeatBehavior = RepeatBehavior.Forever
};
return animation;
}
}
}

I think your mistake here is that the Random object is being recreated every time. Try putting that into a field and initializing it once, or by sending it as a parameter to your SetEllipseColor method.
Due to random number generators not actually being random, they derive their "initial" random values from a seed value, often the current time. This means if you create a bunch of new Random instances in a very short time, they are likely to end up with the same seed and thus the same value.
(In more general terms, "Appear" and "SetEllipseColor" aren't very good method names. The former is vague and the latter doesn't actually describe what that method is doing.)

Related

Displaying grid lines around individual pixels when zooming

I'm experimenting with the concept of drawing grid lines over a control and was wondering what adjustments I might need to make to make this actually work. I found some code on another post that enables grid lines to be drawn OnRender over a canvas. Here's what that looks like:
public class MyCanvas : Canvas
{
public bool IsGridVisible = true;
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
base.OnRender(dc);
if (IsGridVisible)
{
// Draw GridLines
Pen pen = new Pen(Brushes.Black, 1);
pen.DashStyle = DashStyles.Solid;
for (double x = 0; x < this.ActualWidth; x += 2)
{
dc.DrawLine(pen, new Point(x, 0), new Point(x, this.ActualHeight));
}
for (double y = 0; y < this.ActualHeight; y += 2)
{
dc.DrawLine(pen, new Point(0, y), new Point(this.ActualWidth, y));
}
}
}
public MyCanvas()
{
DefaultStyleKey = typeof(MyCanvas);
}
}
This part: y += 2 indicates how many other pixels/points to wait before drawing next line, though I am uncertain of it's correctness.
Here's the xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ScrollViewer>
<local:MyCanvas>
<local:MyCanvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=Slider, Path=Value}" ScaleY="{Binding ElementName=Slider, Path=Value}"/>
</local:MyCanvas.LayoutTransform>
<Image Canvas.Top="2" Canvas.Left="2" Source="C:\Users\Me\Pictures\nyan-wallpaper2.jpg" Width="325" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</local:MyCanvas>
</ScrollViewer>
<Slider x:Name="Slider" Maximum="500" Grid.Row="1" Value="1"/>
</Grid>
Here are screenshots of what the above results in.
As you can see, the grid lines change in size as you zoom and the lines themselves do not snap around each individual pixel. I highlighted an example pixel in red to show how small the lines should be versus how they actually are.
I read that the thickness of the pen should be divided by the scale value, however, I tested this by replacing Pen pen = new Pen(Brushes.Black, 1); with Pen pen = new Pen(Brushes.Black, 1 / 3); and set the ScaleX and ScaleY of MyCanvas to 3. At that point, no lines showed at all.
Any help at all is immensely valued!
Got it working like this for anyone curious:
MainWindow.xaml.cs
namespace Test
{
public class MyCanvas : Canvas
{
public bool IsGridVisible = false;
#region Dependency Properties
public static DependencyProperty ZoomValueProperty = DependencyProperty.Register("ZoomValue", typeof(double), typeof(MyCanvas), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnZoomValueChanged));
public double ZoomValue
{
get
{
return (double)GetValue(ZoomValueProperty);
}
set
{
SetValue(ZoomValueProperty, value);
}
}
private static void OnZoomValueChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
{
}
#endregion
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
base.OnRender(dc);
IsGridVisible = ZoomValue > 4.75 ? true : false;
if (IsGridVisible)
{
// Draw GridLines
Pen pen = new Pen(Brushes.Black, 1 / ZoomValue);
pen.DashStyle = DashStyles.Solid;
for (double x = 0; x < this.ActualWidth; x += 1)
{
dc.DrawLine(pen, new Point(x, 0), new Point(x, this.ActualHeight));
}
for (double y = 0; y < this.ActualHeight; y += 1)
{
dc.DrawLine(pen, new Point(0, y), new Point(this.ActualWidth, y));
}
}
}
public MyCanvas()
{
DefaultStyleKey = typeof(MyCanvas);
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private WriteableBitmap bitmap = new WriteableBitmap(500, 500, 96d, 96d, PixelFormats.Bgr24, null);
private void Button_Click(object sender, RoutedEventArgs e)
{
int size = 1;
Random rnd = new Random(DateTime.Now.Millisecond);
bitmap.Lock(); // Lock() and Unlock() could be moved to the DrawRectangle() method. Just do some performance tests.
for (int y = 0; y < 500; y++)
{
for (int x = 0; x < 500; x++)
{
byte colR = (byte)rnd.Next(256);
byte colG = (byte)rnd.Next(256);
byte colB = (byte)rnd.Next(256);
DrawRectangle(bitmap, size * x, size * y, size, size, Color.FromRgb(colR, colG, colB));
}
}
bitmap.Unlock(); // Lock() and Unlock() could be moved to the DrawRectangle() method. Just do some performance tests.
Image.Source = bitmap; // This should be done only once
}
public void DrawRectangle(WriteableBitmap writeableBitmap, int left, int top, int width, int height, Color color)
{
// Compute the pixel's color
int colorData = color.R << 16; // R
colorData |= color.G << 8; // G
colorData |= color.B << 0; // B
int bpp = writeableBitmap.Format.BitsPerPixel / 8;
unsafe
{
for (int y = 0; y < height; y++)
{
// Get a pointer to the back buffer
int pBackBuffer = (int)writeableBitmap.BackBuffer;
// Find the address of the pixel to draw
pBackBuffer += (top + y) * writeableBitmap.BackBufferStride;
pBackBuffer += left * bpp;
for (int x = 0; x < width; x++)
{
// Assign the color data to the pixel
*((int*)pBackBuffer) = colorData;
// Increment the address of the pixel to draw
pBackBuffer += bpp;
}
}
}
writeableBitmap.AddDirtyRect(new Int32Rect(left, top, width, height));
}
}
}
MainWindow.xaml
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test"
mc:Ignorable="d"
Title="MainWindow"
Height="Auto"
Width="Auto"
WindowStartupLocation="CenterScreen"
WindowState="Maximized">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ScrollViewer>
<local:MyCanvas ZoomValue="{Binding ElementName=ScaleTransform, Path=ScaleX}">
<local:MyCanvas.LayoutTransform>
<ScaleTransform x:Name="ScaleTransform" ScaleX="{Binding ElementName=Slider, Path=Value}" ScaleY="{Binding ElementName=Slider, Path=Value}"/>
</local:MyCanvas.LayoutTransform>
<Image Canvas.Top="1" Canvas.Left="1" x:Name="Image" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</local:MyCanvas>
</ScrollViewer>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Slider x:Name="Slider" Maximum="100" Minimum="0.5" Value="1" Width="200"/>
<Button Click="Button_Click" Content="Click Me!"/>
</StackPanel>
</Grid>
</Window>
We generate a bitmap with random colored pixels and then render the grid lines only if zoomed up close. Performance-wise, this is actually better than expected. I should note, though, that if you attempt to zoom below 50%, the app crashes. Not sure if it's an issue with the grid lines being drawn at a minute size (IsGridVisible = true where ZoomValue < 0.5) or with the bitmap being generated. Either way, cheers!
Update
Didn't realize the grid lines are still behind the contents of the canvas. Haven't worked out a solution for that yet...
Update 2
Replace:
<local:MyCanvas ZoomValue="{Binding ElementName=ScaleTransform, Path=ScaleX}">
<local:MyCanvas.LayoutTransform>
<ScaleTransform x:Name="ScaleTransform" ScaleX="{Binding ElementName=Slider, Path=Value}" ScaleY="{Binding ElementName=Slider, Path=Value}"/>
</local:MyCanvas.LayoutTransform>
<Image Canvas.Top="1" Canvas.Left="1" x:Name="Image" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</local:MyCanvas>
With:
<Grid>
<Canvas>
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=Slider, Path=Value}" ScaleY="{Binding ElementName=Slider, Path=Value}"/>
</Canvas.LayoutTransform>
<Image Canvas.Top="5" Canvas.Left="5" x:Name="Image" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</Canvas>
<local:MyGrid ZoomValue="{Binding ElementName=ScaleTransform, Path=ScaleX}">
<local:MyGrid.LayoutTransform>
<ScaleTransform x:Name="ScaleTransform" ScaleX="{Binding ElementName=Slider, Path=Value}" ScaleY="{Binding ElementName=Slider, Path=Value}"/>
</local:MyGrid.LayoutTransform>
</local:MyGrid>
</Grid>
I believe another boost in performance as we are utilizing a simpler control to display the grid lines, plus, the grid lines can be placed either below or above desired controls.
Update 3
I have decided to post my latest solution, which is significantly more efficient and can all be done in XAML:
<Grid>
<Grid.Background>
<DrawingBrush Viewport="0,0,5,5" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M-.5,0 L50,0 M0,10 L50,10 M0,20 L50,20 M0,30 L50,30 M0,40 L50,40 M0,0 L0,50 M10,0 L10,50 M20,0 L20,50 M30,0 L30,50 M40,0 L40,50">
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Grid.Background>
</Grid>

WPF - Plotting a cosine function when radiobutton is clicked

I just started learning C# and I want to plot a cosine when user presses the radiobutton using WPF GUI interface. I think I am having trouble how to use call objects within different class. Thanks in advance and below is my code:
namespace WpfApplication2
{
using OxyPlot;
using OxyPlot.Annotations;
using OxyPlot.Axes;
using OxyPlot.Series;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button_Click_2(object sender, RoutedEventArgs e)
{
if (radioButton1.IsChecked == true)
{
MessageBox.Show("Plot Cosine");
//I think solution should be something like this
//MainViewModel.MyModel.Series.Add(new FunctionSeries(Math.Cos, -10, 10, 0.01, "cos(x)"));
}
}
}
public class MainViewModel : Window
{
//Plotting without any user input
public const double Pi = 3.14159265358979323846;
public const int SpeedOfLight = 3 * 10 ^ 8; // m per sec.
//OxyPlot.Wpf.PlotModel plot = new OxyPlot.Wpf.PlotView();
public MainViewModel()
{
MyModel = new PlotModel { Title = "Your Equation", LegendTitle = "Equations" };
MyModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Distance" });
MyModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Height" });
//Determine your range for the plot
//MyModel.Axes.Add(new LinearAxis(AxisPosition.Bottom, -10, 10));
//MyModel.Axes.Add(new LinearAxis(AxisPosition.Left, -5, 5));
MyModel.Series.Add(new FunctionSeries(Math.Cos, -10, 10, 0.01, "cos(x)"));
MyModel.Series.Add(new FunctionSeries(Math.Sin, -10, 10, 0.01, "sin(x)"));
LineSeries linePoints = new LineSeries() { };
double x, y;
DataPoint XYpoint = new DataPoint();
for (x = -10; x <= 10; x += 0.01)
{
//Make sure not 1/3 since C# will read it as integer divided by integer hence 1/3=0
//Use Math.Pow for powers
//Definately Matlab is easier to plot stuff XD
y = 1.0 / 2.0 * Math.Pow(x, 2) + 1;
XYpoint = new DataPoint(x, y);
linePoints.Points.Add(XYpoint);
}
MyModel.Series.Add(linePoints);
MyModel.InvalidatePlot(true);
}
public PlotModel MyModel { get; private set; }
}
}
Below is XAML code:
<Window x:Name="plot" x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:oxy="http://oxyplot.org/wpf"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication2"
mc:Ignorable="d"
Title="Plots" Height="450.307" Width="955.532" Background="White">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="73*"/>
<RowDefinition Height="11*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="145*"/>
<ColumnDefinition Width="329*"/>
</Grid.ColumnDefinitions>
<oxy:PlotView Title="{Binding Title}" Margin="4,0,0,0" Model="{Binding MyModel}" Grid.Column="1" >
<oxy:PlotView.Series>
<oxy:LineSeries ItemsSource="{Binding Points}"/>
</oxy:PlotView.Series>
</oxy:PlotView>
<Label x:Name="label" HorizontalAlignment="Left" Height="30" Margin="120,185,0,0" VerticalAlignment="Top" Width="142"/>
<RadioButton x:Name="radioButton1" Content="Plot Cosine" Grid.Column="1" HorizontalAlignment="Left" Height="20" Margin="50,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="85" />
<Button x:Name="button1" Content="Clear" HorizontalAlignment="Left" Height="35" Margin="120,7,0,0" Grid.Row="1" VerticalAlignment="Top" Width="142" Click="button_Click_2"/>
</Grid>
</Window>
C#
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using OxyPlot;
using OxyPlot.Series;
using OxyPlot.Axes;
namespace WpfApplication2
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public PlotModel MyModel { get; private set; }
public MainWindow()
{
InitializeComponent();
MyModel = new PlotModel { Title = "Your Equation", LegendTitle = "Equations" };
MyModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Distance" });
MyModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Height" });
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (radioButton1.IsChecked == true)
{
//MessageBox.Show("Plot Cosine");
graph();
}
}
public double getValue(int x, int y)
{
return (10 * x * x + 11 * x * y * y + 12 * x * y);
}
//setting the values to the function
public FunctionSeries GetFunction()
{
int n = 100;
FunctionSeries serie = new FunctionSeries();
for (int x = 0; x < n; x++)
{
for (int y = 0; y < n; y++)
{
//adding the points based x,y
DataPoint data = new DataPoint(x, getValue(x, y));
//adding the point to the serie
serie.Points.Add(data);
}
}
//returning the serie
return serie;
}
public void graph()
{
MyModel = new PlotModel { Title = "example" };
MyModel.LegendPosition = LegendPosition.RightBottom;
MyModel.LegendPlacement = LegendPlacement.Outside;
MyModel.LegendOrientation = LegendOrientation.Horizontal;
MyModel.Series.Add(GetFunction());
var Yaxis = new OxyPlot.Axes.LinearAxis();
OxyPlot.Axes.LinearAxis XAxis = new OxyPlot.Axes.LinearAxis { Position = OxyPlot.Axes.AxisPosition.Bottom, Minimum = 0, Maximum = 100 };
XAxis.Title = "X";
Yaxis.Title = "10 * x * x + 11 * x*y*y + 12*x*y";
MyModel.Axes.Add(Yaxis);
MyModel.Axes.Add(XAxis);
this.plot.Model = MyModel;
}
}
}
XAML
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:oxy="http://oxyplot.org/wpf"
xmlns:local="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="73*"/>
<RowDefinition Height="11*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="145*"/>
<ColumnDefinition Width="329*"/>
</Grid.ColumnDefinitions>
<oxy:PlotView Margin="4,0,0,0" Grid.Column="1" Name="plot" >
<!--<oxy:PlotView.Series>
<oxy:LineSeries ItemsSource="{Binding Points}"/>
</oxy:PlotView.Series>-->
</oxy:PlotView>
<Label x:Name="label" HorizontalAlignment="Left" Height="30" Margin="120,185,0,0" VerticalAlignment="Top" Width="142"/>
<RadioButton x:Name="radioButton1" IsChecked="True" Content="Plot Cosine" Grid.Column="1" HorizontalAlignment="Left" Height="20" Margin="50,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="85" />
<Button x:Name="button1" Content="Clear" HorizontalAlignment="Left" Height="35" Margin="120,7,0,0" Grid.Row="1" VerticalAlignment="Top" Width="142" Click="button1_Click"/>
</Grid>
</Window>

Image control and Image resizing when Stretch is set to Uniform

I have this peculiar problem. I am having a user control . I am making an app for Windows 8.1 where I would choose an image from my Picture gallery. The image would open in my app with Stretch is Uniform and Horizontal And vertical alignment to center.
My user control will appear where I tap on the image. Now the problem is , when the image Stretch was none , I was able to magnify the correct region (around my click) , but now when I make it Stretch to Uniform and Set the horizontal and vertical Alignment to Center , I am getting other pixel information in my user control.
I want to know how to fix it.Any how , the images can be of 2*Full HD also or they can be HD or even less.
Secondly , I want to know the boundaries of the image . With boundaries I want to say that , my user control shouldnt go above the boundaries of the image .
How to implement that. If my code is needed , I would paste it , If required.
Have this video for reference . This is what I have to develop ! I have the user control ready and I am getting exact pixels for Stretch=NONE , and no Horizontal And Vertical Alignment set.
This is my code for my app
I believe the issue is with how you use the control, rather than the image. If you avoid doing the bitmap cropping and replacing, it would speed up dramatically and likely work for all stretch types.
I've modified the source to show this - removing the Cropping completely. If you need cropping for other reasons, you should consider using the unsafe keyword (and property setting to allow) in order to dramatically speed up its use.
Also, to avoid the lagging/jumping upward, I added IsHitTestVisible="False" so that your delta wouldn't be interrupted by hovering over your image.
I see you have the 45-degree code already - since it wasn't in your source, I only added an example of 90 degree rotation when you get to the sides - so you can see how to set a RenderTransformOrigin point.
MainPage.xaml:
<Page x:Name="page1"
x:Class="controlMagnifier.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:controlMagnifier"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="ParentGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" PointerReleased="ParentGrid_OnPointerReleased" >
<Canvas x:Name="InkPresenter" Height="auto" Width="auto">
<Image Stretch="Uniform" x:Name="image2" >
<Image.Source >
<BitmapImage UriSource="/Assets/wallpaper.jpg" />
</Image.Source>
</Image>
</Canvas>
<local:MagnifierUsercontrol x:Name="MagnifyTip" Visibility="Collapsed" ManipulationMode="All"
IsHitTestVisible="False" Height="227" Width="171"
VerticalContentAlignment="Bottom" HorizontalContentAlignment="Center">
</local:MagnifierUsercontrol>
</Grid>
</Page>
MainPage.xaml.cs:
using System;
using Windows.Foundation;
using Windows.Storage;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
namespace controlMagnifier
{
public sealed partial class MainPage : Page
{
public const int XAxis = 200;
public const int YAxis = 435;
private readonly RotateTransform myRotateTransform = new RotateTransform {CenterX = 0.5, CenterY = 1};
private readonly ScaleTransform myScaleTransform = new ScaleTransform {ScaleX = 1, ScaleY = 1};
private readonly TransformGroup myTransformGroup = new TransformGroup();
private readonly TranslateTransform myTranslateTransform = new TranslateTransform();
public WriteableBitmap CurrentBitmapObj, CurrentCroppedImage = null;
public Point currentContactPt, GridPoint;
public Thickness margin;
public PointerPoint pt;
public double xValue, yValue;
public MainPage()
{
InitializeComponent();
ParentGrid.Holding += Grid_Holding;
image2.PointerMoved += InkCanvas_PointerMoved;
image2.PointerReleased += ParentGrid_OnPointerReleased;
margin = MagnifyTip.Margin;
image2.CacheMode = new BitmapCache();
myTransformGroup.Children.Add(myScaleTransform);
myTransformGroup.Children.Add(myRotateTransform);
myTransformGroup.Children.Add(myTranslateTransform);
MagnifyTip.RenderTransformOrigin = new Point(0.5, 1);
MagnifyTip.RenderTransform = myTransformGroup;
}
private void Grid_Holding(object sender, HoldingRoutedEventArgs e)
{
try
{
GridPoint = e.GetPosition(image2);
myTranslateTransform.X = xValue - XAxis;
myTranslateTransform.Y = yValue - YAxis;
MagnifyTip.RenderTransform = myTransformGroup;
MagnifyTip.Visibility = Visibility.Visible;
}
catch (Exception)
{
throw;
}
}
private void InkCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
try
{
pt = e.GetCurrentPoint(image2);
currentContactPt = pt.Position;
xValue = currentContactPt.X;
yValue = currentContactPt.Y;
if (xValue > 300)
{
myRotateTransform.Angle = -90;
}
else if (xValue < 100)
{
myRotateTransform.Angle = 90;
}
else
{
myRotateTransform.Angle = 0;
}
MagnifyTip.RenderTransform = myRotateTransform;
myTranslateTransform.X = xValue - XAxis;
myTranslateTransform.Y = yValue - YAxis;
MagnifyTip.RenderTransform = myTransformGroup;
}
catch (Exception)
{
throw;
}
finally
{
e.Handled = true;
}
}
private async void StoreCrrentImage()
{
try
{
var storageFile =
await
StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wallpaper.jpg",
UriKind.RelativeOrAbsolute));
using (
var fileStream =
await storageFile.OpenAsync(FileAccessMode.Read))
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
var writeableBitmap =
new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
fileStream.Seek(0);
await writeableBitmap.SetSourceAsync(fileStream);
CurrentBitmapObj = writeableBitmap;
writeableBitmap.Invalidate();
}
}
catch (Exception)
{
// Graphics g=new Graphics();
throw;
}
finally
{
}
}
private void ParentGrid_OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
MagnifyTip.Visibility = Visibility.Collapsed;
}
}
}
MagnifierUsercontrol.xaml:
<UserControl
x:Class="controlMagnifier.MagnifierUsercontrol"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:controlMagnifier"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Height="227" Width="171">
<Canvas x:Name="controlCanvas" x:FieldModifier="public" Height="Auto" Width="Auto" >
<Grid Height="227" Width="171" HorizontalAlignment="Center" Canvas.Left="0" Canvas.Top="0">
<Border x:FieldModifier="public" x:Name="imgBorder" Width="150" CornerRadius="50,50,50,50" Margin="13,25,13,97">
<Border.Background>
<ImageBrush x:FieldModifier="public" x:Name="image1" />
</Border.Background>
</Border>
<TextBlock x:Name="txtreading" Height="30" Width="80" Margin="0,-145,0,0" FontWeight="Bold" Foreground="Red" FontSize="20" Text="ABC" TextAlignment="Center" />
<!--<Image Height="120" Width="150" Margin="0,-50,0,0" Source="Assets/SmallLogo.scale-100.png" ></Image>-->
<Path x:Name="MagnifyTip" Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z" Fill="#FFF4F4F5" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" Height="227" Width="171" />
</Grid>
</Canvas>
</UserControl>
Let me know if this helps or if there is further toward your specific question.

How to create a Method that creates a new List and takes additional parameters

Is there a way to create a Method that creates a new instance of a List as a Method Parameterand does something with the new List?
private void ApplyMaxValue(List<double> list, double myDouble, Border border)
{
list = new List<double>();
list.Add(myDouble * 8);
border.Width = list.Max();
}
I would like to be able to pass values like this where someListToCreate is created in the Method rather than using an existing list.
ApplyMaxValue(someListToCreate, aDouble, myBorder);
I am still a little new to C# and not sure if Methods are capable of this or if I would need to create a Class.
EDIT
Code with demonstration of Method
<Window x:Class="NewListSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" Width="525">
<Grid>
<StackPanel Margin="20">
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
<Border x:Name="borderForArray1" BorderThickness="1" Height="1" HorizontalAlignment="Left" Width="20" Background="#FFF57F7F" VerticalAlignment="Bottom"/>
<Border x:Name="borderForArray2" BorderThickness="1" Height="1" HorizontalAlignment="Left" Width="20" Background="#FF6FA8D6" VerticalAlignment="Bottom"/>
<Border x:Name="borderForArray3" BorderThickness="1" Height="1" HorizontalAlignment="Left" Width="20" Background="#FFEEB382" VerticalAlignment="Bottom"/>
<Border x:Name="borderForArray4" BorderThickness="1" Height="1" HorizontalAlignment="Left" Width="20" Background="#FFB171E6" VerticalAlignment="Bottom"/>
</StackPanel>
<Button Content="Generate" HorizontalAlignment="Left" Padding="8,3" Margin="0,5,0,0" Click="Button_Click"/>
<Button Content="Method" HorizontalAlignment="Left" Padding="8,3" Margin="0,5,0,0" Click="Button_Click_1" />
<Button Content="Clear" HorizontalAlignment="Left" Padding="8,3" Margin="0,5,0,0" Click="Button_Click_2"/>
</StackPanel>
</Grid>
</Window>
CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace NewListSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
string[] array1 = { "This is a word.", "This is a sentence.", "This is short.", "This is." };
string[] array2 = { "This is a word.", "This is a very very very very long sentence.", "This is the longest sentence in this array along with all other arrays in this sample.", "This is a string." };
string[] array3 = { "This.", "That.", "Those.", "These.", "Slightly longer string." };
string[] array4 = { "a.", "b.", "c.", "defg." };
//Prevent from writing this code
List<double> list1 = new List<double>();
List<double> list2 = new List<double>();
List<double> list3 = new List<double>();
List<double> list4 = new List<double>();
//Prevent code end
//Method to prevent writing longer code
private void ApplyMaxValue(string[] array, Border border)
{
List<double> someList = new List<double>();
foreach (string s in array)
{
someList.Add(s.Length * 3);
}
border.Height = someList.Max();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
foreach (string s in array1)
{
list1.Add(s.Length * 3);
}
foreach (string s in array2)
{
list2.Add(s.Length * 3);
}
foreach (string s in array3)
{
list3.Add(s.Length * 3);
}
foreach (string s in array4)
{
list4.Add(s.Length * 3);
}
borderForArray1.Height = list1.Max();
borderForArray2.Height = list2.Max();
borderForArray3.Height = list3.Max();
borderForArray4.Height = list4.Max();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ApplyMaxValue(array1, borderForArray1);
ApplyMaxValue(array2, borderForArray2);
ApplyMaxValue(array3, borderForArray3);
ApplyMaxValue(array4, borderForArray4);
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
borderForArray1.Height = borderForArray2.Height = borderForArray3.Height = borderForArray4.Height = 1;
}
}
}
It sounds like you should be returning the list reference, rather than using it as a parameter - otherwise the fact that you're assigning a different value to it in the first statement of the method body makes it pointless:
private List<double> ApplyMaxValue(double myDouble, Border border)
{
List<double> list = new List<double>();
list.Add(myDouble * 8);
border.Width = list.Max();
return list;
}
Admittedly it's not obvious to me why you'd use list.Max() here when the only element is myDouble...
If you meant you want to accept a list as a method parameter but you don't need to create a new list, you can just use:
private void ApplyMaxValue(List<double> list, double myDouble, Border border)
{
list.Add(myDouble * 8);
border.Width = list.Max();
}
It's still not entirely clear why you'd want a single method to do that - it feels like it doesn't really have one responsibility. But it will at least work...
You don't have to pass the list as a parameter
private void ApplyMaxValue(double myDouble, Border border)
{
List<double> list = new List<double>();
list.Add(myDouble * 8);
border.Width = list.Max();
}
if you want to use the list after using this method you can use:
private List<double> ApplyMaxValue(double myDouble, Border border)
{
List<double> list = new List<double>();
list.Add(myDouble * 8);
border.Width = list.Max();
return list
}

Binding of a Polyline. What am I doing wrong?

I am trying what I thought a simple thing: drawing lines of a list of point.
If I put the list statically in the xaml of my window everything is ok.
If I do the bind, then nothing is displayed.
the window code:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Polyline Stretch="Fill" Grid.Column="0" Name="polyline" Stroke="Red" DataContext="{Binding Points}">
</Polyline>
</Grid>
public partial class testWindow2 : Window
{
AudioSignalModelView audioSignalModelView;
public testWindow2()
{
InitializeComponent();
audioSignalModelView = new AudioSignalModelView();
this.DataContext = audioSignalModelView;
}
}
public class AudioSignalModelView
{
public AudioSignalModelView()
{
Point pointA = new Point {X=0,Y=0};
Point pointB = new Point { X = 0.2, Y = 0.4 };
Point pointC = new Point { X = 0.8, Y = 0.1 };
Point pointD = new Point { X = 1, Y = 1 };
Points.Add(pointA);
Points.Add(pointB);
Points.Add(pointC);
Points.Add(pointD);
}
private AudioSignalTest audioSignalTest;
private PointCollection _points = new PointCollection();
public PointCollection Points
{
get { return _points; }
}
}
I think the binding is done somehow, because if I put a breakpoint in the getter of the Points property, it is called by the system...
What is obviously wrong in my code ?
You want to bind to the Points property not the DataContext.
<Polyline Stretch="Fill" Grid.Column="0"
Name="polyline" Stroke="Red"
Points="{Binding Points}"> <-- Here
</Polyline>
MSDN page

Categories

Resources