Im trying to create a rangeslider for my application in MAUI C#. There is no default rangeslider in Maui library so I tried to make my own rangeslider in a very simple way. It works kind of fine but when I drag the left or right slider the thumbs tend to move a little bit in the GUI, and I of course don't want that. Can anyone help me?
P.S. Im kinda of a noob.
Here is my code:
public class DoubleSlider : ContentView
{
Slider sliderLeft;
Slider sliderRight;
double totalWidth;
Grid grid;
public DoubleSlider(Slider left, Slider right)
{
//initialize sliders
grid = new Grid();
this.Content = grid;
sliderLeft = left;
sliderRight = right;
//Make the right slider slide from right to left
sliderRight.Rotation = 180;
//Add events
sliderLeft.DragStarted += OnLeftDragStarted;
sliderRight.DragStarted += OnRightDragStarted;
sliderLeft.DragCompleted += OnLeftDragCompleted;
sliderRight.DragCompleted += OnRightDragCompleted;
}
public void SetSize(double width)
{
//Set size
grid.WidthRequest = width;
totalWidth = width;
//Left slider width
sliderLeft.WidthRequest = totalWidth;
//make some headroom so the user can press the thumb
sliderRight.WidthRequest = totalWidth - 20;
//Move up the slider a tiny bit so it looks that the sliders are in sync
sliderLeft.TranslationY = 1.1;
//Left slider start from left
sliderLeft.HorizontalOptions = LayoutOptions.Start;
//Right slider start from right
sliderRight.HorizontalOptions = LayoutOptions.End;
//Maximum values
sliderLeft.Maximum = totalWidth;
sliderRight.Maximum = totalWidth - 20;
grid.Add(sliderLeft);
grid.Add(sliderRight);
}
public void OnLeftDragStarted(object sender, EventArgs e)
{
Slider slider = sender as Slider;
//When drag started, give the slider the total width and maximum value
slider.WidthRequest = totalWidth;
slider.Maximum = totalWidth;
}
public void OnRightDragStarted(object sender, EventArgs e)
{
Slider slider = sender as Slider;
//When drag started, give the slider the total width and maximum value
slider.WidthRequest = totalWidth;
slider.Maximum = totalWidth;
}
public void OnLeftDragCompleted(object sender, EventArgs e)
{
Slider slider = sender as Slider;
//When drag is completed, give the width and maximum the slider value
slider.WidthRequest = slider.Value;
slider.Maximum = slider.Value;
//And minimize the other sliders width and maximum
sliderRight.WidthRequest = totalWidth - slider.Value;
sliderRight.Maximum = totalWidth - slider.Value;
}
public void OnRightDragCompleted(object sender, EventArgs e)
{
Slider slider = sender as Slider;
//When drag is completed, give the width and maximum the slider value
slider.WidthRequest = slider.Value;
slider.Maximum = slider.Value;
//And minimize the other sliders width and maximum
sliderLeft.WidthRequest = totalWidth - slider.Value;
sliderLeft.Maximum = totalWidth - slider.Value;
}
}
This is how it looks which is fine but when I drag the left or right thumb the other one tends to move a bit
enter image description here
Related
I have a WPF application that suppresses all the mouse inputs so I want to create my own inputs using xaml/behavior for MapSui 3.02. I've added the following method into my ViewModel to allow the user to zoom.
public void MapControlOnMouseWheel(object sender, MouseWheelEventArgs e)
{
Easing easing = default;
if (e.Delta > 0)
{
MapControl.Navigator.ZoomIn(mousePosition, 200, easing);
}
if (e.Delta < 0)
{
MapControl.Navigator.ZoomOut(mousePosition, 200, easing);
}
}
This Zoom method works ok, but it's not as good as the out of the box MapSui Zoom. It's not as smooth, and if you zoom a little too fast it ignores inputs until it has finished the last zoom event.
The out of the box MapSui zoom will zoom faster if you scroll the mouse button faster.
How is this achieved?
For completeness, here is the panning Method which explains where mousePosition comes from in the above zooming Method.
public void MapControlOnMouseMove(object sender, MouseEventArgs e)
{
var screenPosition = e.GetPosition(MapControl);
mousePosition = new Point(screenPosition.X, screenPosition.Y);
Point worldPosition = MapControl.Viewport.ScreenToWorld(screenPosition.X, screenPosition.Y);
if (mouseMiddledown)
{
var panX = lastPosition.X - worldPosition.X;
var panY = lastPosition.Y - worldPosition.Y;
Point newCenter = new Point(lastCentre.X + panX, lastCentre.Y + panY);
MapControl.Navigator?.NavigateTo(newCenter, MapControl.Viewport.Resolution, 0);
lastPosition = new Point(worldPosition.X + panX, worldPosition.Y + panY);
lastCentre = newCenter;
}
else
{
lastPosition = worldPosition;
lastCentre = MapControl.Viewport.Center;
}
CoordsText = $"{worldPosition.X:F0}, {worldPosition.Y:F0}";
}
I made a scrollable panel like this:
private void button3_Click(object sender, EventArgs e)
{
Form f2 = new Form();
f2.Size = new Size(400, 300);
f2.AutoScroll = false;
Panel pan = new Panel();
pan.Size = new Size(600, 100);
pan.AutoScroll = false;
for (int i = 1; i <= 10; i++)
{
Button b = new Button();
b.Text = "B" + (i);
b.Name = "button_" + (i);
b.Left = (b.Width + 12) * (i - 1);
b.Parent = pan;
pan.Parent = f2;
f2.Show();
}
}
private void panel1_MouseWheel(object sender, MouseEventArgs e)
{
Form2 frm = new Form2();
panel1.Top += e.Delta > 0 ? 10 : -10;
if (panel1.Top > 0)
panel1.Top = 0;
else if (panel1.Top <= panel1.Parent.Height)
panel1.Top = panel1.Parent.Height;
Console.WriteLine("panel2.top:" + panel1.Top);
}
This is the full code of that panel, panel1 = pan...
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
pPt = e.Location;
}
public void panel1_MouseMove(object sender, MouseEventArgs e)
{
Console.WriteLine("panel2.top:" + panel1.Top);
if (e.Button.HasFlag(MouseButtons.Left))
{
Form2 frm = new Form2();
panel1.Top += e.Y - pPt.Y;
if (panel1.Top > 0)
panel1.Top = 0;
else if (panel1.Top <= panel1.Parent.Height)
panel1.Top = panel1.Parent.Height;
}
}
And you can scroll it by dragging the panel with the mouse but the problem is it looks like this:
And I want to don't go higher than button1 or lower than the last button.
Tweak this method: you need to "pin" the panel so it doesn't move below the top and above the bottom - because mouse wheel deltas are events you will continuously receive. You have to manually decide when to ignore them
private void panel1_MouseWheel(object sender, MouseEventArgs e)
{
Form2 frm = new Form2();
panel1.Top += e.Delta > 0 ? 10 : -10;
// tweak this
if (panel1.Top > 0) panel1.Top = 0;
else if (panel1.Bottom <= panel1.Parent.Height) panel1.Bottom = panel1.Parent.Height;
Console.WriteLine("panel2.top:" + panel1.Top);
}
Also, the above will work when the panel you are scrolling is "Taller" than the viewport (the form itself). You might need to tweak further when the panel is smaller than the form - so just test a few cases.
You also need to pay attention to the Resize event so your panel has the correct Top property when someone expands the container form.
We can Get or set the upper limit of values of the scrollable range with
ScrollBar.Maximum Property
An example is as follows.
The following example assumes that you have created a Form, added a PictureBox to the Form, and added a horizontal HScrollBar and a vertical VScrollBar to the PictureBox. This code example is part of a larger example provided for the ScrollBar class overview.
In this example, the Maximum property is set to the size of the Image plus the size of the scrollbar if it is visible plus an adjustment factor of the size of the LargeChange property.
You must add references to the System.Drawing and System.Windows.Forms namespaces to run this example.
public void SetScrollBarValues()
{
//Set the following scrollbar properties:
//Minimum: Set to 0
//SmallChange and LargeChange: Per UI guidelines, these must be set
// relative to the size of the view that the user sees, not to
// the total size including the unseen part. In this example,
// these must be set relative to the picture box, not to the image.
//Maximum: Calculate in steps:
//Step 1: The maximum to scroll is the size of the unseen part.
//Step 2: Add the size of visible scrollbars if necessary.
//Step 3: Add an adjustment factor of ScrollBar.LargeChange.
//Configure the horizontal scrollbar
//---------------------------------------------
if (this.hScrollBar1.Visible)
{
this.hScrollBar1.Minimum = 0;
this.hScrollBar1.SmallChange = this.pictureBox1.Width / 20;
this.hScrollBar1.LargeChange = this.pictureBox1.Width / 10;
this.hScrollBar1.Maximum = this.pictureBox1.Image.Size.Width - pictureBox1.ClientSize.Width; //step 1
if (this.vScrollBar1.Visible) //step 2
{
this.hScrollBar1.Maximum += this.vScrollBar1.Width;
}
this.hScrollBar1.Maximum += this.hScrollBar1.LargeChange; //step 3
}
//Configure the vertical scrollbar
//---------------------------------------------
if (this.vScrollBar1.Visible)
{
this.vScrollBar1.Minimum = 0;
this.vScrollBar1.SmallChange = this.pictureBox1.Height / 20;
this.vScrollBar1.LargeChange = this.pictureBox1.Height / 10;
this.vScrollBar1.Maximum = this.pictureBox1.Image.Size.Height - pictureBox1.ClientSize.Height; //step 1
if (this.hScrollBar1.Visible) //step 2
{
this.vScrollBar1.Maximum += this.hScrollBar1.Height;
}
this.vScrollBar1.Maximum += this.vScrollBar1.LargeChange; //step 3
}
}
Hope you can change the code accordingly to set the maximum scrollable space.:)
I want to be able to grab a datapoint drawn in a chart and to move it and change its position by dragging it over the chart control.
How can I ..
..grab the specific series point (series name ="My Series")
When released the series point should change its position/ values
It's like making series points movable with drag event.
Here the color dots (points) should be able to move:
There are some charts like devExpress chart which perform this task but I want to do it in normal MS chart.
Moving a DataPoint is not a built-in feature of the Chart control. We need to code it..
The problem with interacting with a Chart by mouse is that there are not one but three coordinate systems at work in a Chart:
The chart elements, like a Legend or an Annotation are measured in percentages of the respective containers. Those data make up an ElementPosition and usually go from 0-100%.
The Mouse coordinates and all graphics drawn in one of the three Paint events, all work in pixels; they go from 0-Chart.ClientSize.Width/Height.
The DataPoints have an x-value and one (or more) y-values(s). Those are doubles and they can go from and to anywhere you set them to.
For our task we need to convert between mouse pixels and data values.
DO see the Update below!
There are several ways to do this, but I think this is the cleanest:
First we create a few class level variables that hold references to the targets:
// variables holding moveable parts:
ChartArea ca_ = null;
Series s_ = null;
DataPoint dp_ = null;
bool synched = false;
When we set up the chart we fill some of them:
ca_ = chart1.ChartAreas[0];
s_ = chart1.Series[0];
Next we need two helper functions. They do the 1st conversion between pixels and data values:
// two helper functions:
void SyncAllPoints(ChartArea ca, Series s)
{
foreach (DataPoint dp in s.Points) SyncAPoint(ca, s, dp);
synched = true;
}
void SyncAPoint(ChartArea ca, Series s, DataPoint dp)
{
float mh = dp.MarkerSize / 2f;
float px = (float)ca.AxisX.ValueToPixelPosition(dp.XValue);
float py = (float)ca.AxisY.ValueToPixelPosition(dp.YValues[0]);
dp.Tag = (new RectangleF(px - mh, py - mh, dp.MarkerSize, dp.MarkerSize));
}
Note that I chose to use the Tag of each DataPoints to hold a RectangleF that has the clientRectangle of the DataPoint's Marker.
These rectangles will change whenever the chart is resized or other changes in the Layout, like sizing of a Legend etc.. have happend, so we need to re-synch them each time! And, of course you need to initially set them whenever you add a DataPoint!
Here is the Resize event:
private void chart1_Resize(object sender, EventArgs e)
{
synched = false;
}
The actual refreshing of the rectangles is being triggered from the PrePaint event:
private void chart1_PrePaint(object sender, ChartPaintEventArgs e)
{
if ( !synched) SyncAllPoints(ca_, s_);
}
Note that calling the ValueToPixelPosition is not always valid! If you call it at the wrong time it will return null.. We are calling it from the PrePaint event, which is fine. The flag will help keeping things efficient.
Now for the actual moving of a point: As usual we need to code the three mouse events:
In the MouseDown we loop over the Points collection until we find one with a Tag that contains the mouse position. Then we store it and change its Color..:
private void chart1_MouseDown(object sender, MouseEventArgs e)
{
foreach (DataPoint dp in s_.Points)
if (((RectangleF)dp.Tag).Contains(e.Location))
{
dp.Color = Color.Orange;
dp_ = dp;
break;
}
}
In the MouseMove we do the reverse calculation and set the values of our point; note that we also synch its new position and trigger the Chart to refresh the display:
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left) && dp_ != null)
{
float mh = dp_.MarkerSize / 2f;
double vx = ca_.AxisX.PixelPositionToValue(e.Location.X);
double vy = ca_.AxisY.PixelPositionToValue(e.Location.Y);
dp_.SetValueXY(vx, vy);
SyncAPoint(ca_, s_, dp_);
chart1.Invalidate();
}
else
{
Cursor = Cursors.Default;
foreach (DataPoint dp in s_.Points)
if (((RectangleF)dp.Tag).Contains(e.Location))
{
Cursor = Cursors.Hand; break;
}
}
}
Finally we clean up in the MouseUp event:
private void chart1_MouseUp(object sender, MouseEventArgs e)
{
if (dp_ != null)
{
dp_.Color = s_.Color;
dp_ = null;
}
}
Here is how I have set up my chart:
Series S1 = chart1.Series[0];
ChartArea CA = chart1.ChartAreas[0];
S1.ChartType = SeriesChartType.Point;
S1.MarkerSize = 8;
S1.Points.AddXY(1, 1);
S1.Points.AddXY(2, 7);
S1.Points.AddXY(3, 2);
S1.Points.AddXY(4, 9);
S1.Points.AddXY(5, 19);
S1.Points.AddXY(6, 9);
S1.ToolTip = "(#VALX{0.##} / #VALY{0.##})";
S1.Color = Color.SeaGreen;
CA.AxisX.Minimum = S1.Points.Select(x => x.XValue).Min();
CA.AxisX.Maximum = S1.Points.Select(x => x.XValue).Max() + 1;
CA.AxisY.Minimum = S1.Points.Select(x => x.YValues[0]).Min();
CA.AxisY.Maximum = S1.Points.Select(x => x.YValues[0]).Max() + 1;
CA.AxisX.Interval = 1;
CA.AxisY.Interval = 1;
ca_ = chart1.ChartAreas[0];
s_ = chart1.Series[0];
Note that I have set both the Minima and Maxima as well as the Intervals for both Axes. This stops the Chart from running wild with its automatic display of Labels, GridLines, TickMarks etc..
Also note that this will work with any DataType for X- and YValues. Only the Tooltip formatting will have to be adapted..
Final note: To prevent the users from moving a DataPoint off the ChartArea you can add this check into the if-clause of the MouseMove event:
RectangleF ippRect = InnerPlotPositionClientRectangle(chart1, ca_);
if (!ippRect.Contains(e.Location) ) return;
For the InnerPlotPositionClientRectangle function see here!
Update:
On revisiting the code I wonder why I didn't choose a simpler way:
DataPoint curPoint = null;
private void chart1_MouseUp(object sender, MouseEventArgs e)
{
curPoint = null;
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left))
{
ChartArea ca = chart1.ChartAreas[0];
Axis ax = ca.AxisX;
Axis ay = ca.AxisY;
HitTestResult hit = chart1.HitTest(e.X, e.Y);
if (hit.PointIndex >= 0) curPoint = hit.Series.Points[hit.PointIndex];
if (curPoint != null)
{
Series s = hit.Series;
double dx = ax.PixelPositionToValue(e.X);
double dy = ay.PixelPositionToValue(e.Y);
curPoint.XValue = dx;
curPoint.YValues[0] = dy;
}
}
download Samples Environments for Microsoft Chart Controls
https://code.msdn.microsoft.com/Samples-Environments-for-b01e9c61
Check this:
Chart Features -> Interactive Charting -> Selection -> Changing Values by dragging
I have a scrollviewer with a grid as the child. I am changing the grid's width and height properties to show different "zoom" levels. The grid contains 2 rows with many columns of images, all the same size.
However, I want the relative position of the scrollbar to stay the same. Whatever is on the center of the screen should still be on the center of the screen after changing the grid's size.
Default "zoomed in" view:
private void SizeGrid()
{
grid1.Width = (scrollViewer1.ViewportWidth / 2) * grid1.ColumnDefinitions.Count;
grid1.Height = (scrollViewer1.ViewportHeight / 2) * grid1.RowDefinitions.Count;
}
"Zoomed out" view:
private void scrollViewer1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyboardDevice.IsKeyDown(Key.Insert))
{
grid1.Width = (scrollViewer1.ViewportWidth / 2) * grid1.ColumnDefinitions.Count / 5;
grid1.Height = (scrollViewer1.ViewportHeight / 2) * grid1.RowDefinitions.Count / 3;
}
}
What I tried doing...
If I know what column is focused (I don't want to need to know this):
double shiftAmount = (scrollViewer1.ScrollableWidth / (grid1.ColumnDefinitions.Count - columnsOnScreen));
scrollViewer1.ScrollToHorizontalOffset(column * shiftAmount);
If I don't know exactly what column they are looking at, but I just want to keep the relative position...
double previousScrollRatio = scrollViewer1.HorizontalOffset / scrollViewer1.ScrollableWidth;
//resize grid...
scrollViewer1.ScrollToHorizontalOffset(previousScrollRatio * scrollViewer1.ScrollableWidth);
Neither approach works. If I zoom out with the scrollbar centered, then the scrollbar will go to the far right. Any idea?
A minimal code example can be found here plus the scroll_KeyDown method from above.
Screenshot of the default zoom:
Screenshot after zooming out, incorrectly (the navy blue and pink squares are far off screen):
Screenshot after zooming out, what it should look like:
Here is a solution to keep the content in center while zooming in or out
//variables to store the offset values
double relX;
double relY;
void scrollViewer1_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ScrollViewer scroll = sender as ScrollViewer;
//see if the content size is changed
if (e.ExtentWidthChange != 0 || e.ExtentHeightChange != 0)
{
//calculate and set accordingly
scroll.ScrollToHorizontalOffset(CalculateOffset(e.ExtentWidth, e.ViewportWidth, scroll.ScrollableWidth, relX));
scroll.ScrollToVerticalOffset(CalculateOffset(e.ExtentHeight, e.ViewportHeight, scroll.ScrollableHeight, relY));
}
else
{
//store the relative values if normal scroll
relX = (e.HorizontalOffset + 0.5 * e.ViewportWidth) / e.ExtentWidth;
relY = (e.VerticalOffset + 0.5 * e.ViewportHeight) / e.ExtentHeight;
}
}
private static double CalculateOffset(double extent, double viewPort, double scrollWidth, double relBefore)
{
//calculate the new offset
double offset = relBefore * extent - 0.5 * viewPort;
//see if it is negative because of initial values
if (offset < 0)
{
//center the content
//this can be set to 0 if center by default is not needed
offset = 0.5 * scrollWidth;
}
return offset;
}
idea behind is to store the last scroll position and use it to calculate the new offset whenever the content size is changed which will make the change in extent.
just attach the event ScrollChanged of ScrollViewer to this event handler in constructor etc. and leave the rest to it.
eg
scrollViewer1.ScrollChanged += scrollViewer1_ScrollChanged;
above solution will ensure to keep the grid in center, even for first load
sample of centered content
zoomed in
zoomed out
Extra
I also tried to create an attachable behavior for the same so you do not need to wire the events, just setting up the property will enable or disable the behavior
namespace CSharpWPF
{
public class AdvancedZooming : DependencyObject
{
public static bool GetKeepInCenter(DependencyObject obj)
{
return (bool)obj.GetValue(KeepInCenterProperty);
}
public static void SetKeepInCenter(DependencyObject obj, bool value)
{
obj.SetValue(KeepInCenterProperty, value);
}
// Using a DependencyProperty as the backing store for KeepInCenter. This enables animation, styling, binding, etc...
public static readonly DependencyProperty KeepInCenterProperty =
DependencyProperty.RegisterAttached("KeepInCenter", typeof(bool), typeof(AdvancedZooming), new PropertyMetadata(false, OnKeepInCenterChanged));
// Using a DependencyProperty as the backing store for Behavior. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BehaviorProperty =
DependencyProperty.RegisterAttached("Behavior", typeof(AdvancedZooming), typeof(AdvancedZooming), new PropertyMetadata(null));
private static void OnKeepInCenterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ScrollViewer scroll = d as ScrollViewer;
if ((bool)e.NewValue)
{
//attach the behavior
AdvancedZooming behavior = new AdvancedZooming();
scroll.ScrollChanged += behavior.scroll_ScrollChanged;
scroll.SetValue(BehaviorProperty, behavior);
}
else
{
//dettach the behavior
AdvancedZooming behavior = scroll.GetValue(BehaviorProperty) as AdvancedZooming;
if (behavior != null)
scroll.ScrollChanged -= behavior.scroll_ScrollChanged;
scroll.SetValue(BehaviorProperty, null);
}
}
//variables to store the offset values
double relX;
double relY;
void scroll_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ScrollViewer scroll = sender as ScrollViewer;
//see if the content size is changed
if (e.ExtentWidthChange != 0 || e.ExtentHeightChange != 0)
{
//calculate and set accordingly
scroll.ScrollToHorizontalOffset(CalculateOffset(e.ExtentWidth, e.ViewportWidth, scroll.ScrollableWidth, relX));
scroll.ScrollToVerticalOffset(CalculateOffset(e.ExtentHeight, e.ViewportHeight, scroll.ScrollableHeight, relY));
}
else
{
//store the relative values if normal scroll
relX = (e.HorizontalOffset + 0.5 * e.ViewportWidth) / e.ExtentWidth;
relY = (e.VerticalOffset + 0.5 * e.ViewportHeight) / e.ExtentHeight;
}
}
private static double CalculateOffset(double extent, double viewPort, double scrollWidth, double relBefore)
{
//calculate the new offset
double offset = relBefore * extent - 0.5 * viewPort;
//see if it is negative because of initial values
if (offset < 0)
{
//center the content
//this can be set to 0 if center by default is not needed
offset = 0.5 * scrollWidth;
}
return offset;
}
}
}
enabling the behavior
via xaml
<ScrollViewer l:AdvancedZooming.KeepInCenter="True">
or
<Style TargetType="ScrollViewer" x:Key="zoomCenter">
<Setter Property="l:AdvancedZooming.KeepInCenter"
Value="True" />
</Style>
or via code like
scrollViewer1.SetValue(AdvancedZooming.KeepInCenterProperty, true);
or
AdvancedZooming.SetKeepInCenter(scrollViewer1, true);
set the property l:AdvancedZooming.KeepInCenter="True" inline, via styles or programmatically in order to enable the behavior on any scrollviewer
l: refers to the namespace to AdvancedZooming class xmlns:l="clr-namespace:CSharpWPF" in this example
This may sound a bit complicated but if you align the center of the object (that is inside the grid's cell) with the center of the scrollbar, using the screen coordinates?
You can use the PointToScreen to get the object coordinates in screen coordinates and align it after the zoom out or zoom in.
private void OnMouseMove(object sender, MouseEventArgs e)
{
var element = (UIElement)e.Source;
int c = Grid.GetColumn(element);
int r = Grid.GetRow(element);
}
This only works, if you have UIElements in each cell.
Or you can try this to get the coordinates.
This is just an assumption since I cannot test it right know.
I am trying to make it so that when the user holds down the left mouse button the slider control appears where the mouse is positioned and the user can move the slider control left/right. Once the left mouse button is removed it will pass the value into a method. I am completely stuck on this. I have the slider control built, with a default position (the position can vary).
I have tried the following code to get the slider control to move to the mouses position but it does not do anything:
private void Button_Click(object sender, RoutedEventArgs e)
{
TranslateTransform currentTransform = new TranslateTransform();
currentTransform = slider.RenderTransform as TranslateTransform;
currentTransform.X = Mouse.GetPosition(Deck_Door).X;
currentTransform.Y = Mouse.GetPosition(Deck_Door).Y;
slider.Visibility = Visibility.Visible;
}
Thanks in advance!
First you should capture mouse
then you should calculate mouse move distance
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
this.CaptureMouse();
//Show slider here
}
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
this.ReleaseMouseCapture();
//Hide slider here and get it's value
}
Point previousMousePosition;
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
if (this.IsMouseCaptured)
{
Point point = e.GetPosition(this);
double d = point.X - previousMousePosition.X;
//you can use this value to change the slider's value
this.previousMousePosition = point;
}
}
I was able to do this fairly easily. I modified the slider code to include a name for the translateTransform:
<Slider x:Name="slider"
TickFrequency="1"
Value="1"
IsSnapToTickEnabled="True"
IsMoveToPointEnabled="True"
Minimum="0"
Maximum="10"
ValueChanged="slider_ValueChanged"
AutoToolTipPlacement="BottomRight"
Grid.Column="0" VerticalAlignment="Top" Margin="0,-3,51.5,0"
Thumb.DragCompleted="slider_DragCompleted" >
<Slider.RenderTransform>
<TranslateTransform x:Name="mySliderTransform" />
</Slider.RenderTransform>
</Slider>
Then I hooked a click event to a button and used the following code:
private void Button_Click(object sender, RoutedEventArgs e)
{
slider.Visibility = Visibility.Visible;
slider.Value = 1;
// get the mouse positions
string x = Mouse.GetPosition(this).X.ToString();
string y = Mouse.GetPosition(this).Y.ToString();
// convert the mouse position to a double
var X = Convert.ToDouble(x);
var Y = Convert.ToDouble(y);
// reset the slider transform and apply the coordinates of the mouse position.
mySliderTransform.X = 0;
mySliderTransform.Y = 0;
mySliderTransform.X = X - 20;
mySliderTransform.Y = Y;
}