Silverlight cannot update property after animation runs - silverlight

Im trying to create a simple pan and zoom app using silverlight 4, but Im having trouble updating the TranslateTransform and ScaleTransform properties after I run an animation on them.
I have tried to set the FillBehaviour to Stop, with no success.
Here is the code that I have:
<Canvas x:Name="LayoutRoot" Background="White" Width="800" Height="600">
<Canvas x:Name="PanningCanvas" Height="600" Width="800">
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="CanvasScale"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform x:Name="CanvasTransform"/>
</TransformGroup>
</Canvas.RenderTransform>
<Rectangle x:Name="MovingRect" Fill="#FF834040" Height="209" Canvas.Left="219" Stroke="#FF500505" Canvas.Top="220" Width="329" StrokeThickness="2"/>
</Canvas>
<Button Content="Animate" Width="107" Canvas.Left="38" Canvas.Top="46" ClickMode="Press" Click="Button_Click"/>
</Canvas>
And here is the C# behind it all (slightly abbreviated)
public partial class MainPage : UserControl
{
private ManipulationProcessor2D manipulationProcessor;
public MainPage()
{
InitializeComponent();
this.manipulationProcessor = new ManipulationProcessor2D(Manipulations2D.Translate | Manipulations2D.Scale);
this.manipulationProcessor.Delta += OnManipulationDelta;
Touch.FrameReported += OnCapturedTouchReported;
}
private void OnManipulationDelta(object sender, Manipulation2DDeltaEventArgs e)
{
float zoomVal = e.Delta.ScaleX;
Point pinchPoint = new Point(e.OriginX, e.OriginY);
float xTranslation = e.Delta.TranslationX;
float yTranslation = e.Delta.TranslationY;
if (zoomVal != 1.0)
{
Zoom(zoomVal, PanningCanvas.RenderTransform.Inverse.Transform(pinchPoint), pinchPoint, xTranslation, yTranslation, true);
}
else if (xTranslation != 0 || yTranslation != 0)
{
Translate(xTranslation, yTranslation);
}
}
public void Zoom(double zoom, Point pinchPosition, Point physicalPosition, float xTranslation, float yTranslation, bool isFinger)
{
if (isFinger)
{
CanvasScale.ScaleX = CanvasScale.ScaleX * zoom;
CanvasScale.ScaleY = CanvasScale.ScaleY * zoom;
CanvasTransform.X = -1 * (pinchPosition.X * CanvasScale.ScaleX - physicalPosition.X);
CanvasTransform.Y = -1 * (pinchPosition.Y * CanvasScale.ScaleY - physicalPosition.Y);
}
else
{
CanvasScale.ScaleX = CanvasScale.ScaleX + zoom;
CanvasScale.ScaleY = CanvasScale.ScaleY + zoom;
}
}
private void Translate(float xTranslation, float yTranslation)
{
CanvasTransform.X += xTranslation;
CanvasTransform.Y += yTranslation;
}
private void OnCapturedTouchReported(object sender, TouchFrameEventArgs e)
{
//..removed..//
// process manipulations
this.manipulationProcessor.ProcessManipulators(DateTime.UtcNow.Ticks,manipulators);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
AnimatePosition(new Point(400, 300), 1);
AnimateScale(1.2, 1);
}
private Storyboard translateStoryboard = new Storyboard();
private Storyboard scaleStoryboard = new Storyboard();
public void AnimatePosition(Point destinationPoint, double lengthOfAnimation)
{
Point offset = new Point(destinationPoint.X, destinationPoint.Y);
var translationAnimationX = new DoubleAnimation() { SpeedRatio = 1, Duration = new Duration(TimeSpan.FromSeconds(lengthOfAnimation)), To = offset.X };
translateStoryboard.Children.Add(translationAnimationX);
Storyboard.SetTargetProperty(translationAnimationX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"));
var translationAnimationY = new DoubleAnimation() { SpeedRatio = 1, Duration = new Duration(TimeSpan.FromSeconds(lengthOfAnimation)), To = offset.Y };
translateStoryboard.Children.Add(translationAnimationY);
Storyboard.SetTargetProperty(translationAnimationY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"));
Storyboard.SetTarget(translateStoryboard, PanningCanvas);
translateStoryboard.Begin();
}
public void AnimateScale( double scale, double lengthOfAnimation)
{
var scaleAnimationX = new DoubleAnimation() { SpeedRatio = 1, Duration = new Duration(TimeSpan.FromSeconds(lengthOfAnimation)), To = scale };
scaleStoryboard.Children.Add(scaleAnimationX);
Storyboard.SetTargetProperty(scaleAnimationX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));
var scaleAnimationY = new DoubleAnimation() { SpeedRatio = 1, Duration = new Duration(TimeSpan.FromSeconds(lengthOfAnimation)), To = scale };
scaleStoryboard.Children.Add(scaleAnimationY);
Storyboard.SetTargetProperty(scaleAnimationY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));
Storyboard.SetTarget(scaleStoryboard, PanningCanvas);
scaleStoryboard.Begin();
}
}
The issue is that after I click the button, I cannot translate or zoom anymore...
please help!
Mark

