2014-10-01 3 views
1

Я пытаюсь увеличить некоторое содержимое в scrollviewer.WPF Zoom + Полоса прокрутки?

Поведение масштабирования, которое я искал, относится к RenderTransform + ScaleTransform. Но это не работает с ScrollViewer.

Использование LayoutTransform + ScaleTransform влияет на scrollviewer (только ContentTemplate1), но не ведет себя как масштабирование.

Предполагая, что ContentTemplate1/ContentTemplate2 не может быть изменен (т. Е. Сторонние элементы управления), как я могу получить масштабирование для работы с scrollviewer?

<Grid> 
    <Grid.Resources> 
     <!-- Content type 1 --> 
     <DataTemplate x:Key="ContentTemplate1"> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="150"/> 
        <ColumnDefinition /> 
       </Grid.ColumnDefinitions> 
       <TextBlock Background="DodgerBlue" Text="Left"/> 
       <TextBlock Grid.Column="1" Background="DarkGray" Text="Right"/> 
      </Grid> 
     </DataTemplate> 

     <!-- Content type 2 --> 
     <DataTemplate x:Key="ContentTemplate2"> 
      <Viewbox> 
       <TextBlock Background="DodgerBlue" Text="Scale to fit" Width="100" Height="70" Foreground="White" TextAlignment="Center"/> 
      </Viewbox> 
     </DataTemplate> 
    </Grid.Resources> 
    <Grid.RowDefinitions> 
     <RowDefinition /> 
     <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 

    <TabControl> 
     <!-- Content 1 --> 
     <TabControl.Resources> 
      <ScaleTransform x:Key="ScaleTransform" 
          ScaleX="{Binding ElementName=ZoomSlider,Path=Value}" 
          ScaleY="{Binding ElementName=ZoomSlider,Path=Value}" /> 
     </TabControl.Resources> 
     <TabItem Header="Content 1"> 
      <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> 
       <ContentControl ContentTemplate="{StaticResource ContentTemplate1}" Margin="10" RenderTransformOrigin=".5,.5"> 
        <!-- Affects scrollviewer, but does not behave like a zoom --> 
        <!--<FrameworkElement.LayoutTransform> 
         <StaticResource ResourceKey="ScaleTransform" /> 
        </FrameworkElement.LayoutTransform>--> 

        <!-- Expected zoom behavior, but doesn't affect scrollviewer --> 
        <FrameworkElement.RenderTransform> 
         <StaticResource ResourceKey="ScaleTransform" /> 
        </FrameworkElement.RenderTransform> 
       </ContentControl> 
      </ScrollViewer> 
     </TabItem> 
     <!-- Content 2 --> 
     <TabItem Header="Content 2"> 
      <ContentControl ContentTemplate="{StaticResource ContentTemplate2}" Margin="10" RenderTransformOrigin=".5,.5"> 
       <!-- Affects scrollviewer, but does not behave like a zoom --> 
       <!--<FrameworkElement.LayoutTransform> 
         <StaticResource ResourceKey="ScaleTransform" /> 
        </FrameworkElement.LayoutTransform>--> 

       <!-- Expected zoom behavior, but doesn't affect scrollviewer --> 
       <FrameworkElement.RenderTransform> 
        <StaticResource ResourceKey="ScaleTransform" /> 
       </FrameworkElement.RenderTransform> 
      </ContentControl> 

     </TabItem> 
    </TabControl> 

    <StackPanel Grid.Row="1" Orientation="Horizontal"> 
     <!-- Zoom --> 
     <Slider x:Name="ZoomSlider" 
       Width="100" 
       Maximum="5" 
       Minimum="0.1" 
       Orientation="Horizontal" 
       Value="1" /> 

     <!-- Autofit --> 
     <CheckBox Content="Autofit?" x:Name="AutoFitCheckBox" /> 
    </StackPanel> 
</Grid> 

ответ

0

Для сделайте увеличенные элементы получить точный вид RenderTransform, мы можем также придерживаться RenderTransform и вместо этого сообщать ScrollViewer, как вести себя, реализуя собственную логику прокрутки. Этот подход основан на этой превосходной учебник:

http://tech.pro/tutorial/907/wpf-tutorial-implementing-iscrollinfo

Мы создаем наш собственный обычай "ZoomableContentControl", который реализует IScrollInfo и сказать ScrollViewer получить свою логику прокрутки оттуда (ScrollViewer.CanContentScroll = True). Волшебство происходит в ArrangeOverride(), где мы играем с ExtentWidth/ExtentHeight и RenderTransformOrigin.

public class ZoomableContentControl : ContentControl, IScrollInfo 
{ 
    public ZoomableContentControl() 
    { 
     this.RenderTransformOrigin = new Point(0.5, 0.5); 
    } 

