WPF: put Label around Circle in specific Circle Value point - wpf

So i have this Circle and Slider:
<DesignInControl:CircularProgressBar
x:Name="circle"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Percentage="{Binding Value, ElementName=slider}"
SegmentColor="Red"
StrokeThickness="25"
Radius="100"/>
So when this Slider value changed My Circle Percentage property is updated but also i want to add Label near the Circle Value.
For example if the Circle Percentage is 83% i want:
So inside my Slider ValueChanged Event i calculate this:
public void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
var radius = circle.Radius;
var sangle = (slider.Value * 360) / 100;
double angleRad = (Math.PI / 180.0) * (sangle - 90);
double x = radius * Math.Cos(angleRad);
double y = radius * Math.Sin(angleRad);
vlb.Content = string.Format("{0:N2}", slider.Value);
vlb.RenderTransform = new RotateTransform { Angle = sangle, CenterX = 0, CenterY = 0 };
}
So i create simple Label:
<Label x:Name="vlb"
Content="123"
Margin="-50,-50,-50,-50"
HorizontalAlignment="Center"
RenderTransformOrigin="0.5,0.5"
Grid.RowSpan="2"
xml:space="preserve">
<Label.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="3600.12"/>
<TranslateTransform/>
</TransformGroup>
</Label.RenderTransform>
</Label>
And the result is almost what i want:
The only problem is that my Label is not straight.
Any suggestions how to solve it ?

Related

How can I refresh the position of a Slider with Scroll event?

I'm now tryin to scaling a image with mouse-wheel cmd.
and have some problems with refresh the position of slider position.
MainWindow.xaml
<Grid Grid.Row="1">
<Slider x:Name="slider_value" Value="{Binding Scale, Mode=TwoWay}" Maximum="3" Minimum="1"/>
</Grid>
<Other Grid>
<target obj want to scale>
<Grid.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=slider_value, Path=Value}"
ScaleY="{Binding ElementName=slider_value, Path=Value}"/>
</Grid.LayoutTransform>
</Other Grid>
MainViewModel.cs
private void ExecuteZoom(MouseWheelEventArgs e) {
if(e.Delta > 0) {
if(Scale>=3)
return;
Scale += 0.1;
}
if(e.Delta < 0) {
if(Scale<=1)
return;
Scale -= 0.1;
}
//((MainWindow)Application.Current.MainWindow).UpdateLayout();
//i thought this can be solved by above code but don't work
Debug.Print($"{Scale}");
}
I checked
the value of var Scale varies successfully with mouseWheel
the value of var Scale varies successfully with moving slider
the scale of target varies with slider moved by "Manually"
the value of var Scale successfully is changed
but the position of slider isn't affected, and also ScaleTransForm doesnt work.
thanks!
enter image description here
enter image description here

Silverlight Geometry scaling issue

How can I implement zoom to specific point in Silverlight using geometry and ScaleTransform? Can you suggest some algorithm so that I can achieve this? My logic is wrong. I think I have some trouble by setting the center point of scaling.
This is my geometry data in xaml file
<Canvas x:Name="LayoutRoot" Background="Orchid" MouseWheel="PathDraw_OnMouseWheel">
<Path x:Name="PathDraw" Stroke="Brown" StrokeThickness="1" Margin="200,200,0,0">
<Path.Data>
<RectangleGeometry x:Name="rect" Rect="80 80 80 80"/>
</Path.Data>
</Path>
</Canvas>
And below is the scaling logic.
private static int ZoomSteps = 0;
private static double centerX = 0;
private static double centerY = 0;
private double zoomCoeff = 1.1;
private void PathDraw_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
double delta = e.Delta;
if (scaleX != 1)
{
scaleX = delta >= 0 ? scaleX * zoomCoeff : (scaleX <= 1 ? 1 : scaleX / zoomCoeff);
scaleY = delta >= 0 ? scaleY * zoomCoeff : (scaleY <= 1 ? 1 : scaleY/zoomCoeff);
}
else
{
scaleX = scaleY = delta >= 0 ? zoomCoeff : 1;
}
scale = new ScaleTransform { ScaleX = scaleX, ScaleY = scaleY,
CenterX = e.GetPosition(PathDraw).X,
CenterY = e.GetPosition(PathDraw).Y
};
rect.Transform = scale;
}
Thanks
Instead of having a Margin at the Path and a Geometry that has an inherent offset (rectangle upper left corner at 80,80) you should separate scaling from translation by using two transforms:
<Canvas x:Name="LayoutRoot" Background="AliceBlue" MouseWheel="PathDraw_OnMouseWheel">
<Path x:Name="PathDraw" Stroke="Brown" StrokeThickness="1">
<Path.Data>
<RectangleGeometry x:Name="rect" Rect="0 0 80 80">
<RectangleGeometry.Transform>
<TransformGroup>
<ScaleTransform x:Name="scaleTransform"/>
<TranslateTransform x:Name="translateTransform"
X="100" Y="100"/>
</TransformGroup>
</RectangleGeometry.Transform>
</RectangleGeometry>
</Path.Data>
</Path>
</Canvas>
With this your MouseWheel event handler becomes as simple as this:
private double zoomCoeff = 1.1;
private void PathDraw_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
var deltaScale = (e.Delta > 0) ? zoomCoeff : (1d / zoomCoeff);
var position = e.GetPosition((UIElement)sender);
var dx = position.X - translateTransform.X;
var dy = position.Y - translateTransform.Y;
translateTransform.X = position.X - deltaScale * dx;
translateTransform.Y = position.Y - deltaScale * dy;
scaleTransform.ScaleX *= deltaScale;
scaleTransform.ScaleY *= deltaScale;
}
You may now also independently manipulate the translation in a MouseMove handler in order to drag the rectangle.

