Ограничьте количество панорамирования, чтобы изображение не выходило за пределы окна.
ВСТУПЛЕНИЕ:
Я экспортировал SVG
как XAML
и превратился в холст с огромным количеством дорожек.
После создания этого основного содержимого Canvas в простом автоматически сгенерированном окне изображение было обрезано, поскольку оно было больше, чем клиентский прямоугольник главного окна.
Я решил эту проблему с помощью панорамирования.
Так как я планирую возиться с масштабированием позже, я добавил манекен ScaleTransform
в XAML
холста и изменили его RenderTransformOrigin на 0.5 , 0.5
(так что я могу увеличить изображение вокруг его центра).
Я хотел, чтобы изображение было центрировано при загрузке окна, поэтому я поместил этот Canvas внутри Viewbox, который, кажется, работает нормально, после настройки нескольких свойств.
ПРОБЛЕМА:
Поскольку я изменил RenderTransformOrigin для Canvas, я не могу понять математику, которая позволит мне ограничить количество панорамирования.
Несмотря на то, что Viewbox является содержимым главного окна, я не могу получить размеры клиентской области главного окна (Viewbox изменяет размеры в соответствии с его содержимым). Это делает мою задачу еще более сложной.
МОИ УСИЛИЯ ДЛЯ РЕШЕНИЯ ЭТОГО:
Кажется, нет другого способа получить прямоугольник клиента главного окна, кроме как с использованием P/Invoke
а также GetClientRect
WinAPI звонок.
Был еще один хак с запросом SystemParametersInfo для не-клиентских метрик, таких как границы и заголовок, но это оценка, которая может потерпеть неудачу из-за примененных тем и подобных.
Я не пытался использовать P/Invoke
потому что я просто отказываюсь сделать это в данный момент. Должно быть лучшее решение, чем это! Этот путь должен быть моим последним выбором, и тот, который я выберу из чистого отчаяния.
Я пытался найти альтернативный подход самостоятельно, но безуспешно.
Я пытался использовать TransformToAncestor(...).Transformtobounds(..)
для моих расчетов, но это тоже не удалось.
ВОПРОС:
Как ограничить панорамирование, чтобы изображение не исчезало из главного окна, когда пользователь перетаскивает слишком много?
Я приму альтернативные решения. Код, который был представлен, был попыткой неопытного начинающего, самоучки, поэтому я принимаю конструктивную критику и советы.
РЕЛЕВАНТНАЯ ИНФОРМАЦИЯ:
Чтобы этот пост был как можно более коротким, я даю ниже только соответствующие фрагменты XAML и "код позади".
Полный код наклеен на Pastebin, и его можно найти в самом низу этого поста.
Соответствующие фрагменты XAML:
<Window x:Class="TestZaMapu.MainWindow"
Name="GlavniProzor"
WindowStartupLocation="CenterScreen"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350"
Width="525"
MouseLeftButtonDown="GlavniProzor_MouseLeftButtonDown"
MouseLeftButtonUp="GlavniProzor_MouseLeftButtonUp"
MouseMove="GlavniProzor_MouseMove"
LostMouseCapture="GlavniProzor_LostMouseCapture">
<Viewbox
Name="surface"
Stretch="UniformToFill"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Background="Blue"
x:Name="svg4306"
Width="494.44705"
Height="510.55356"
<!-- needed in the future, for zooming around center-->
RenderTransformOrigin="0.5, 0.5">
<!--Unknown tag: metadata-->
<Canvas.RenderTransform>
<TransformGroup>
<!-- I intend to experiment with scaling in the future, so I added the below part -->
<ScaleTransform ScaleX="1" ScaleY="1"/>
<!-- I have used dependency properties for translation -->
<TranslateTransform X="{Binding TranslationFactorX, ElementName=GlavniProzor, Mode=TwoWay}" Y="{Binding TranslationFactorY, ElementName=GlavniProzor, Mode=TwoWay}"/>
</TransformGroup>
</Canvas.RenderTransform>
<!-- Bunch of Path objects, omitted for brevity-->
</Canvas>
</Viewbox>
</Window>
Соответствующий код за фрагментами:
namespace TestZaMapu
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TranslationFactorX = 0;
TranslationFactorY = 0;
isPanning = false;
}
// panning variables
private Point ptOldPosition;
private bool isPanning ;
// dependency properties for translation along X and Y axes
public static readonly DependencyProperty TranslateX =
DependencyProperty.Register("TranslationFactorX", typeof(double), typeof(MainWindow));
public static readonly DependencyProperty TranslateY =
DependencyProperty.Register("TranslationFactorY", typeof(double), typeof(MainWindow));
public double TranslationFactorX
{
get { return (double)GetValue(TranslateX); }
set { SetValue(TranslateX, value); }
}
public double TranslationFactorY
{
get { return (double)GetValue(TranslateY); }
set { SetValue(TranslateY, value); }
}
// mouse event handlers for panning
private void GlavniProzor_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (isPanning )
return;
isPanning = this.CaptureMouse();
ptOldPosition = e.GetPosition(this);
}
private void GlavniProzor_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (this.IsMouseCaptured)
{
this.ReleaseMouseCapture();
isPanning = false;
}
}
private void GlavniProzor_MouseMove(object sender, MouseEventArgs e)
{
base.OnMouseMove(e);
if (isPanning )
{
Point ptNewPosition = e.GetPosition(this);
if (ptNewPosition != ptOldPosition)
{
Vector direction = ptOldPosition - ptNewPosition;
direction.X = TranslationFactorX - direction.X;
direction.Y = TranslationFactorY - direction.Y;
TranslationFactorX = direction.X;
TranslationFactorY = direction.Y;
ptOldPosition = ptNewPosition;
}
}
}
private void GlavniProzor_LostMouseCapture(object sender, MouseEventArgs e)
{
isPanning = false;
this.OnLostMouseCapture(e);
}
}
}
2 ответа
Это звучит преступно просто, но если ваша цель состоит в том, чтобы не дать вашему вектору срезаться за пределами назначенного ему пространства, почему бы вам просто не изменить Stretch="UniformToFill"
вашего Viewbox для Stretch="Uniform"
?
Я действительно не читал полный вопрос (я думаю, что никто не будет), но вот код, который я использую в библиотеке графиков для ограничения панорамирования. Это математика. Теперь добавьте это к вашему делу. Совет: в следующий раз введите только соответствующий код, чтобы мы могли дать лучший ответ.
Я вызываю этот метод, когда панорамирование заканчивается (в моем случае событие "вверх")
Если это помогает, то это библиотека ( https://github.com/beto-rodriguez/Live-Charts), может быть, вы тоже можете помочь вам увидеть исходный код. Расслабьтесь, я думаю, вы делаете это намного сложнее, чем то, что есть.
private void PreventGraphToBeVisible()
{
var tt = Canvas.RenderTransform as TranslateTransform;
if (tt == null) return;
var eX = tt.X;
var eY = tt.Y;
var xOverflow = -tt.X + ActualWidth - Canvas.Width;
var yOverflow = -tt.Y + ActualHeight - Canvas.Height;
if (eX > 0)
{
tt.X = 0;
}
if (eY > 0)
{
tt.Y = 0;
}
if (xOverflow > 0)
{
tt.X = tt.X + xOverflow;
}
if (yOverflow > 0)
{
tt.Y = tt.Y + yOverflow;
}
}