wpf: scroll canvas to objects beyon top or left side.

M

moondaddy

I have a wpf project where I use a canvas to drag shapes around. when I
drag a shape beyond the right or bottom side I get scrollbars which is good.
I also get scrollbars when I zoom in and a shape goes beyond the right or
bottom side. However, I don't get scrollbars when shapes move beyond the
left or top side of the canvas. This is bad. I need the behavior similar
to Visio where you can drag an object past the left or top and you will get
scrollbars to scroll that area back into view.

I have a grid which has a scrollviewer and the canvas is the content of the
scrollviewer. In my custom canvas control at the end of the mouse move
event I call this line:

this.InvalidateMeasure();

Which causes the next method to run. All it does is re-measures the canvas
area which determines if the right or bottom are out of view. What can I do
here to determine if the top or left are out of view?

protected override Size MeasureOverride(Size constraint)
{
Size size = new Size();
foreach (UIElement element in base.Children)
{
double left = Canvas.GetLeft(element);
double top = Canvas.GetTop(element);
left = double.IsNaN(left) ? 0 : left;
top = double.IsNaN(top) ? 0 : top;

//measure desired size for each child
element.Measure(constraint);

Size desiredSize = element.DesiredSize;
if (!double.IsNaN(desiredSize.Width) &&
!double.IsNaN(desiredSize.Height))
{
size.Width = Math.Max(size.Width, left + desiredSize.Width);
size.Height = Math.Max(size.Height, top + desiredSize.Height);
}
}
// add margin
size.Width += 10;
size.Height += 10;
return size;
}


Note, most of what I do is in c# rather than xaml.

Thanks.
 
L

Linda Liu[MSFT]

Hi George,

Could you please reproduce the problem in a simple application and send it
to me?I think it would be a quick way that helps to address the problem.

To get my actual email address, remove 'online' from my displayed email
address.

Thank you for your understanding and cooperation. I look forward to your
reply!

Sincerely,
Linda Liu
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
L

Linda Liu[MSFT]

Hi George,

Thank you for your sample project! I understand what you're trying to
achieve now.

The reason why the scrollbars of the ScrollViewer don't appear when the
Rectangle is moved beyond the left or the top side of the Canvas is that
the Canvas's size isn't changed bigger than the viewport size of the
ScrollViewer at all.

The following steps can lead you to what you want:
1. Among all child elements in the Canvas, find the minimum left and top
values of the child elements.
2. If the minimun left or top value is less than zero, adjust positions of
all child elements according to the minimum left or top values.
3. Calculate the desired size of the Canvas based on all elements in it.
4. Scroll the parent ScrollViewer the absolute value of the minimum left
and top value horizontally and vertically, if any.

I have made some modifications in the override MeasueOverride method of the
DiagramCanvas class and it works well on my side. I will send the modified
sample project to your email box.

If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

This posting is provided "AS IS" with no warranties, and confers no rights.
 
L

Linda Liu[MSFT]

Hi George,

Thank you for your feedback!

Although you place a Thumb in the Canvas in the project, the main idea to
get the scrollbars to appear in the ScrollViewer remains the same. I modify
my code for the override MeasureOverride method as follow and it works fine
on my side:

protected override Size MeasureOverride(Size constraint)
{
Size size = new Size();
// restore the left and top values of all Buttons to their
original values
foreach (UIElement element in base.Children)
{
if (!(element is Thumb))
{
if (horizontaloffset < 0.0)
{
Canvas.SetLeft(element, Canvas.GetLeft(element) +
horizontaloffset);
}
if (verticaloffset < 0.0)
{
Canvas.SetTop(element, Canvas.GetTop(element) +
verticaloffset);
}
}
}
// get the parent ScrollViewer, if any
ScrollViewer sv = null;
if (this.Parent != null && (this.Parent is ScrollViewer))
{
sv = this.Parent as ScrollViewer;
}

double minleft = 0.0, mintop = 0.0, minwidth = 0.0, minheight =
0.0;
if (sv != null)
{
// find the minimun left and top values of all child
elements
foreach (UIElement element in base.Children)
{
minleft = Math.Min(minleft, Canvas.GetLeft(element));
mintop = Math.Min(mintop, Canvas.GetTop(element));
}
// store minimum left and top values to the global variables
horizontaloffset = minleft;
verticaloffset = mintop;
// if the minimum left value is less than zero, we can
determine the minimum width of the Canvas
if (minleft < 0.0)
{
minwidth = sv.ViewportWidth + Math.Abs(minleft);
}
// if the minimum top value is less than zero, we can
dertermine the minimum height of the Canvas
if (mintop < 0.0)
{
minheight = sv.ViewportHeight + Math.Abs(mintop);
}
}
// set initial values to Width and Height of the size variable
size.Width = minwidth;
size.Height = minheight;
foreach (UIElement element in base.Children)
{
// if minimum left value is less than zero, adjust each
element's left value
if (minleft < 0.0)
{
Canvas.SetLeft(element, Canvas.GetLeft(element) +
Math.Abs(minleft) );
}
// if minimum top value is less than zero, adjust each
element's top value
if (mintop < 0.0)
{
Canvas.SetTop(element, Canvas.GetTop(element) +
Math.Abs(mintop) );
}

double left = Canvas.GetLeft(element);
double top = Canvas.GetTop(element);
left = double.IsNaN(left) ? 0 : left;
top = double.IsNaN(top) ? 0 : top;

//measure desired size for each child
element.Measure(constraint);

Size desiredSize = element.DesiredSize;
// calculate the desired size of the Canvas
if (!double.IsNaN(desiredSize.Width) &&
!double.IsNaN(desiredSize.Height))
{
size.Width = Math.Max(size.Width, left +
desiredSize.Width);
size.Height = Math.Max(size.Height, top +
desiredSize.Height);
}
}

// add margin
size.Width += 300;
size.Height += 300;

// scroll parent if any
if (sv != null)
{
sv.ScrollToHorizontalOffset(Math.Abs(minleft) );
sv.ScrollToVerticalOffset(Math.Abs(mintop));
}
return size;
}

I will send the modified sample project to your email box. If you have any
question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

This posting is provided "AS IS" with no warranties, and confers no rights.
 
L

Linda Liu[MSFT]

Hi George,

Thank you for your feedback! I'm glad to hear that the problem is solved
now.

If you have any other questions in the future, please don't hesitate to
contact us. It's always our pleasure to be of assistance!

Have a nice day!

Sincerely,
Linda Liu
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Top