WPF Scrollviewer Panning lags when moving complex path - c#

So i have stacked canvasses and an image inside a scrollviewer that i can pan and scroll into using the mouse event, think Map with overlays.
<ScrollViewer Name="scrollViewer" Panel.ZIndex="99" Grid.Column="1"
VerticalScrollBarVisibility="Hidden"
HorizontalScrollBarVisibility="Hidden"
IsTabStop="False" Focusable="False">
<Grid Width="{Binding ElementName=map_image, Path=Width}"
Height="{Binding ElementName=map_image, Path=Height}"
VerticalAlignment="Center" HorizontalAlignment="Center"
RenderTransformOrigin="0.5,0.5">
<Grid.LayoutTransform>
<TransformGroup>
<ScaleTransform x:Name="zoomScale"/>
</TransformGroup>
</Grid.LayoutTransform>
<Grid x:Name="grid_draggable"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Cursor="ScrollAll">
<Image x:Name="map_image"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="0"
Height="0"
Stretch="Fill"
Panel.ZIndex="1"
Visibility="Visible"/>
<Canvas x:Name="Canvas_complexPath"
Visibility="Collapsed"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
IsHitTestVisible="False"
Panel.ZIndex="7"/>
<Image x:Name="Bitmapforpath"
Visibility="Collapsed"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Panel.ZIndex="7"/>
<local:UCcustomCanvas x:Name="CustomPathCanvas"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Panel.ZIndex="7"/>
</Grid>
</Grid>
</ScrollViewer>
code for panning:
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (lastDragPoint.HasValue)
{
Point posNow = e.GetPosition(scrollViewer);
double dX = posNow.X - lastDragPoint.Value.X;
double dY = posNow.Y - lastDragPoint.Value.Y;
lastDragPoint = posNow;
//check whether mouse is near border
if (sender != maingrid && mouse_near_border(posNow))
{
AutoMoveStart();
return;
}
map_drag[0] += Math.Abs(dX);
map_drag[1] += Math.Abs(dY);
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - dX);
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - dY);
}
}
All is smooth until i put a very large and complex path inside the canvas.
Then as soon as i zoom into the complex path, the map laggs when panning. As soon as the path is not in view anymore, panning is smooth again.
I can get smooth panning if i turn the canvas containing the path into a bitmap, but this is then dependent on the resolution of the bitmap. So RAMuse is going up if i want a large bitmap.
Is there another way using vector graphics?
I tried exchanging the canvas with path shapes for a image with GeometryGroup turned DrawingImage... this gives me a region inside the path where there is no lag.. no idea how this is determined.
i tried exchanging the canvas for a custom canvas with DrawingContext, but this behaves identical to alternative 1.
I know my CPU climbs up to 10+% for solution 1. as soon as lag happens, in the mysterious lag-free region CPU stays low 1-3%.
I read that WPF sometimes has issues with the Mousemove command, but i am not sure how to access the Scrollviewer internally to change that.

Related

Blur images no matter what in WPF

I have a button with an image and no matter what I do the image looks blurry after rendered/compiled.
FYI - The image looks good when not in WPF controls
The image on the left is before compiled, the image on the right is blurry after compiled.
I tried applying UseLayoutRounding, applying SnapsToDevicePixels,
RenderOptions.BitmapScalingMode and removing the antialiasing directly in the button and directly to the image but nothing.
Any idea how can I improve the quality of the images in WPF?
XAML:
Styles applied directly to the button:
<Grid>
<Button x:Name="recentButton" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" SnapsToDevicePixels="True" RenderOptions.EdgeMode="Aliased"
Margin="10,137,302,10"
Width="auto"
Height="23"
HorizontalAlignment="Stretch"
BorderBrush="{x:Null}"
Foreground="White"
BorderThickness="0"
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Image Source="/Tool;component/Design/Images/more-icon-active.png" Stretch="None"/>
</Button>
</Grid>
Styles applied directly to the image:
<Grid>
<Button x:Name="recentButton"
Margin="10,137,302,10"
Width="auto"
Height="23"
HorizontalAlignment="Stretch"
BorderBrush="{x:Null}"
Foreground="White"
BorderThickness="0"
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Image Source="/Tool;component/Design/Images/more-icon-active.png" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" SnapsToDevicePixels="True" RenderOptions.EdgeMode="Aliased" Stretch="None"/>
</Button>
</Grid>
The problem is you're using UseLayoutRounding on the control directly.
But, be aware of this note in the linked documentation,
You should set UseLayoutRounding to true on the root element. The layout system adds child coordinates to the parent coordinates; therefore, if the parent coordinates are not on a pixel boundary, the child coordinates are also not on a pixel boundary. If UseLayoutRounding cannot be set at the root, set SnapsToDevicePixels on the child to obtain the effect that you want.
Therefore, use it on the parent container instead. In your case, that would be on the on the <grid> element.
Other recommandations
Recommended by #Clemens in the comment section,
Depending on the kind of image, RenderOptions.BitmapScalingMode="NearestNeighbor" may add some sharpness.
Note that you will have to apply that on the image directly.
Recommended by #BradleyUffner in the comment section,
Setting TextOptions.TextFormattingMode="Display" on your top level elements to greatly improve text rendering on desktop computers.