WPF DataGrid Zoom to mouse position

I have a DataGrid that LayoutTransform is Binded to a Slider like that:
<DataGrid.LayoutTransform>
<ScaleTransform
ScaleX="{Binding ElementName=MySlider, Path=Value}"
ScaleY="{Binding ElementName=MySlider, Path=Value}" />
</DataGrid.LayoutTransform>
</DataGrid>
<Slider x:Name="MySlider"
Minimum="0.3"
Maximum="2.0"
SmallChange="0.1"
LargeChange="0.1"
Value="1.0"
IsSnapToTickEnabled="True"
TickFrequency="0.1"
TickPlacement="TopLeft"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Width="200"
Margin="0,0,61,0" />
<TextBlock Name="Lstate"
Text="{Binding ElementName=MySlider, Path=Value, StringFormat={}{0:P0}}"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Width="50" Height="20"
Margin="0,0,0,1" />
Now, in the Code I have the PreviewMouseWheel event with the following Code:
bool handle = (Keyboard.Modifiers & ModifierKeys.Control) > 0;
if (!handle)
return;
double value;
if (e.Delta > 0)
value = 0.1;
else
value = -0.1;
MySlider.Value += value;
And my question is: How to scroll to the actual Mouse Position like AutoCad or some other programs?
Thanks
Sorry for my bad english...
I have a very very good solution now:
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
EnableColumnVirtualization="False"
EnableRowVirtualization="True"
ScrollViewer.CanContentScroll="True"
private void Data_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
// Scroll to Zoom
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
// Prevent scroll
e.Handled = true;
var scrollview = FindVisualChild<ScrollViewer>(Data);
if (scrollview != null)
{
// The "+20" are there to account for the scrollbars... i think. Not perfectly accurate.
var relativeMiddle = new Point((Data.ActualWidth + 20) / 2 + (Mouse.GetPosition(Data).X - Data.ActualWidth / 2), (Data.ActualHeight + 20) / 2 + (Mouse.GetPosition(Data).Y - Data.ActualHeight / 2));
var oldLocation = Data.LayoutTransform.Transform(Data.PointFromScreen(relativeMiddle));
// Zoom
MySlider.Value += (e.Delta > 0) ? MySlider.TickFrequency : -MySlider.TickFrequency;
// Scroll
var newLocation = Data.LayoutTransform.Transform(Data.PointFromScreen(relativeMiddle));
// Calculate offset
var shift = newLocation - oldLocation;
if (scrollview.CanContentScroll)
{
// Scroll to the offset (Item)
scrollview.ScrollToVerticalOffset(scrollview.VerticalOffset + shift.Y / scrollview.ViewportHeight);
}
else
{
// Device independent Pixels
scrollview.ScrollToVerticalOffset(scrollview.VerticalOffset + shift.Y);
}
// Device independent Pixels
scrollview.ScrollToHorizontalOffset(scrollview.HorizontalOffset + shift.X);
}
}
}
It zooms to the Mouse Position on the Datagrid with and without virtualization.

Scaling InkCanvas strokes to fit specific dimensions to crop out unused space