Ok, so I got it working, but I dont know why.
Changing the animation to work like this:
Storyboard translateStoryboard = new Storyboard();
Point offset = new Point(destinationPoint.X, destinationPoint.Y);
var translationAnimationX = new DoubleAnimation() { SpeedRatio = 1, Duration = new Duration(TimeSpan.FromSeconds(lengthOfAnimation)), To = offset.X };
var translationAnimationY = new DoubleAnimation() { SpeedRatio = 1, Duration = new Duration(TimeSpan.FromSeconds(lengthOfAnimation)), To = offset.Y };
Storyboard.SetTargetProperty(translationAnimationX, new PropertyPath("X"));
Storyboard.SetTargetProperty(translationAnimationY, new PropertyPath("Y"));
Storyboard.SetTargetName(translationAnimationX, "CanvasTransform");
Storyboard.SetTargetName(translationAnimationY, "CanvasTransform");
translateStoryboard.Children.Add(translationAnimationX);
translateStoryboard.Children.Add(translationAnimationY);
translateStoryboard.Begin();
Did the trick, but I dont know why...
Can someone please explain it to me?

Related

How can I draw lines in WPF inkCanvas with sequence of PNGs

I was trying to make a method to draw some arrowheads from a PNG image with transparency.
While I moving mouse, the application will be plot that png along the path.
What is the way to make that?
Another form I was wondering is creating a polygnon shape. I was tryed draw the shape (triangle) when enter on mouse down event.
void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
double posX = e.GetPosition(null).X;
double posY = e.GetPosition(null).Y;
double posX1 = posX - (posX / 4);
double posY1 = posY - (posY / 4);
double posX2 = posX + (posX / 4);
double posY2 = posY;
double posX3 = posX - (posX / 4);
double posY3 = posY + (posY - posY / 3);
Polygon p = new Polygon();
p.Stroke = Brushes.Black;
p.Fill = Brushes.LightBlue;
p.StrokeThickness = 1;
p.HorizontalAlignment = HorizontalAlignment.Left;
p.VerticalAlignment = VerticalAlignment.Center;
p.Points = new PointCollection() { new Point(posX1, posY1), new Point(posX2, posY2), new Point(posX3, posY3), new Point(posX1, posY1) };
MyCanvas.Children.Add(p);
}
But still can't click and draw a triangle correctly in mouse (x,y) position.
http://i.stack.imgur.com/bM2i4.png
Here is a quick example.
XAML
<Canvas x:Name='DrawingCanvas'
Margin='30'
Background='LightBlue'
MouseDown='Canvas_MouseDown'
MouseMove='Canvas_MouseMove'
MouseUp='Canvas_MouseUp'>
<Rectangle>
<Rectangle.Fill>
<ImageBrush ImageSource='Arrow.png' x:Name='ArrowBrush'/>
</Rectangle.Fill>
</Rectangle>
</Canvas>
CODE
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private bool _isDrawing = false;
private Point _lastPosition;
const double MIN_MOVEMENT = 60;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e) {
_isDrawing = true;
_lastPosition = e.GetPosition(DrawingCanvas);
// add the first arrow
AddArrow(_lastPosition);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e) {
if (!_isDrawing)
{
return;
}
var currentPosition = e.GetPosition(DrawingCanvas);
// draw a new image if mouse has traveled minimum distance
if (Math.Abs((currentPosition.X - _lastPosition.X)) > MIN_MOVEMENT ||
Math.Abs((currentPosition.Y - _lastPosition.Y)) > MIN_MOVEMENT)
{
AddArrow(currentPosition);
_lastPosition = e.GetPosition(DrawingCanvas);
}
}
private void AddArrow(Point currentPosition) {
var rect = new Rectangle();
rect.Width = 120;
rect.Height = 120;
rect.Fill = ArrowBrush;
Canvas.SetTop(rect, currentPosition.Y);
Canvas.SetLeft(rect, currentPosition.X);
DrawingCanvas.Children.Add(rect);
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e) {
_isDrawing = true;
}
}
Screenshot