Make tooltip area bigger than the control

I have a chart with thin lines as markers which the user can hover over to get their values.
I would like to make the area in which the tooltip activates bigger but keep the actual line the same size as it is quite difficult for the use to actually hover over.
I also have one line that the user can drag around and it is very difficult to get the precise spot to click and drag.
This is my template for the marker but I am not sure how to accomplish this goal, can anyone point me in the right direction?
<Geometry x:Key="LineGeometry">M 0,0 L 5,0 L 5,15 L 0,15 Z</Geometry>
<DataTemplate>
<!-- Define the template for the actual markers -->
<Path Width="10"
Height="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Data="{StaticResource LineGeometry}"
Stretch="Fill"
Stroke="{StaticResource BlackBrush}"
StrokeThickness="0.5">
<Path.ToolTip>
<!-- Lots of tooltip definition stuff -->
</Path.ToolTip>
</Path>
</DataTemplate>
Visual Studio 2015
WPF
C#
Infragistics XamDataChart
Your actual problem is you have not used the Fill property of Path,so while creating this shape there is literally nothing in between lines, that's why if you check IsMouseOver property when Mouse pointer is inside this shape, it will return false. however if you specify Fill property result will be as expected.
Use Fill property as below and your ToolTip will be visible if Mouse is over Path shape anywhere.:
Fill="Transparent"
So your output won't get impacted visually. below is a sample program.
XAML:
<Window.Resources>
<Geometry x:Key="LineGeometry">M 0,0 L 5,0 L 5,15 L 0,15 Z</Geometry>
</Window.Resources>
<StackPanel>
<Path Width="100"
Height="100"
Name="path"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Data="{StaticResource LineGeometry}"
Stretch="Fill"
Stroke="Red" Margin="50"
StrokeThickness="5"
Fill="Transparent"
MouseLeftButtonDown="Path_MouseLeftButtonDown">
<Path.ToolTip>
<TextBlock Text="This is My Tooltip of Path" />
</Path.ToolTip>
</Path>
<StackPanel Orientation="Horizontal">
<Label Content="Is Mouse Over Path : " />
<Label Content="{Binding ElementName=path,Path=IsMouseOver}" BorderThickness="0.5" BorderBrush="Black"/>
</StackPanel>
</StackPanel>
Output:
Sorry,don't know how to captureMousein screenshot, but mouse is in between the shape while image was captured. RemoveFill
propertyfromPathand then see the change in ouput.
If I understand you correctly, you just want to show tooltip inside your rectangle represented by Path. If so you can just wrap your path in transparent border and set tooltip on border:
<Border Background="Transparent">
<Path Width="10"
Height="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Data="{StaticResource LineGeometry}"
Stretch="Fill"
Stroke="Black"
StrokeThickness="0.5"></Path>
<Border.ToolTip>
<TextBlock Text="Tooltip" />
</Border.ToolTip>
</Border>

Image Distortion in ScrollViewer

I'm having a weird issue that causes an Image to get distorted if I re-size the window to a particular size. I'm assuming the image is being positioned inside the scrollviewer to a sub pixel position , but I'm not really sure how to fix this.
I'm using a Scaletransform, but the current issue is happening if the scale is set to 1.
If you Look at the Text in the screenshot below you'll see the text is slightly distorted , If i re-size the window by a single pixel , the distortion goes away as seen in the alternate screenshot.
Pixel Distortion
No Distortion
XAML Code:
<ScrollViewer x:Name="scrollViewer"
Background="#282828"
Focusable="False"
Grid.Column="2"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible" SnapsToDevicePixels="True">
<Border BorderBrush="Red" BorderThickness="1">
<Grid Name="grid" RenderTransformOrigin="0.5,0.5" SnapsToDevicePixels="True">
<Grid.LayoutTransform>
<TransformGroup>
<ScaleTransform x:Name="scaleTransform" CenterX="0.5" CenterY="0.5" />
</TransformGroup>
</Grid.LayoutTransform>
<Image Name="img" HorizontalAlignment="Left" VerticalAlignment="Top"
IsHitTestVisible="False"
RenderOptions.BitmapScalingMode="NearestNeighbor"
SnapsToDevicePixels="True"
Stretch="Uniform" />
</Grid>
</Border>
</ScrollViewer>
Just a hunch: Have you tried to apply UseLayoutRounding?