I am attempting to scale an InkCanvas's contents (Strokes) to fit a fixed page size for printing. I want to essentially crop out all of the surrounding whitespace from the InkCanvas, and scale up the Strokes to fit the page while maintaining aspect ratio.
In the handler below the markup, you can see that I am changing the dimensions of the grid that starts at 800x300, and I'm making it 425x550, half of the size of a printable page.
markup:
<Grid>
<Button Height="100" Width="100" HorizontalAlignment="Left" PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown_1" />
<Grid Width="1200" Height="1400" Background="Aquamarine" HorizontalAlignment="Right" VerticalAlignment="Top">
<Grid Background="Red" x:Name="grid" Width="800" Height="300">
<Viewbox x:Name="vb" Width="800" Height="300" Stretch="Fill" StretchDirection="Both">
<InkCanvas Width="500" Height="500" Background="Transparent" IsEnabled="True"/>
</Viewbox>
</Grid >
</Grid>
</Grid>
codebehind file:
bool b = true;
private void Button_PreviewMouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
if (b)
{
//I toyed with using Uniform, UniformToFill, and Fill
vb.Stretch = Stretch.Fill;
grid.Width = 425;
grid.Height = 550;
//scale viewbox down until it fits horizontally
var scaleX = grid.Width / vb.Width;
vb.Width *= scaleX;
vb.Height *= scaleX;
//if constraining it to the width made it larger than it needed to be vertically, scale it down
if (vb.Height > grid.Height)
{
var scaleY = grid.Height / vb.Height;
vb.Width *= scaleY;
vb.Height *= scaleY;
}
b = false;
}
else
{
//reset it back to what it was
vb.Stretch = Stretch.Fill;
grid.Width = 800;
grid.Height = 300;
vb.Width = grid.Width;
vb.Height = grid.Height;
b = true;
}

Event bubbling with CaptureMouse() in Silverlight

I'm writing a window program in Silverlight, meaning that the top bar of a popup has a draggable area, and within that draggable area, an "X" that closes the window. My drag function has a capturemouse() event which, when combined with the event bubbling that occurs, prevents the close function from being called. Here's the code:
private void close_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e){
pop.IsOpen = false;
hasFocus = true;
}
private void topBar_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Border item = sender as Border;
mouseY = e.GetPosition(null).Y;
mouseX = e.GetPosition(null).X;
draggable = true;
item.CaptureMouse();
}
private void topBar_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if(draggable){
double changeY = e.GetPosition(null).Y - mouseY;
double changeX = e.GetPosition(null).X - mouseX;
double top = changeY + (double)pop.GetValue(Canvas.TopProperty);
double left = changeX + (double)pop.GetValue(Canvas.LeftProperty);
if(top<0){
top = 0;
}
if(left<0){
left = 0;
}
if(left>670){
left = 670;
}
if(top>450){
top = 450;
}
pop.SetValue(Canvas.TopProperty, top);
pop.SetValue(Canvas.LeftProperty, left);
mouseY = e.GetPosition(null).Y;
mouseX = e.GetPosition(null).X;
}
}
private void topBar_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Border item = sender as Border;
draggable = false;
mouseY = -1;
mouseX = -1;
item.ReleaseMouseCapture();
}
EDIT: here is the XAML for the entire popup:
<Popup x:Name="pop" Height="200" Width="200" VerticalAlignment="Center" HorizontalAlignment="Center">
<Border CornerRadius="5" Width="200" Height="200" Background="#FFFAFCFF" BorderThickness="1">
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99666666" Offset="0" />
<GradientStop Color="#99F5F5F5" Offset="0.5"/>
<GradientStop Color="#99666666" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
<StackPanel>
<Border x:Name="topBar" CornerRadius="4,4,0,0" BorderBrush="Silver" BorderThickness="0,0,0,1" Background="Crimson" Width="198" Height="20" MouseLeftButtonDown="topBar_MouseLeftButtonDown" MouseMove="topBar_MouseMove" MouseLeftButtonUp="topBar_MouseLeftButtonUp">
<Image x:Name="close" Source="X.png" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,7,0" Height="11" Width="11" MouseLeftButtonUp="close_MouseLeftButtonUp" />
</Border>
<StackPanel Margin="10">
<TextBlock Text="Printer info goes here..." />
</StackPanel>
</StackPanel>
</Border>
</Popup>
The problem occurs because of your MouseCapture calls. When you set the mousecapture, the border is the only control that will be allowed to initiate mouse events. This means the image, while the mouse button is down, no longer triggers mouseevents.
Without the mousecapture it should work fine. Just for my curiosity, why do you set and release it?
I hope this helps.
Edit:
You can get the position of the mouseEvent and see if it falls in the image:
var x = e.GetPosition(close).X;
var y = e.GetPosition(close).Y;
if (0 <= x && x <= 11 && 0 <= y && y <= 11)
{
//do the close call
}
I haven't tested this code but it should be close to what you want to do.

Resources