Zooming To Mouse Point With ScrollView and ViewBox in Wpf

I have some paths drawn to the screen in wpf. The coordinates being used are quite small so they have been made to fill the screen with a view box. I am now trying to implement pan and zoom functionality. I would like to be able to zoom to wherever the mouse is in relation to the ui (i.e zoomed screen center is equal to mouse coordinates). The current outcome is that the center of the screen when zoomed is not reflective of the exact mouse position on the ui.
If you want to see what is happening... Here is my current solution file.
Or
Heres some code:
View Xaml
<Grid Name="MasterGrid" DataContext="{StaticResource mainWindowViewModel}">
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" Name="VisualisationScroller">
<Viewbox Name="VisualisationBox" Stretch="Fill" Loaded="VisualisationBox_Loaded">
<ItemsControl Name="CustomDrawingElement" ItemsSource="{Binding Trajectories}" Width="{Binding VisualisationWidth}" Height="{Binding VisualisationHeight}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="data:VisualisedTrajectory">
<Path Data = "{Binding PathData}" Stroke="Red" StrokeThickness="0.001" Fill="Transparent" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas
Background="DarkGray"
IsItemsHost="True">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1" />
<TranslateTransform />
</TransformGroup>
</ItemsControl.RenderTransform>
</ItemsControl>
</Viewbox>
</ScrollViewer>
</Grid>
View Model
public class MainWindowViewModel : BaseViewModel
{
public MainWindowViewModel()
{
VisualiseRawTrajectories();
}
private ObservableCollection<VisualisedTrajectory> _trajectories = new ObservableCollection<VisualisedTrajectory>();
public ObservableCollection<VisualisedTrajectory> Trajectories
{
get { return _trajectories; }
}
#region VisualisationDimensions
private double _visualisationWidth = 100;
public double VisualisationWidth
{
get { return _visualisationWidth; }
private set { _visualisationWidth = value; }
}
private double _visualisationHeight = 100;
public double VisualisationHeight
{
get { return _visualisationHeight; }
private set { _visualisationHeight = value; }
}
#endregion
public void VisualiseRawTrajectories()
{
var rand = new Random();
for (int i = 0; i < 5; i++)
{
var currentTrajectorySet = new List<Point>(); //each time through reinitialise
for (int j = 0; j < 5; j++)
{
currentTrajectorySet.Add(new Point(rand.NextDouble() * 0.5, rand.NextDouble() * 0.5)); //add a new point with max 0.5
if(j == 4)
{
currentTrajectorySet.Add(new Point(0.5, 0.5)); //for good measure :)
_trajectories.Add(new VisualisedTrajectory(CreatePathData(currentTrajectorySet)));
}
}
}
VisualisationHeight = 0.5;
VisualisationWidth = 0.5; //just for demonstration purposes
OnPropertyChanged("VisualisationHeight");
OnPropertyChanged("VisualisationWidth");
}
private Geometry CreatePathData(IList<Point> points)
{
var geometry = new StreamGeometry {FillRule = FillRule.EvenOdd};
using (StreamGeometryContext ctx = geometry.Open())
{
ctx.BeginFigure(points[0], false, false); //use the first index
ctx.PolyLineTo(points, true, true);
}
return (Geometry)geometry.GetAsFrozen();
}
}
View Code Behind
public MainWindow()
{
InitializeComponent();
VisualisationScroller.PreviewMouseWheel += OnPreviewMouseWheel;
}
private Point originalDimensions;
private void VisualisationBox_Loaded(object sender, RoutedEventArgs e)
{
Viewbox viewBox = sender as Viewbox;
viewBox.Width = viewBox.ActualWidth;
viewBox.Height = viewBox.ActualHeight;
originalDimensions = new Point(viewBox.ActualWidth, viewBox.ActualHeight);
}
#region Zoom
private int _numberDrawnItems = 0;
private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var zoomScale = new Point(CustomDrawingElement.RenderTransform.Value.M11,
CustomDrawingElement.RenderTransform.Value.M22); //gets the scale x and scale y
if (CustomDrawingElement != null && _numberDrawnItems != CustomDrawingElement.Items.Count) //if there was something draw to screen
{
_numberDrawnItems = CustomDrawingElement.Items.Count;
CustomDrawingElement.RenderTransformOrigin = new Point(0.5, 0.5); //if not set zoom from center
}
if (e.Delta > 0)
{
if (CustomDrawingElement != null)
{
VisualisationBox.Width = originalDimensions.X * (zoomScale.X + 1);
VisualisationBox.Height = originalDimensions.Y * (zoomScale.Y + 1);
var mousePosition = e.GetPosition(MasterGrid);
CustomDrawingElement.RenderTransformOrigin = new Point(mousePosition.X / MasterGrid.ActualWidth, mousePosition.Y / MasterGrid.ActualHeight);
CustomDrawingElement.RenderTransform = new MatrixTransform(zoomScale.X + 1, 0, 0, zoomScale.Y + 1, 0, 0);
}
}
if (e.Delta < 0)
{
if (zoomScale.X > 1 && zoomScale.Y > 1) //stops you from zooming out too much
{
if (CustomDrawingElement != null)
{
VisualisationBox.Width = VisualisationBox.Width - originalDimensions.X;
VisualisationBox.Height = VisualisationBox.Height - originalDimensions.Y;
CustomDrawingElement.RenderTransform = new MatrixTransform(zoomScale.X - 1, 0, 0, zoomScale.Y - 1, 0, 0);
}
}
}
e.Handled = true;
}
#endregion //Zooming code
}
Solved it changed the back code for zooming the View to:
if (e.Delta > 0)
{
if (CustomDrawingElement != null)
{
//zoom
_zoomScale++; //increase it now that we have zoomed
VisualisationBox.Width = _originalDimensions.X * (_zoomScale);
VisualisationBox.Height = _originalDimensions.Y * (_zoomScale);
ScrollerDimensions.Content = VisualisationScroller.ActualWidth + "x" + VisualisationScroller.ActualHeight;
BoxDimensions.Content = VisualisationBox.ActualWidth + "x" + VisualisationBox.ActualHeight;
var mousePosition = e.GetPosition(MasterGrid);
mousePosition = MasterGrid.TransformToVisual(VisualisationBox).Transform(mousePosition);
ScrolledPoint.Content = mousePosition.X + "," + mousePosition.Y;
VisualisationScroller.ScrollToHorizontalOffset(mousePosition.X);
VisualisationScroller.ScrollToVerticalOffset(mousePosition.Y);
}
}
if (e.Delta < 0)
{
if (_zoomScale > 1) //stops you from zooming out too much
{
if (CustomDrawingElement != null)
{
var mousePosition = e.GetPosition(MasterGrid);
_zoomScale -= 1; //decrease the zoom
VisualisationBox.Width = VisualisationBox.Width - _originalDimensions.X;
VisualisationBox.Height = VisualisationBox.Height - _originalDimensions.Y;
mousePosition = MasterGrid.TransformToVisual(VisualisationBox).Transform(mousePosition);
mousePosition = new Point(mousePosition.X - _originalDimensions.X, mousePosition.Y - _originalDimensions.Y);
VisualisationScroller.ScrollToHorizontalOffset(mousePosition.X);
VisualisationScroller.ScrollToVerticalOffset(mousePosition.Y);
}
}
}
e.Handled = true;
If anyone is interested HERE is the finished solution file with panning implemented too.