how can I draw the trail of joints with ellipse in kinect?

The program I would like to make is like this:
Track the joint of right hand and on that coordinate, an ellipse is displayed.
I made this ellipse track my hand.
I want to make the trail of ellipse not disappear, so the ellipse can be used like a brush tool.
I added this statement,
canvasPaint.Children.Add(ellipse);
but it doesn't work. Actually, the program stops running because of this statement.
So, how can I draw multiple ellipses like in this video?
I am developing in c# and xaml.
Do I need openni? is it necessary?
I solved this problem by myself :)
The problem occurred because
1. I didn't make a new object and just added an existing ellipse.
2. I should have handled Zindex to print ellipses in front of Kinect video.
So I implemented a method drawEllipse,
void drawEllipse(SolidColorBrush c, double x, double y)
{
Ellipse ellipse = new Ellipse()
{
Fill = c,
Height = 30,
Width = 30,
Opacity = 0.5
};
Canvas.SetLeft(ellipse, x);
Canvas.SetTop(ellipse, y);
canvasPaint.Children.Add(ellipse);
}
and handled the property Zindex.
<Window x:Class="KinectPractice01.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="480" Width="640">
<Grid>
<Image Height="441" Canvas.Left="10" Canvas.Top="0" Width="618" Name="image1" Panel.ZIndex="0"/>
<Canvas Margin="0,0,0,0">
<Canvas Name="canvasPaint" Width="640" Height="480" Margin="90,0,0,0" Panel.ZIndex="1"/>
<TextBox Height="23" Canvas.Left="32" TextWrapping="Wrap" Text="null" Canvas.Top="10" Width="120" Name="textbox1"/>
<Ellipse Opacity="0.5" Fill="White" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Name="ellipse1"/>
<Ellipse Opacity="0.5" Fill="Cyan" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Name="ellipse2"/>
</Canvas>
</Grid>

How to place a slider over on top of a videobrush

I am attempting to create a slider control which will determine the scaletransform of a videobrush in my MainPage, and was wondering if it was possible to somehow place this slider on top of the videobrush (which I would like to be full screen)? Currently I am using a grid for my layout where a videobrush takes up the whole screen except for two buttons on the bottom of the screen, but I would like to possibly use a canvas and place this slider in a way that would account for the current and future screen sizes of a Windows Phone device. I am unsure of how to exactly accomplish this without setting constant dimensions for the slider. For instance the slider may be placed horizontally near the bottom of the screen in Portrait mode and would have a 50 pixel space between the left and right sides. Could someone assist with how this could be done?
EDIT
Placing a single child element over the videobrush works, although I would like to place more than one slider which gives an error. I also wanted to add information above and below each slider so I chose a stackpanel to do this (yet only one stackpanel as a child element is allowed?).
<Border x:Name="videoRectangle" Grid.Row="0" Grid.ColumnSpan="2" >
<Border.Background>
<VideoBrush x:Name="viewfinderBrush">
<VideoBrush.RelativeTransform>
<CompositeTransform x:Name="viewfinderBrushTransform" CenterX=".5" CenterY=".5" Rotation="90" />
</VideoBrush.RelativeTransform>
</VideoBrush>
</Border.Background>
<!--<StackPanel VerticalAlignment="Top">
<TextBlock x:Name="resolutionValueTextBlock" HorizontalAlignment="Center" Text="{Binding Value, ElementName=resolutionSlider}"/>
<Slider x:Name="resolutionSlider" HorizontalAlignment="Stretch" Margin="50,5,50,5"/>
<TextBlock x:Name="resolutionTextBlock" HorizontalAlignment="Center" Text="resolution"/>
</StackPanel>-->
<StackPanel VerticalAlignment="Bottom">
<TextBlock x:Name="zoomNumberTextBlock" HorizontalAlignment="Center" Text="{Binding Value, ElementName=zoomSlider}"/>
<Slider x:Name="zoomSlider" HorizontalAlignment="Stretch" Margin="50,5,50,5"/>
<TextBlock x:Name="zoomTextBlock" HorizontalAlignment="Center" Text="zoom"/>
</StackPanel>
</Border>
If possible I would like both stackpanels to be available, but if not I guess I would have to use the bottom one only.
Stay with the Grid:
<Grid>
<Rectangle>
<Rectangle.Fill>
<VideoBrush ... />
</Rectangle.Fill>
</Rectangle>
<Slider HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Margin="50,5,50,5"/>
</Grid>

Categories