Получение Viewbox и ScrollViewer для совместной работы
Ive получил n играющую карту, где я использую ScrollViewer
для перемещения по карте, и я хочу использовать ViewBox
вместе с PinchManipulations
для увеличения и уменьшения масштаба карты. До сих пор Ive делал это, устанавливая режим ScrollViewer
s Manipulation
на control
, однако это дает мне задержку при масштабировании. Есть ли способ заставить ViewBox
и ScrollViewer
работать лучше вместе и тем самым избежать отставания? Код Ive до сих пор:
ScrollViewer:
<ScrollViewer Grid.Column ="0" Width="768" Height="380" HorizontalScrollBarVisibility="Hidden">
<Viewbox Stretch="None">
<View:Map/>
</Viewbox>
</ScrollViewer>
PinchZoom:
<Grid x:Name="Map" Width="1271" Height="1381.5">
<Grid.RenderTransform>
<ScaleTransform ScaleX="{Binding Path=deltaZoom}" ScaleY="{Binding Path=deltaZoom}"/>
</Grid.RenderTransform>
<i:Interaction.Triggers>
<i:EventTrigger EventName="ManipulationStarted">
<cmd:EventToCommand Command="{Binding Path=ZoomStartedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="ManipulationDelta">
<cmd:EventToCommand Command="{Binding Path=ZoomDeltaCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="ManipulationCompleted">
<cmd:EventToCommand Command="{Binding Path=ZoomCompletedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
Код, в котором я использую масштабирование зума:
public ICommand ZoomStartedCommand { get; set; }
public ICommand ZoomDeltaCommand { get; set; }
public ICommand ZoomCompletedCommand { get; set; }
private double _deltaZoom;
public double deltaZoom
{
get
{
return _deltaZoom;
}
set
{
_deltaZoom = value;
RaisePropertyChanged("deltaZoom");
}
}
public double distance;
public MainViewModel()
{
ZoomStartedCommand = new RelayCommand<ManipulationStartedEventArgs>(ZoomStart);
ZoomDeltaCommand = new RelayCommand<ManipulationDeltaEventArgs>(ZoomDelta);
ZoomCompletedCommand = new RelayCommand<ManipulationCompletedEventArgs>(ZoomCompleted);
}
public void ZoomStart(ManipulationStartedEventArgs e)
{
FrameworkElement Element = (FrameworkElement)e.OriginalSource;
var myScrollViewer = FindParentOfType<ScrollViewer>(Element) as ScrollViewer;
myScrollViewer.SetValue(ScrollViewer.ManipulationModeProperty, ManipulationMode.Control);
}
public void ZoomDelta(ManipulationDeltaEventArgs e)
{
if (e.PinchManipulation != null)
{
deltaZoom = deltaZoom * e.PinchManipulation.DeltaScale;
}
else
{
FrameworkElement Element = (FrameworkElement)e.OriginalSource;
var myScrollViewer = FindParentOfType<ScrollViewer>(Element) as ScrollViewer;
myScrollViewer.SetValue(ScrollViewer.ManipulationModeProperty, ManipulationMode.System);
}
}
public void ZoomCompleted(ManipulationCompletedEventArgs e)
{
FrameworkElement Element = (FrameworkElement)e.OriginalSource;
var myScrollViewer = FindParentOfType<ScrollViewer>(Element) as ScrollViewer;
myScrollViewer.SetValue(ScrollViewer.ManipulationModeProperty, ManipulationMode.System);
}
Ответы
Ответ 1
Я думаю, вам стоит вместо этого взглянуть на диспетчер viewport и посмотреть на образец основной линзы, где они это реализовали. Viewportcontroller, имеет scrollviewer внутри и viewport.
Основы таковы:
- Пока изображение у вас "unzoomed", scrollviewer имеет полный контроль, а ViewportControl ничего не делает.
- Когда вы начинаете зажимать, заблокируйте scrollviewer, отключив вертикальную панель прокрутки и установив viewport.height = scrollviewer.height. Это нейтрализует scollviewer.
- Вы можете сделать временное масштабирование с помощью Image ScaleTransform.
- На финише, измените размер вашего фактического изображения так, чтобы оно занимало реальное пространство внутри ViewportControl. Теперь ваш viewportControl позволит вам панорамировать весь снимок с хорошим возвратом.
- При повторном масштабировании снова включите scrollviewer. (Установите высоту на высоту экрана и включите полосу прокрутки.)
FYI, я полностью забываю, почему там есть холст, но я чувствую, что это важно. См. Ниже:
Пока приведенный ниже пример не делает то, что вы хотите сделать, я основал свой код в MediaViewer внутри этого примера и изменил его:
Основной образец объектива
Однако следует отметить, что он предназначен для масштабирования изображения.
Ответ 2
У меня тоже была эта проблема, когда я пытался обрабатывать множество данных в одном контейнере.
Вы не можете просто загрузить всю карту в окне просмотра и использовать средство просмотра прокрутки и ожидать, что все будет работать нормально.
Первое решение сделать приложение хорошо работать на больших наборах данных - попробовать Виртуализация пользовательского интерфейса. Элемент управления, который принимает виртуализацию, создает только элементы, необходимые для отображения текущего представления или, точнее, только элементов, которые видны на дисплее. Чтобы лучше понять эту концепцию, я приведу вам пример реального мира. Посмотрите, как Facebook передает свою ленту новостей. Он загружает X-сообщения в элементы X html, а затем, когда пользователи прокручиваются вниз, он выгружает невидимые и загружает новые.
Виртуализация 1.UI
Он просто повторно использует элементы. Это концепция виртуализации пользовательского интерфейса. Я должен упомянуть одну важную функцию: отложенную прокрутку (пользователь может прокручивать, но результаты отображаются только после выпуска клика, это улучшение производительности, если пользователю нравится играть вверх и вниз с помощью полосы прокрутки)
Возвращаясь к вашей проблеме. Если карта полностью загружена, это проблема производительности для прокрутки или масштабирования, потому что невидимые части будут масштабироваться и прокручиваться. Представьте, что произошло бы, если бы Google Maps не поддерживал виртуализацию пользовательского интерфейса. Когда пользователь попытается увеличить масштаб, вся Земля будет увеличивать (тонны ГБ).
2. Виртуализация данных
Однако ваша карта должна быть полностью загружена где-то в памяти. Если он большой, это проблема, и наступает Виртуализация данных.
Вместо того, чтобы полностью загрузить карту, она загружает только нужные разделы для отображения. Если вы хотите лучше реагировать, вы можете использовать концепцию, которую использует Google Maps. Загрузите в память несколько данных, чем при отображении на дисплее, поэтому пользовательский интерфейс не будет зависеть (пока данные не будут записаны в память) при прокрутке.
Вы можете прочитать больше:
Я решил свою проблему, используя Виртуализированный холст. Пример приложения с использованием виртуализованного холста: http://pavzav.blogspot.ro/2010/11/virtualized-canvas.html
Возможно, вам стоит взглянуть на Wpf Bing Maps Control