Strange act of canvas when Scale/ Zoom in Silverlight

I'm working on Zooming with Silverlight 5,
My Idea is to zoom according to mouse position on the Canvas, and the ability to Drag that Canvas,
The problem I have is when scale is less than 1, about 0.6 or 0.5, point to the corner of the canvas and wheel up, the canvas will change its position or "jump", any help please?
these two photos describe the status before Then after:
I have the following XAML:
<Grid x:Name="LayoutRoot" Background="White">
<ScrollViewer x:Name="sv" Margin="0,0,0,76" ScrollViewer.VerticalScrollBarVisibility="Disabled" Background="#FFE3E7F1">
<Canvas x:Name="grd" Height="394" Width="630">
<Canvas x:Name="cvs" Background="White" MouseWheel="cvs_MouseWheel" MouseLeftButtonDown="cvs_MouseLeftButtonDown" MouseLeftButtonUp="cvs_MouseLeftButtonUp" MouseMove="cvs_MouseMove" Height="391" Canvas.Left="2" Canvas.Top="1" Width="625">
<Canvas.Effect>
<DropShadowEffect ShadowDepth="0"/>
</Canvas.Effect>
<Rectangle Height="70" Canvas.Left="155" Canvas.Top="58" Width="79" Fill="#FFFFBFBF"/>
<Rectangle Height="70" Canvas.Left="544" Canvas.Top="126" Width="79" Fill="#FF8B92FF"/>
</Canvas>
</Canvas>
</ScrollViewer>
</Grid>
and here's the C#:
public partial class MainPage : UserControl
{
CompositeTransform canvasTransform = new CompositeTransform();
bool canDragCanvas;
double mouseRelatedPositionX = 0;
double mouseRelatedPositionY = 0;
public MainPage()
{
// Required to initialize variables
InitializeComponent();
}
private void cvs_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
var scaleFactor = 0.2*(e.Delta < 0?-1:1);
var centerX = e.GetPosition(cvs).X;
var centerY = e.GetPosition(cvs).Y;
if (centerX > cvs.ActualWidth * canvasTransform.ScaleX || centerX < 0 || centerY > cvs.ActualHeight * canvasTransform.ScaleY || centerY < 0)
{
centerX = cvs.ActualWidth/2;
centerY = cvs.ActualHeight/2;
}
canvasTransform.CenterX = centerX;
canvasTransform.CenterY = centerY;
canvasTransform.ScaleX += scaleFactor;
canvasTransform.ScaleY += scaleFactor;
cvs.RenderTransform = canvasTransform;
}
private void cvs_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
canDragCanvas = true;
mouseRelatedPositionX = e.GetPosition(cvs).X;
mouseRelatedPositionY = e.GetPosition(cvs).Y;
}
private void cvs_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
canDragCanvas = false;
}
private void cvs_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if(!canDragCanvas) return;
var leftValueToAdd = e.GetPosition(cvs).X - mouseRelatedPositionX;
var topValueToAdd = e.GetPosition(cvs).Y - mouseRelatedPositionY;
UpdateCanvasPosition(leftValueToAdd*canvasTransform.ScaleX, topValueToAdd*canvasTransform.ScaleX);
}
void UpdateCanvasPosition(double leftValueToAdd,double topValueToAdd)
{
var leftOffset = canvasTransform.CenterX - canvasTransform.CenterX * canvasTransform.ScaleX;
var rightOffset = (cvs.ActualWidth - canvasTransform.CenterX) - (cvs.ActualWidth - canvasTransform.CenterX) * canvasTransform.ScaleX;
var topOffset = canvasTransform.CenterY - canvasTransform.CenterY * canvasTransform.ScaleY;
var bottomOffset = (cvs.ActualHeight - canvasTransform.CenterY) - (cvs.ActualHeight - canvasTransform.CenterY) * canvasTransform.ScaleY;
var canvasLeftInBorders = Canvas.GetLeft(cvs)+ leftValueToAdd + leftOffset > 0;
var canvasRightInBorders = Canvas.GetLeft(cvs) + cvs.ActualWidth * canvasTransform.ScaleX + leftValueToAdd + leftOffset < grd.ActualWidth;
var canvasTopInBorders = Canvas.GetTop(cvs) + topValueToAdd + topOffset > 0;
var canvasBottomInBorders = Canvas.GetTop(cvs) + cvs.ActualHeight * canvasTransform.ScaleY + topValueToAdd + topOffset < grd.ActualHeight;
if (leftValueToAdd > 0)
{
if (canvasLeftInBorders)
leftValueToAdd = 0;
}
else if (leftValueToAdd < 0)
if (canvasRightInBorders)
leftValueToAdd = 0;
if (topValueToAdd > 0)
{
if (canvasTopInBorders)
topValueToAdd = 0;
}
else if (topValueToAdd < 0)
if (canvasBottomInBorders)
topValueToAdd = 0;
Canvas.SetLeft(cvs, Canvas.GetLeft(cvs) + leftValueToAdd);
Canvas.SetTop(cvs,Canvas.GetTop(cvs)+topValueToAdd);
}
}
Basically you are attaching mouse events to the surface that is zooming and the mouse coordinates get altered too. Silverlight is designed to still be interactive when you rotate, zoom and tilt.
You want to put a transparent layer over the top, that is not zoomed, and attached your mouse methods that that layer.
If you leave that layer turned on you will have to calculate collisions, but you can make it so that the layer only appears on mouse down and goes away on mouse up.

