РЕДАКТИРОВАТЬ 1 19/12
После небольшого количества гугл-фу я чувствую себя лучше, чтобы объяснить более кратко мою проблему.Я хотел реализовать «масштабирование по размеру», когда холст, который больше, чем его родитель, отображается с подходящим масштабным коэффициентом, но предлагает пользователю возможность увеличить масштаб и увидеть изображение в полном размере (с помощью средства просмотра с прокруткой).Моя первоначальная реализация не поддерживала пропорции изображения, вместо этого она работала независимо друг от друга, а затем попыталась использовать один ползунок для управления обоими.
Я наткнулся на в этом уроке , чтобы сделатьпрокручиваемый и масштабируемый просмотрщик изображений, который предлагает "масштабирование, чтобы соответствовать".После этого я изменил свой код на следующий:
if (CanvasWidth > CanvasHeight)
{
ScaleX = (Math.Floor(_scrollViewer.ViewportWidth + 0.5)) / ((double)CanvasWidth);
ScaleY = ScaleX;
if (_scrollViewer.Height < (CanvasHeight * ScaleY) )
{
ScaleX = ( _scrollViewer.Height) / (CanvasHeight);
ScaleY = ScaleX;
}
}
else
{
ScaleX = (Math.Floor(_scrollViewer.ViewportHeight + 0.5)) / ((double)CanvasHeight);
ScaleY = ScaleX;
if (_scrollViewer.Width < ( CanvasWidth * ScaleX) )
{
ScaleX = ((double)_scrollViewer.Width) / ((double)CanvasWidth);
ScaleY = ScaleX;
}
}
Это изменение, кажется, работает отлично, но мне было интересно, если бы кто-нибудь мог объяснить мне, как вычисление соотношения сторон , как это работает иправильно масштабирует изображение для родительского элемента управления?
то есть, что является значимым «внутреннего оператора if» и как это обеспечивает соответственно масштабирование X и Y.
Исходный вопрос
Я динамически генерирую контент на холсте (эффективно создавая карту изображения, где каждый дочерний элемент на холсте кликабелен), где общая ширина/ высота содержимого часто больше, чем размер его родителя.В этих ситуациях я применяю ScalerTransform , чтобы масштабировать изображение до подходящего размера, чтобы оно было полностью видимым в родительском элементе управления.
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ScaleX,RelativeSource={RelativeSource
TemplatedParent}}" ScaleY="{Binding ScaleY,RelativeSource={RelativeSource
TemplatedParent}}" />
</Canvas.LayoutTransform>
Каждый дочерний элемент в Canvas имеет константуширина / высота, что означает, что я могу вычислить желаемый размер содержимого.
Я рассчитываю начальный масштабный коэффициент X / Y, выполняя что-то вроде этого.
ScaleX = ActualCanvasWidth / DesiredCanvasWidth;
ScaleY = ActualCanvasHeight / DesiredCanvasHeight;
Это работает, как ожидалось, иВ результате холст хорошо вписывается в родительский контейнер.
Моя проблема в том, что я хочу дать пользователю возможность масштабировать и перемещаться по изображению.Чтобы достичь этого, я обернул Canvas внутри ScrollViewer и добавил Slider.
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto" x:Name="PART_ScrollViewer" VerticalScrollBarVisibility="Auto">
<Canvas x:Name="PART_MiniMapCanvas">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ScaleX,RelativeSource={RelativeSource TemplatedParent}}"
ScaleY="{Binding ScaleY,RelativeSource={RelativeSource TemplatedParent}}" />
</Canvas.LayoutTransform>
</Canvas></ScrollViewer>
<Slider TickFrequency="1" IsSnapToTickEnabled="True" Grid.Row="0" Grid.Column="0" Minimum="1" Maximum="200" Value="{Binding ScaledPercent,RelativeSource={RelativeSource TemplatedParent}}" x:Name="sliderPercent" MinWidth="100px" />
Пользовательский интерфейс использует один ползунок для управления масштабированием, и его значение привязано к свойству ScaledPercent.Начальное значение ползунка рассчитывается следующим образом:
double scaledArea = (DesiredCanvasWidth * ScaleX) * (DesiredCanvasHeight* ScaleY);
double desiredArea = DesiredCanvasWidth * DesiredCanvasHeight;
double scaledPercent = scaledArea/desiredArea;
Насколько я понимаю, я могу выполнить этот расчет, чтобы найти процент увеличения / масштаба всего холста, а не только коэффициент масштабирования X холста./Y.
Как вы можете см. Здесь , холст и его родительский объект имеют высоту примерно 160 * 200 с желаемым размером содержимого примерно 300 * 320, что соответствует 48000/96000.вот где я получил 50%, используемый ползунком.
Если пользователь решит увеличить масштаб и изменит значение ползунка на 51, я преобразую это новое значение «масштабированный процент» в подходящий ScaleX / Yзначение для холста.Это выполняется в обратном вызове свойства зависимостей
private static void OnScaledPercentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is MiniMap map)
{
int newPercent = (int)e.NewValue;
int oldPercent = (int)e.OldValue;
int diff = newPercent - oldPercent;
double oldWidth = map.CanvasWidth * map.ScaleX;
double oldHeight = map.CanvasHeight * map.ScaleY;
double scale = (diff > 0 ? (100 + diff) : (100 - Math.Abs(diff))) / 100d;
double newHeight = scale * oldHeight;
double newWidth = scale * oldWidth;
map.ScaleX = newWidth / map.CanvasWidth;
map.ScaleY = newHeight / map.CanvasHeight;
}
}
Как вы можете видеть, я эффективно масштабирую ширину / высоту старого изображения на +/- 1%, а затем вычисляю новые значения масштаба X / Y.Похоже, это работает, как вы можете см. Здесь , но если вы постоянно увеличиваете / уменьшаете масштаб, холст становится настолько маленьким, что не отображается.Я предполагаю, что это потому, что я вычисляю новую ширину / высоту каждый раз, и она в конечном итоге будет округляться до 0.
Очевидно, что моя реализация слишком сложна, содержит ошибки и ошибочна.Буду признателен, если кто-нибудь сможет мне помочь или посоветовать, как мне поступить с реализацией требуемой функциональности.