I have a ListView (auftraegeView). Of this ListView I whish to change the FontSize of its Items through Ctrl + MouseWheel aka. a simple zoom like in excel or a browser.
In the form's ctor I subscribed my method to the event
this.MouseWheel += scrollZoom;
My EventHandler calculates the new FontHeight and applies it, if it doesn't exceed the bounds. The RowHeight is always kept a little bigger, finally I resize the columns so the zoom also works on the horizontal scale.
private void scrollZoom(object sender, MouseEventArgs e)
{
if(Control.ModifierKeys != Keys.Control)
return;
int currFontHeight = ListViewFontHeight;
int delta = (e.Delta)/120;
int newFontHeight = currFontHeight + delta;
if(newFontHeight < 1 || newFontHeight > 150)
return;
ListViewFontHeight = newFontHeight;
ListViewRowHeight = ListViewFontHeight + 4;
auftraegeView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
}
ListViewFontHeight gets the Font.Height of the first Item. (Value is identical across all Items, so the first is as good as any.)
The set is where the issue seems to be (see below). My idea is that I just go through each Item and change the Font.
private int ListViewFontHeight
{
get { return auftraegeView.Items[0].Font.Height; }
set
{
foreach (ListViewItem line in auftraegeView.Items)
{
line.Font = new Font(line.Font.FontFamily, value);
}
}
}
ISSUE / QUESTION
Regardless of the direction I scroll in, the FontSize only increases till it hits the ceiling. The rest works fine (setting ListViewRowHeight, detecting the event at all,...).
What might be causing this?
Try this:
delta = (e.Delta > 0? 1 : -1);
to be on the safe side for different mouse settings.
This works for me:
float delta = (e.Delta > 0 ? 2f : -2f);
listView1.Font = new Font (listView1.Font.FontFamily, listView1.Font.Size + delta);
Found it myself:
In the ListViewFontHeight - property the get accessor used Item.Font.Height instead of Item.Font.Size
private int ListViewFontHeight
{
get { return (int)auftraegeView.Items[0].Font.Size; } //works now
Related
I have been attempting to understand the tiled listView in c#.net for weeks now with no succession.
I have shrunk my form's height/width (154x154) to the same tile size as the picture(s) (items with pictures) in my listView (which is docked in the form2); when my form2 is shown, you see item[0] in the listView...that is it! (which I want so far, so good!)
I have set the scrollable property to false to do away with both scrollbars (works perfectly fine so far...)
I have hooked both the left and right arrow keys GLOBALLY (which works as it has been thoroughly debugged) and when clicking the RIGHT arrow key, it should VERTICALLY bring up item[1], and so fourth.
The LEFT arrow key would bring up the previous item till it hits 0.
I have tried the following, but it does NOTHING.
private void HotkeyHandler(int i)
{
{
if (this.listView1.InvokeRequired)
{
SetHotkeyCallback p = new SetHotkeyCallback(HotkeyHandler);
this.Invoke(p, new object[] { i });
}
else
{
switch (i)
{
case 1:
listView1.View = View.List;
if (listView1.TopItem.Index > 0)
{
listView1.TopItem = listView1.Items[listView1.TopItem.Index - 1];
}
listView1.View = View.Tile;
break;
case 2:
listView1.View = View.List;
if (listView1.TopItem.Index < listView1.Items.Count)
{
listView1.TopItem = listView1.Items[listView1.TopItem.Index + 1];
}
listView1.View = View.Tile;
break;
}
}
}
}
Please help me, I been loosing my mind for weeks now.
EDIT: The switch within the function above does go off, I have debugged it; therefore, it is not the invoking that is the problem...
I don't think you can do it directly.
The way to get rid of the ScrollBars is indeed to set Scrollable = false;.
But that means what it says: Now the ListView will not scroll.
Here is a common workaround for many scrolling issues:
Place the Listview in a Panel and make it as large as needed to show all Items.
Then in order to scroll simply move the LV up and down:
private void prepare_Click_1(object sender, EventArgs e)
{
// we sit inside a Panel
listView1.Parent = panel1;
// initially they have the same size
listView1.Size = panel1.Size;
listView1.Location = Point.Empty;
// a few test items
for (int i = 0; i < 100; i++)
listView1.Items.Add("Item " + i);
// now grow the height to display all items:
int cols = listView1.Width / listView1.TileSize.Width;
listView1.Height = (listView1.Items.Count / cols) * listView1.TileSize.Height;
}
// moving the LV up looks like scrolling down..
private void scrollDown_Click(object sender, EventArgs e)
{
listView1.Top -= listView1.TileSize.Height;
if (listView1.Bottom < panel1.Height)
listView1.Top = -listView1.Height + panel1.Height;
}
// moving the LV down looks like scrolling up..
private void scrollUp_Click_1(object sender, EventArgs e)
{
listView1.Top += listView1.TileSize.Height;
if (listView1.Top > 0) listView1.Top = 0;
}
i have taken one Flow layout panel and placed multiple picture box inside in it. now i want when i will place my mouse at the right or left most edge of the Flow layout panel then rest of picture will scroll out. just think about windows 8 start screen where many tiles appear in screen and when we place mouse at right most edge on the screen then rest of the tiles scroll out. i want to simulate same thing in windows form with Flow layout panel.
i want my Flow layout panel will not show scroll bar but images will scroll out when i will place mouse right or left most part on the panel. here is my screen shot
some one told me to do it this way...here is bit code
Set AutoScrollPosition property in MouseMove event of Panel.
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
panel1.AutoScrollPosition = new Point(e.X, e.Y);
}
but this trick was not good. AutoScrollPosition works when scroll bar is visible but in my case i do not want to show scroll bar with Flow layout panel. i want smooth scrolling images from left to right or right to left. anyone can help me to achieve what i am trying to do....if possible guide me with respect of coding. thanks
EDIT
Here i am giving my full code after modification following #Taw suggestion but it is not working fine....rather flickering found when picture move. anyway here is the full code.
namespace ScrollTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
flowLayoutPanel1.MouseMove += MouseScroll;
foreach (Control x in this.Controls)
{
if (x is PictureBox)
{
((PictureBox)x).MouseMove += MouseScroll;
}
}
}
int near = 33;
private void MouseScroll(object sender, MouseEventArgs e)
{
Point mouse = flowLayoutPanel1.PointToClient(MousePosition);
Rectangle C = flowLayoutPanel1.ClientRectangle;
int dLeft = mouse.X - C.Left;
int dTop = mouse.Y - C.Top;
int dRight = C.Right - mouse.X;
int dBottom = C.Bottom - mouse.Y;
int dX = dLeft < near ? dLeft : dRight < near ? -dRight : 0;
int dY = dTop < near ? dTop : dBottom < near ? -dBottom : 0;
if (dX != 0 | dY != 0) scrollFLP(dX, dY);
}
void scrollFLP(int deltaX, int deltaY)
{
flowLayoutPanel1.Left += getSpeedFromDistance(deltaX);
flowLayoutPanel1.Top += getSpeedFromDistance(deltaY);
System.Threading.Thread.Sleep(11);
}
int getSpeedFromDistance(int delta)
{
int sig = Math.Sign(delta);
int d = Math.Abs(delta);
if (d > near / 2) return sig;
else if (d > near / 3) return near / 10 * sig;
else if (d > near / 4) return near / 8 * sig;
else if (d > near / 5) return near / 5 * sig;
else return near * sig;
}
}
}
basically i am trying achieve something like suppose i have flow layout panel and which has many picture box inside it with many images as the screen shot but scroll bar should not show rather scroll will happen automatically when i will place my mouse at the top or bottom of the flow layout panel like carousel.
see this picture of your application
when place my mouse at the right end then it scroll and form background shown which i do not want. i want picture box will scroll & scroll upto last one not more than that.
any idea how to do it. thanks
2nd Edit
this code i added as per your suggestion
public Form1()
{
InitializeComponent();
for (int i = 0; i < 666; i++)
{
PictureBox pan = new PictureBox();
//pan.MouseMove += MouseScroll;
//pan.MouseLeave += outSideCheck;
pan.Size = new Size(75, 75);
pan.BackColor = Color.FromArgb(255, (i * 2) & 255, (i * 7) & 255, (i * 4) & 255);
flowLayoutPanel1.Controls.Add(pan);
}
//flowLayoutPanel1.MouseMove += MouseScroll;
//this.flowLayoutPanel1.MouseLeave += outSideCheck;
mouseScroller MSC = new mouseScroller();
MSC.registerControl(flowLayoutPanel1); // FLP = your FlowLayouPanel
MSC.timerSpeed = 5; // optional
MSC.nearness = 100; // optional
flowLayoutPanel1.AutoScroll = false;
}
now the apps doing wired behavior after adding new code. if i am making any mistake then guide me please. thanks
This is a two-part problem:
How to grab the event
How to scroll a FlowLayoutPanel with its scrollbars invisible.
Second first. It is not an easy task from what I found, unless you use a simple and rather common trick: Don't actually scroll it! Instead place it into a Panel and then control its position inside that Panel.
To do this you add a Panel panel1 to your Form, Dock or Anchor it as you need to and set its Autoscroll = false (!) (Which is not the way it is usually done, when you want to make, say a PictureBox scrollable. But we don't want the Panel to show it Scrollbars either.)
Set the FLP to its desired size and place it into the Panel, it obviously also has Autoscroll = false, and we're ready to tackle the other problem of setting up the event..:
First you add the MouseScroll event below to your code and then you hook every control up to it you want to work with the mouse move, namely the FLP:
flowLayoutPanel1.MouseMove += MouseScroll;
..and also each of your PictureBoxes, maybe like this
// your creation loop..
PictureBox pbox = new PictureBox();
pbox.MouseMove += MouseScroll; // <<--- hook into to the mousemove
pan.MouseLeave += outSideCheck; // <<--- hook into to the mouseleave
// .. do your stuff.. here I put some paint on to test..
pbox.BackColor = Color.FromArgb(255, 111, (i * 3) & 255, (i * 4) & 255);
flowLayoutPanel1.Controls.Add(pbox);
or however you create them..
Edit 2 I have changed my original code once more. It now includes an outside check, a check for moving towards the closest edge and a workaround for tha mousemove bug. It uses a Timer set to maybe 30ms. The speed mapping is in a function of its own.
flowLayoutPanel1.MouseMove += MouseScroll;
this.flowLayoutPanel1.MouseLeave += outSideCheck;
flowLayoutPanel1.AutoScroll = false;
int near = 33;
Point lastLocation = Point.Empty;
int dX = 0;
int dY = 0;
private void MouseScroll(object sender, MouseEventArgs e)
{
Point mouse = panel1.PointToClient(MousePosition);
Rectangle C = panel1.ClientRectangle;
// mouseMove has a bug, we need to workaround
if (mouse == lastLocation) return;
if (lastLocation == Point.Empty) { lastLocation = mouse; return; }
// distance from each edge
int dLeft = mouse.X - C.Left;
int dTop = mouse.Y - C.Top;
int dRight = C.Right - mouse.X;
int dBottom = C.Bottom - mouse.Y;
// relevant distances with sign
dX = dLeft < near ? dLeft : dRight < near ? -dRight : 0;
dY = dTop < near ? dTop : dBottom < near ? -dBottom : 0;
// we need the closest edge to check if we are moving in or out
List<int> edges = new List<int>() { dLeft, dTop, dRight, dBottom };
var closest = edges.IndexOf(edges.Min());
// if we are moving
if (dX != 0 | dY != 0)
// if moving out: go else stop going
if (!movingIn(mouse, closest)) timer1.Start(); else timer1.Stop();
// remember position
lastLocation = mouse;
}
bool movingIn(Point current, int Edge)
{
switch (Edge)
{
case 0: return current.X > lastLocation.X;
case 1: return current.Y > lastLocation.Y;
case 2: return current.X < lastLocation.X;
case 3: return current.Y < lastLocation.Y;
}
return false;
}
void scrollFLP(int deltaX, int deltaY)
{
flowLayoutPanel1.Left += getSpeedFromDistance(deltaX);
flowLayoutPanel1.Top += getSpeedFromDistance(deltaY);
Size C = panel1.ClientSize;
if (flowLayoutPanel1.Left > 1) { flowLayoutPanel1.Left = 0; timer1.Stop(); }
if (flowLayoutPanel1.Right < C.Width)
{ flowLayoutPanel1.Left = C.Width - flowLayoutPanel1.Width; timer1.Stop(); }
if (flowLayoutPanel1.Top > 1) { flowLayoutPanel1.Top = 0; timer1.Stop(); }
if (flowLayoutPanel1.Bottom < C.Height)
{ flowLayoutPanel1.Top = C.Height - flowLayoutPanel1.Height; timer1.Stop(); }
}
int getSpeedFromDistance(int delta)
{
int sig = Math.Sign(delta);
int d = Math.Abs(delta);
if (d > near / 2) return sig;
else if (d > near / 3) return 2 * sig;
else if (d > near / 4) return 4 * sig;
else if (d > near / 5) return 6 * sig;
else return 10 * sig;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (insidePanel()) scrollFLP(dX, dY); else timer1.Stop();
}
bool insidePanel()
{
return panel1.ClientRectangle.Contains(panel1.PointToClient(MousePosition));
}
private void outSideCheck(object sender, EventArgs e)
{
if (!insidePanel()) {timer1.Stop(); lastLocation = Point.Empty;}
}
Of course you'll want to play with the various 'magic' numbers :-)
Stop code and direction check are now included.
As usual, key is to know precisely what you want.. I hope this gets you started on ways to achieve it!
It's been a while since this question was asked. I just encountered the problem. My scenario was a little different, but I still think it's a solution to the same problem (at worst a timer control can be used because autoscroll is not turned on).
Here is my scenario: I have one panel control (normal panel). I have an PictureBox in it that I made with zoom. I'm making rectangular selections on top of this image, and when the selections spilled out of the panel, my panel was supposed to slide in the direction I was selecting. (in my scenario, mouse is pressed)(also in my scenario, autoscroll is on). This is how I solved it without writing so much code:
I added two private variable for scroll position (Valid for the whole class scope).
private int xPos;
private int yPos;
private int speed = 5;
and I assigned them the current scroll positions when the form is loaded.
private void Form1_Load(object sender, EventArgs e)
{
//when I change the scrollbar manually or change with zoom I still
//need to add these lines to the related event
xPos = panel1.HorizontalScroll.Value;
yPos = panel1.VerticalScroll.Value;
}
and inside my picturebox's mousemove event
private void picturebox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) {
Point mouse = panel1.PointToClient(MousePosition);
if (!panel1.ClientRectangle.Contains( mouse ))
{
Rectangle CRect = panel1.ClientRectangle;
int dLeft = mouse.X - CRect.Left;
int dRight = CRect.Right - mouse.X;
int dTop = mouse.Y - CRect.Top;
int dBottom = CRect.Bottom - mouse.Y;
if(dLeft < 0 && panel1.HorizontalScroll.Value > 0)
{
xPos = -panel1.AutoScrollPosition.X - speed;
}
if (dRight < 0 && panel1.HorizontalScroll.Value < panel1.HorizontalScroll.Maximum)
{
xPos = -panel1.AutoScrollPosition.X + speed;
}
if (dTop < 0 && panel1.VerticalScroll.Value > 0)
{
yPos = -panel1.AutoScrollPosition.Y - speed;
}
if (dBottom < 0 && panel1.VerticalScroll.Value < panel1.VerticalScroll.Maximum)
{
yPos = -panel1.AutoScrollPosition.Y + speed;
}
panel1.AutoScrollPosition = new Point(xPos, yPos);
}
}
}
I developing an application in which I need to integrate scaling of the UI.Althrough it's something trivial to do, I experience some problems. My UI isn't particulary clean and well formated to begin with(the XAML).
I have a Grid which looks like this and acts as a wrapper for all other controls.
It has the same height and width as the height & width of the window
<Grid x:Name="parentBox" Margin="10,10,2,0" Height="511" VerticalAlignment="Top">
Then I got a lot of other nested Grid's inside this grid and some other controls.The number of all controls is ~200.
Then I register the SizeChanged event for the "parentBox" named control which I noted above, and I have the following recursive algorithm to scale the controls.
Registered Event -----
private void ParentSizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
if (e.PreviousSize.Width != 0 && e.PreviousSize.Height != 0)
{
double coefficientHeight = e.NewSize.Height / e.PreviousSize.Height;
double coefficientWidth = e.NewSize.Width / e.PreviousSize.Width;
Scale(Parent, coefficientWidth, coefficientHeight);
}
}
Function to scale all children.
private void Scale(Grid Parent, double coefficientW, double coefficientH)
{
if (Parent.Children.Count == 0)
{
return;
}
else
{
if (coefficientH > 0 && coefficientW > 0)
{
Parent.Width *= coefficientW;
Parent.Height *= coefficientH;
for (int y = 0; y < Parent.Children.Count; y++)
{
var child = Parent.Children[y];
if (child is Grid)
{
var childG = child as Grid;
Scale(childG, coefficientW, coefficientH);
}
else
{
if (child is ElementRepresentation)
{
var element = child as ElementRepresentation;
element.Width *= coefficientW;
element.Height *= coefficientH;
if (element.Height < 25 || element.Width < 25)
{
if (!ElementNames.ContainsKey(int.Parse(element.elementNumber.Text)))
{
ElementNames.Add(int.Parse(element.elementNumber.Text), element.ElementLongName.Text);
element.ElementLongName.Text = String.Empty;
}
}
if (element.ElementLongName.Text == String.Empty)
{
element.ElementLongName.Text = ElementNames[int.Parse(element.elementNumber.Text)];
}
}
else
{
if(child is Label)
{
var label = child as Label;
label.Width *= coefficientW;
label.Height *= coefficientH;
}
}
}
}
}
}
}
While I debug and I scale the height of the Window the "parentBox" control the SizeChanged event fires only when I scale the window from the width side and nothing occurs when I try to do change the height.I'm suspecting it's something to do with my control placements which are inside the nested inside "parentBox" grids.
I appreciate your time to read this question.Thanks.
You have defined the fixed size for Grid(Height="511").
Size changed event won't be called when you set the fixed size. You didn't change the width. That's why event is triggered when you change the width.
You need to remove the Height. By default height and width will be applied from the parent.
Regards,
Dhanasekar
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.
void Rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
//(0/-897)(0/-135)
// Move the rectangle.
Thickness mapmar = MapCont.Margin;
Current.Text = mapmar.Left+"_"+mapmar.Top;
if (marginThickness.Left < 0)
{
MapCont.Margin = new Thickness(0,0,0,0);
}
move.X += e.DeltaManipulation.Translation.X;
move.Y += e.DeltaManipulation.Translation.Y;
}
The idea is that the Canvas is Really big for the view so i use the DeltaMaipulation to allow the user to scroll around it, i need to keep track of the margins to force some clipping
i tried printing the values of the margins (textfield) it's 0 0 no matter what
thanks for your help
The ManipulationDelta Doesn't use the Margin property to position the elements
alternative code:-
use the TranslateTransform Object
private TranslateTransform move = new TranslateTransform();
use the X and Y attributes to do the clipping or any related thing
if (move.X < 0)
{
move.X = 0;
}