Allow a user to create a line series on a wpf chart by clicking on the chart

I have a WPF chart currently displaying an Area series. I need to allow a user the ability to click on the chart and add a new point for a Line series. The problem I'm having is I can't seem to find a way to convert the point from a MouseButtonEventArgs to a LineDataPoint.
private void chtPowerFlowMap_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(chtPowerFlowMap);
points.Add(p); //Issue here is this will return a point in screen coordinates and not in chart coordinates
ls.ItemsSource = points; //ls is an existing lineseries and points is a List<Point> object
chtPowerFlowMap.Series.Add(ls);
}
Thanks in advance.
Here is a complete solution. You can click anywhere on the chart and there will be a new point at that palce.
MainWindows.xaml
<chart:Chart x:Name="chart" MouseLeftButtonDown="Chart_MouseLeftButtonDown">
<chart:LineSeries ItemsSource="{Binding}" x:Name="lineSeries"
DependentValuePath="Value"
IndependentValuePath="Date"/>
</chart:Chart>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
private ObservableCollection<Item> items;
public MainWindow()
{
InitializeComponent();
Random rd = new Random();
items = new ObservableCollection<Item>(
Enumerable.Range(0, 10)
.Select(i => new Item
{
Date = DateTime.Now.AddMonths(i - 10),
Value = rd.Next(10,50)
}));
this.DataContext = items;
}
public class Item
{
public DateTime Date { get; set; }
public double Value { get; set; }
}
private void Chart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var p = Mouse.GetPosition(this.lineSeries);
//ranges in the real values
var left = items.Min(i => i.Date);
var right = items.Max(i => i.Date);
var top = items.Max(i => i.Value);
var bottom = items.Min(i => i.Value);
var hRange = right - left;
var vRange = top - bottom;
//ranges in the pixels
var width = this.lineSeries.ActualWidth;
var height = this.lineSeries.ActualHeight;
//from the pixels to the real value
var currentX = left + TimeSpan.FromTicks((long)(hRange.Ticks * p.X / width));
var currentY = top - vRange * p.Y / height;
this.items.Add(new Item { Date = currentX, Value = currentY });
}
}