    private ScaleTransform _scale = null; 
    private ScaleTransform Scale 
    { 
     get 
     { 
      if (_scale == null) 
      { 
       _scale = this.RenderTransform as ScaleTransform; 

       //RenderTransforms don't update the layout, so we need to trigger that ourselves: 
       _scale.Changed += (s, e) => { InvalidateArrange(); }; 
      } 
      return _scale; 
     } 
    } 
    protected override Size ArrangeOverride(Size arrangeBounds) 
    { 
     Statics.MessageIfDebug("Arranging"); 
     var layout = base.ArrangeOverride(arrangeBounds); 

     var scale = this.Scale; 
     if (scale != null) 
     { 
      //Because RenderTransforms don't update the layout, 
      //we need to pretend we're bigger than we are to make room for our zoomed content: 
      _extent = new Size(layout.Width * scale.ScaleX, layout.Height * scale.ScaleY); 
      _viewport = layout; 

      //Coerce offsets.. 
      var maxOffset = new Vector(ExtentWidth - ViewportWidth, ExtentHeight - ViewportHeight); 
      _offset.X = Math.Max(0, Math.Min(_offset.X, maxOffset.X)); 
      _offset.Y = Math.Max(0, Math.Min(_offset.Y, maxOffset.Y)); 

      //..and move the zoomed content within the ScrollViewer: 
      var renderOffsetX = (maxOffset.X > 0) ? (_offset.X/maxOffset.X) : 0.5; 
      var renderOffsetY = (maxOffset.Y > 0) ? (_offset.Y/maxOffset.Y) : 0.5; 
      this.RenderTransformOrigin = new Point(renderOffsetX, renderOffsetY); 

      if (ScrollOwner != null) 
      { 
       ScrollOwner.InvalidateScrollInfo(); 
      } 
     } 

     return layout; 
    } 


    #region IScrollInfo 

    //This is the boilerplate IScrollInfo implementation, 
    //which can be found in *the first half* of this tutorial: 
    //http://tech.pro/tutorial/907/wpf-tutorial-implementing-iscrollinfo 
    //(down to and including SetHorizontalOffset()/SetVerticalOffset()). 
    //Note the bug reported by "Martin" in the comments. 

    ... 

Использование:

<TabItem Header="Content 1"> 
    <ScrollViewer CanContentScroll="True" 
        HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> 
      <v:ZoomableContentControl ContentTemplate="{StaticResource ContentTemplate1}" Margin="10" > 
      <FrameworkElement.RenderTransform> 
       <StaticResource ResourceKey="ScaleTransform" /> 
      </FrameworkElement.RenderTransform> 
     </v:ZoomableContentControl> 
    </ScrollViewer> 
</TabItem> 
<TabItem Header="Content 2"> 
    <ScrollViewer CanContentScroll="True" 
        HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> 
     <v:ZoomableContentControl ContentTemplate="{StaticResource ContentTemplate2}" Margin="10" > 
      <FrameworkElement.RenderTransform> 
       <StaticResource ResourceKey="ScaleTransform" /> 
      </FrameworkElement.RenderTransform> 
     </v:ZoomableContentControl> 
    </ScrollViewer> 
</TabItem> 
+0

Получил работу с образцом кода. Вел себя так, как хотел. А также отличный опыт в ручном внедрении IScrollInfo. – jayars

1

Если я правильно понимаю:

  • Вы хотите увеличить с ZoomSlider слайдера?
  • Вы хотите, чтобы полосы прокрутки отображались, если содержимое слишком велико, чтобы соответствовать его вкладке?

Если это так, то LayoutTransform вы хотите. Это преобразование выполняется до того, как все элементы будут измерены и выложены, а ScrollViewer сможет определить, нужны ли полосы прокрутки.

На моей машине «Содержимое 1» вкладка работает как ожидается, если вы просто переключиться на LayoutTransform (обратите внимание, что вы должны увеличить много, прежде чем «Right» исчезает за пределы экрана, выключая скроллбар):

Content 1, un-zoomed Content 1, zoomed

"Содержание 2" требует немного больше работы. Прежде всего, на этой вкладке нет ScrollViewer, поэтому ее необходимо добавить. Во-вторых, ContentTemplate2 использует ViewBox, который растягивается по умолчанию, поэтому масштабирование не будет иметь эффекта до тех пор, пока вы не приближаетесь очень близко. Чтобы отключить Viewbox»встроенный„сигналя“, вы можете центрирования ContentControl контейнер (используя HorizontalAlignment/VerticalAlignment), что заставляет его занять как мало места, как это возможно:

<TabItem Header="Content 2"> 
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> 
     <ContentControl ContentTemplate="{StaticResource ContentTemplate2}" ... 
         HorizontalAlignment="Center" VerticalAlignment="Center" > 
      <FrameworkElement.LayoutTransform> 
       ... 

Content 2, un-zoomed Content 2, zoomed

+0

Спасибо за ответ. К сожалению, пропустил второй просмотрщик прокрутки. Как вы могли заметить на скриншоте ContentTemplate1, после шкалы LayoutTransform правая панель меньше левой. Вместо этого я хочу, чтобы он масштабировался точно так же, как RenderTransform, но без потери scrollviewer. Причина, по которой ContentTemplate2 является областью просмотра, заключается в том, что она будет растягиваться, даже до того, как начнется трансфокация. Еще раз хочу, чтобы он масштабировался/вел себя как RenderTransform + ScaleTransform, но все еще работает с ScrollViewer. – jayars

+0

Хорошо. Возможно, я что-то нашел. Я сделаю для него новый ответ. – Sphinxxx

0

Моего первый совет, чтобы проверить, какую функцию масштабирования вы можете с помощью коммерческой третьей стороны zoom control, что уже есть поддержка ScrollViewer, а также имеет множество дополнительного масштабирования и панорамирование функции.

Теперь к решению вашей проблемы:

Вы можете сделать свой код работать с использованием LayoutTransform, но вам нужно будет установить размер содержимого ScrollViewer к фиксированному значению.

В настоящее время у вас есть сетка внутри ScrollViewer. Сетка не имеет определенного размера, поэтому она занимает все пространство, которое она может получить. Поэтому, если вы теперь масштабируете сетку, например, по коэффициенту 2, это означает, что содержимое сетки масштабируется по коэффициенту 2, но сетка все равно будет занимать все пространство, которое оно может получить. Если вы укажете ширину сетки 500, а затем ее масштабирование на 2, то получится ширина сетки 1000. Но если вы скажете: Grid, вы можете взять все пространство, которое дает вам родитель, а затем масштабировать сетку, это будут все те же. Это означает, что масштабирование содержимого Auto-size ScrollViewer не отображает полосы прокрутки.

В вашем примере это верно до тех пор, пока содержимое сетки (первый столбец шириной = 150 + ширина «правого» текста во втором столбце) не превысит доступный размер - в этот момент желаемый размер сетки будет больше размера, который может предоставить ScrollViewer, и ScrollViewer отобразит полосы прокрутки.

Например:

1) допустим, что при запуске приложения, масштаб устанавливается в 1 и ScrollViewer обеспечивает 500 точек по горизонтали для сетки. Сетка отображает первый столбец шириной в 150 точек и показывает «правый» текст без какого-либо масштаба. Второй столбец установлен для заполнения оставшегося пространства - так: во втором столбце используется 500 - 150 = 350 точек.

2) Теперь пользователь устанавливает шкалу в 2. Сетка масштабирует первый столбец до 300 точек. Это означает, что второй столбец теперь может принимать только 200 точек. Сетка также масштабирует текст «Правый», но содержание (300 первого столбца + ширина текста) по-прежнему не превышает 500 точек, которые предоставляются ScrollViewer.

3) Пользователь теперь устанавливает масштаб на 3. Теперь общая ширина содержимого сетки превышает 500 пунктов, а это означает, что ScrollViewer будет показывать полосы прокрутки.

Так что, имея авторизованные элементы управления, ScrollViewer и масштабирование не работают.

Но если вы установили размер сетки на 500, то при масштабировании и использовании ScrollViewer вы получите гораздо более предсказуемые результаты. Например, если вы масштабируете на 10%, то размер сетки будет 550 и будет превышать размер ScrollViewer - поэтому ScrollViewer будет показывать полосы прокрутки. Это также даст вам ожидаемое поведение, когда вы увеличите размер окна - размер сетки останется прежним, и в какой-то момент полосы прокрутки исчезнут (когда окно будет достаточно большим, чтобы показать весь контент масштабированная сетка).

В заключение: мой совет - установить фиксированный размер содержимого элементов управления ScrollViewer. Если у вас есть окно с фиксированным размером, вы можете установить ширину и высоту на основе этого размера.В противном случае вы можете установить его динамически, когда элемент управления первым загружено:

Вы можете изменить XAML для управления содержимым в:

<ContentControl Name="ContentControl1" 
       ContentTemplate="{StaticResource ContentTemplate1}" 
       Margin="10" 
       Loaded="ContentControl1_OnLoaded" > 

А также добавить ContentControl1_OnLoaded обрабатывается, что бы просто установите размер начального размер:

private void ContentControl1_OnLoaded(object sender, RoutedEventArgs e) 
{ 
    ContentControl1.Width = ContentControl1.ActualWidth; 
    ContentControl1.Height = ContentControl1.ActualHeight; 
} 

Масштабирование и панорамирование могут показаться очень простой задачей. Но мой опыт показывает (я автор управления ZoomPanel), что эта задача может быстро стать очень сложной.

Смежные вопросы