Canvas Drawing creating System.OutOfMemoryException Win Phone 8 - c#

I am developing a windows phone 8 app, I use Rectangle and Lines to draw a graph inside a Canvas placed inside a ScrollViewer.
But during the drawing I am facing System.OutOfMemoryException during drawing of the canvas( graph may go more than 3 times the size of the screen)
I have placed the Canvas inside a ScrollViewer. When I remove the ScrollViewer the issue does'nt occur but I am unable to scroll the Canvas even if I set the property Scrollviwer.HorizontalScrollBarVisibilty = Visible.
<ScrollViewer Name="MainScrollViewer" VerticalScrollBarVisibility="Disabled" HorizontalAlignment="Stretch" HorizontalScrollBarVisibility="Auto" Grid.RowSpan="2" >
<Canvas x:Name="MainCanvas" HorizontalAlignment="Left" Tap="OnCanvasTap" >
<Canvas.RenderTransform>
<CompositeTransform CenterX="100" CenterY="75" />
</Canvas.RenderTransform>
</Canvas>
</ScrollViewer>
I have also tried using GC.Collect and Canvas.Children.Clear() where I am drawing but even then the issue persist.

Instead of using a large canvas inside a scrollable div to contain all of the graphics you can use a smaller canvas, optimally max of the actual screen size (not the graphics) and then use translate the canvas and redraw the graphics at the translated position.
Optimally because if you have a huge canvas and only see 25% of then the other 75% is wasted memory.
By using the canvas as a "peephole" combined with translation you will get the same result on screen (you see 100% of what is possible to see at one time) and you don't need to worry about your graphics as this will be clipped automatically by the canvas.
You can attach translation to mouse/touch drag-and-move operation or make "virtual" scroll-bars if that is preferred.

Related

How to vertically center a wingding character in textblock xaml / C# / UWP