Silverlight 4 WriteableBitmap ScaleTransform Exception but was working in v3

I am getting the following exception for code that used to work in silverlight 3 but has stopped working since upgrading to silverlight 4:
System.AccessViolationException was unhandled
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
var OpenFileDialog = new OpenFileDialog();
OpenFileDialog.Filter = "*.jpg|*.jpg";
if (OpenFileDialog.ShowDialog() == true)
{
var file = OpenFileDialog.Files.ToArray()[0];
ScaleStreamAsBitmap(file.OpenRead(), 200);
}
}
public static WriteableBitmap ScaleStreamAsBitmap(Stream file, int maxEdgeLength)
{
file.Position = 0;
var src = new BitmapImage();
var uiElement = new System.Windows.Controls.Image();
WriteableBitmap b = null;
var t = new ScaleTransform();
src.SetSource(file);
uiElement.Source = src;
//force render
uiElement.Effect = new DropShadowEffect() { ShadowDepth = 0, BlurRadius = 0 }; ;
//calc scale
double scaleX = 1;
double scaleY = 1;
if (src.PixelWidth > maxEdgeLength)
scaleX = ((double)maxEdgeLength) / src.PixelWidth;
if (src.PixelHeight > maxEdgeLength)
scaleY = ((double)maxEdgeLength) / src.PixelHeight;
double scale = Math.Min(scaleX, scaleY);
t.ScaleX = scale;
t.ScaleY = scale;
b = new WriteableBitmap(uiElement, t);
return b;
}
}
}
Thanks
I had the same problem and I succeeded to resolve it!
b=new new WriteableBitmap(0, 0);
b.SetSource(file);
b.Render( new Image() { Source = src, Effect = new DropShadowEffect() { ShadowDepth = 0, BlurRadius = 0 } }, new ScaleTransform() { ScaleX = scaleX , ScaleY = scaleY });
And you can remove :uiElement and file.Position!

Resources