I’m trying to use a Wingdings symbol as a graphic in a control and am trying to make it vertically centered within a textbox (UWP app.) I’m putting a visible boarder around it and the fact that the symbol is not vertically centered is noticeable and ruining what I’m going for. If it’s possible it saves me from having to do custom art and the since the Wingdings are resizable my graphic could be somewhat easily rescaled. That's why I don't want to manually adjust the height until it looks centered.
Most the Wingdings aren’t vertically centered but are sometimes used as graphics so I’m wondering if this is doable w/ reasonable effort. A slick xaml way to do this would be ideal but a font metric measuring and then textblock height adjusting tack would be good.
Here’s an example of the problem. The hard drive symbol is not vertically centered in the border.
<Border BorderBrush="Black" BorderThickness="10" Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text=";" FontFamily="Wingdings" FontSize="230"/>
</Border>
EDIT - changed example to declutter and to use Wingdings hard drive symbol because the skull&bones is close enough to vertically centered to confuse the question. The drive symbol is very clearly not vertically centered. My goal to automatically vertically center it even as the font size changes. I can see how XAML may not be able to do this but I'm wondering if some font/text metrics querying exists that I could use to do it.
EDIT 2 - Adding a picture (from above XAML which has the same issues as all the suggested XAML(s):
I'm trying to get the center of the symbol to be at the center of the textblock
The skull & bones is not vertically centered in the border.
Actually by default the skull&bones text should be vertically center. The reason for why your code make it looks not vertically is that the font size is too larger to be inside the border, since Border's height is restricted to 200. So the exceed parts of TextBlock you will not seen which may looks like it is not vertically center.
How to vertically center a wingding character in textblock xaml / C# / UWP
There are several ways to do this, choose which way depend on your prefer.
Remove the height and width properties for the Border control you will see the text vertically center.
<Border BorderBrush="Black" BorderThickness="10" Background="White" HorizontalAlignment="Center">
<TextBlock x:Name="textBlock" Text="N" FontFamily="Wingdings" FontSize="230" />
</Border>
Add a ViewBox control outside the TextBlockcontrol. ViewBox can stretch and scale a single child to fill the available space. This will let your text looks always be center no matter how large is the font size. The text size will depend on the size of Border control. Code as follows:
<Border BorderBrush="Black" BorderThickness="10" Height="200" Width="175" Background="White" >
<Viewbox>
<TextBlock x:Name="textBlock" Text="N" FontFamily="Wingdings" FontSize="230" />
</Viewbox>
</Border>
Just use a TextBox control instead of the component of Border and TextBlock. This will reach the same effects that make the text always center and no matter what is the font size. Pay attention that don't set fixed height and width for the TextBox and also make the TextBox read only. Code as follows:
<TextBox
x:Name="textBox"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="Black"
BorderThickness="10"
FontFamily="Wingdings"
FontSize="230"
IsReadOnly="True"
Text="N"
TextAlignment="Center" />

Translucent background like iOS/OS X and Windows 10 startmenu in WPF apps

iOS, MAC OS X and now Windows 10 support translucent background. Is there a documented API in Windows 10 to extend this effect in WPF window? What I want is part of my app window to be translucent, but content I put there should still be legible. see example
Please not that this is not the same as changing Opacity property on a control, what I want is transparency plus blur on top of primary coloured hotspots in the background.
I have darkened and blurred backgrounds before when having a dialog appear over the top.
The way I would do it is use a VisualBrush with blur effect to create the blurred visual (I was blurring a UserControl that was not blurred before the dialog appeared) and then I would place a Canvas with black background and reduced opacity over the top to darken it.
<VisualBrush>
<VisualBrush.Visual>
<Grid ClipToBounds="True">
<Image Source="Images\myImage.png">
<Image.Effect>
<BlurEffect Radius="20"/>
</Image.Effect>
</Image>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
My code does not exactly describe what you want to achieve, but the technique of using the VisualBrush with blur effect is the key.
P.S. I think the iOS version of this looks awful and I doubt that there is any transparency in their solution, they probably just show a blurred image.

WinRT Canvas Zoom

I'm new to winRT, i'm trying to make a world map app.
I have a canvas control with a lot of path controls in it(every path control represents a country)
Now i want to make something so i can zoom in my canvas, so instead of seeing the wolrd map, i have to focus on, for example, Europe.
I think, it is easy to zoom in an image control, but an image control can't have different path controls in it.
Is there a way to make a zoom behavior or something on a canvas control?
thx in advance
You can try enclosing the canvas inside a ScrollViewer:
<ScrollViewer MinZoomFactor="0.25" >
<Canvas>
<Canvas.Background>
<ImageBrush x:Name="_background" />
</Canvas.Background>
</Canvas>
</ScrollViewer>
...then you can assign an image source to the canvas (in your case, a map).

stretch canvas on maximize

(Can't add pictures so I'll try and explain it) So my program basically consists of two parts: a bitmap image that is scanned and shown in the main window (on a canvas), and a canvas derived class I made that basically takes data (b&w values ranging from 0-255) from the image and represents it in a histogram format (a bargraph basically) and it overlays the bitmap image (its transparent so you can still see the image).
Alright so I got my program working, the only problem is my canvas derived class wont stretch until I "refresh" the screen. The children of the class (being windows shapes rectangles) wont stretch with the window.
It looks fine up to this point
but then I maximize it...
The rectangles then just stay exactly where they're at. It isn't until I click the "display histogram" button that it will disappear and then after clicking it again, I get...
...Exactly what I want, the histogram is in the right place on the screen. So here's my question, how can I get the histogram to stretch with the main window? instead of having to refresh it every time?
<Border Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" BorderBrush="Black" BorderThickness="5" x:Name="testview">
<local:DrawingCanvas x:Name="pbHistogram" IsHitTestVisible="False"
Width="Auto"
Background="Transparent"
Height ="{Binding Path=ActualHeight, ElementName=testview}"/>
</Border>
I know this is not really an answer, but I think the problem is the canvas class itself. It has no automatic layouting or resizing of its child elements. Link to msdn: http://msdn.microsoft.com/en-us/library/ms609101(v=vs.100).aspx
What you could try is to hook up to your main window's resize event and call the same function that the buttonpress calls.
Maybe the quickest, easiest way to do this would be to put your canvas in a Viewbox.

How to resize a Canvas in WPF?

I'm writing a WPF app that has a Canvas in it. This canvas will be custom rendered at runtime. It's sort of like a game in that it needs to be measured in pixels. I need to be able to set my Canvas to 478x478 pixels (client rectangle size). I don't want any scaling or other resolution-independent steps to take place on my Canvas.
I'm not sure if this is possible in WPF, since its nature is to be resolution independent. My questions:
How do I resize my Canvas at runtime (function to call?)
When I resize my Canvas, is the renderable area (the client rectangle) going to be that size? If not, how can I resize it to make sure the client rectangle is a specific width/height?
Is it possible to set the width/height of the Canvas in Pixels? How does the resolution-independent aspect of WPF interfere with what I'm trying to do?
When I resize my Canvas, will other controls resize appropriately as they have been designed to do in the WPF designer?
Thanks in advance.
Any elements positioned in a canvas will not resize or reposition based upon the size of the canvas. So I don't think there's any advantage to setting the size of the canvas. Maybe you should just set a fixed size of the window instead.
Otherwise, just set the Canvas.Width, Height, and ClipToBounds=True and you have a fixed sized canvas that positions its child elements with X/Y coordinates.
Also you should be sure to set SnapsToDevicePixels=True on the canvas so that child elements will have crisp pixel-aligned bounds.
resizing is cake:
MyCanvas.Width = 350;
MyCanvas.Height = 450;
this sets the size, you CAN render to coordinates outside of this, but it will be clipped. You can wrap your canvas inside a scroller to allow the user to see what is outside the height/width of the canvas.
as for the rest of your questions, i think you can see this SO question for your answers
Update 2020: on WPF .NET CORE: If the Canvas is a child of a Viewbox, the content is automatically scaled to the Viewbox height and width.
<Viewbox Stretch="Fill"
Width="50"
Height="50">
<Canvas>
<Path.... />
</Canvas>
</Viewbox>

Categories