[WPF] ScrollView
От: algama  
Дата: 06.04.09 10:44
Оценка:
приветствую...

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


    <Style TargetType="{x:Type local:ScrollViewerEX}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ScrollViewerEX}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="10"/>
                                <ColumnDefinition/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition/>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>

                            <ScrollContentPresenter
                                Name="PART_ScrollContentPresenter"
                                Grid.Column="1"
                                Grid.Row="0"
                                Content="{TemplateBinding Content}"
                                />

                            <ScrollContentPresenter
                                Name="PART_EXScrollContentPresenter"
                                Grid.Column="1"
                                Grid.Row="1"
                                CanContentScroll="True"
                                CanHorizontallyScroll="True"
                                >
                                <ScrollContentPresenter.Content>
                                    <Border
                                        BorderThickness="2"
                                        BorderBrush="Magenta"
                                        Width="{TemplateBinding ExtentWidth }"
                                        Height="43"
                                        >
                                        <Canvas Background="Coral" >
                                            <Canvas Background="Brown"  >
                                                <Ellipse Name="ellipse10" Canvas.Left="10" Canvas.Top="10" Height="20" Width="20" Stroke="Black" Fill="Red" />
                                                <Ellipse Name="ellipse20" Canvas.Left="120" Canvas.Top="10" Height="20" Width="20" Stroke="Black" Fill="Green" />
                                                <Ellipse Name="ellipse30" Canvas.Left="250" Canvas.Top="10" Height="20" Width="20" Stroke="Black" Fill="Blue" />
                                            </Canvas>
                                        </Canvas>
                                    </Border>
                                </ScrollContentPresenter.Content>
                            </ScrollContentPresenter>

                            <ScrollBar
                                Name="PART_VerticalScrollBar"
                                Grid.Row="0"
                                Grid.Column="2"
                                Grid.RowSpan="2"
                                Value="{TemplateBinding VerticalOffset}"
                                Maximum="{TemplateBinding ScrollableHeight}"
                                ViewportSize="{TemplateBinding ViewportHeight}"
                                Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                                />

                            <ScrollBar
                                Name="PART_HorizontalScrollBar"
                                Orientation="Horizontal"
                                Grid.Row="2"
                                Grid.Column="1"
                                Value="{TemplateBinding HorizontalOffset}"
                                Maximum="{TemplateBinding ScrollableWidth}"
                                ViewportSize="{TemplateBinding ViewportWidth}"
                                Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
                                />
                            
                            <Rectangle
                                Grid.Row="2"
                                Grid.Column="2"
                                Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
                                />

                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


переопределил ScrollViewer


    [TemplatePart(Name = "PART_EXScrollContentPresenter", Type = typeof(ScrollContentPresenter))]
    public class ScrollViewerEX : ScrollViewer
    {
        //private ScrollContentPresenter timeLineContentPresenter = null;
        private ScrollContentPresenter timeScaleContentPresenter = null;

        static ScrollViewerEX()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewerEX), new FrameworkPropertyMetadata(typeof(ScrollViewerEX)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            //this.timeLineContentPresenter = base.GetTemplateChild("PART_ScrollContentPresenter") as ScrollContentPresenter;
            this.timeScaleContentPresenter = base.GetTemplateChild("PART_EXScrollContentPresenter") as ScrollContentPresenter;
        }

        /*
        protected override void OnScrollChanged(ScrollChangedEventArgs e)
        {
            base.OnScrollChanged(e);
            if (e.HorizontalChange != 0)
            {
                if (this.timeScaleContentPresenter != null)
                {
                    this.timeScaleContentPresenter.SetHorizontalOffset(e.HorizontalOffset);
                }
            }
        }
        */
    }


верхний ScrollContentPresenter работает как положено,а нижний не скролиться.
если раскоментировать OnScrollChanged? то всё заработает, но как то не кузяво на мой взгляд.
хотелось бы докопаться до правильного решения.
есть какие соображения? может кто знает как это сделано?
заранее спасибо.
Re: [WPF] ScrollView
От: Sinix  
Дата: 07.04.09 08:20
Оценка:
Здравствуйте, algama.

Дык определите биндинг у PART_EXScrollContentPresenter. Посмотрите, как ScrollViewer стандартный с элементами шаблона работает. Cтандартный ScrollViewer ничего не знает о втором (вложенном) ScrollContentPresenter и не может им управлять.

Никакой магии
Re[2]: [WPF] ScrollView
От: algama  
Дата: 07.04.09 08:44
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, algama.


S>Дык определите биндинг у PART_EXScrollContentPresenter. Посмотрите, как ScrollViewer стандартный с элементами шаблона работает. Cтандартный ScrollViewer ничего не знает о втором (вложенном) ScrollContentPresenter и не может им управлять.


S>Никакой магии


дык... пытался... в коде ковырялся по самые уши но так и не вкурил... совсем уже запутался...
Re[3]: [WPF] ScrollView
От: Sinix  
Дата: 08.04.09 00:36
Оценка:
Здравствуйте, algama.

A>дык... пытался... в коде ковырялся по самые уши но так и не вкурил... совсем уже запутался...


Тогда оставьте как есть и идите изучать матчасть, в WPF без этого тяжко.
Может MxKazan или notacat чего подскажет?
Re[3]: [WPF] ScrollView
От: MxKazan Португалия  
Дата: 08.04.09 09:22
Оценка:
Здравствуйте, algama, Вы писали:

A>дык... пытался... в коде ковырялся по самые уши но так и не вкурил... совсем уже запутался...

А что не вкурил то? Всё правильно ответили. Стандартный ScrollViewer знать не знает про твой собственный Presenter, чего ж ты удивляешься. Даже больше скажу: мне кажется у тебя логическая ошибка. ScrollContentPresenter по смыслу спроектирован так, что он все-лишь элемент шаблона, строющий визуальное дерево по содержимому ScrollViewer. Ты же явно запихиваешь в него своё собственное содержимое, что противоречит целям использования данного элемента. Так что не серчай на WPF, что у нее не получается догадаться о твоей задаче

Можно рассмотреть другой вариант. Для второго содержимого (где кружочки всякие) использовать не ScrollContentPresenter, а Canvas. Элементам внутри Canvas сделать биндинг свойства Canvas.Left на текущую позицию PART_HorizontalScrollBar с конвертером, который будет инвертировать значение. Там, конечно, придется повозиться еще с размерами, но это всё-равно будет корректнее двух ScrollContentPresenter.

Ну или оставить вариант с обработчиком! В конце концов почему нет, в частном порядке
Re[3]: [WPF] ScrollView
От: notacat  
Дата: 08.04.09 09:41
Оценка:
а зачем именно ScrollViewer переопределять?
Не проще сделать свой контрол, в который два ScrollViewer'а положить?
Re[4]: [WPF] ScrollView
От: algama  
Дата: 08.04.09 10:47
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, algama.


A>>дык... пытался... в коде ковырялся по самые уши но так и не вкурил... совсем уже запутался...


S>Тогда оставьте как есть и идите изучать матчасть, в WPF без этого тяжко.


собственно этим я и занимаюсь...
Re[4]: [WPF] ScrollView
От: algama  
Дата: 08.04.09 10:55
Оценка:
Здравствуйте, MxKazan, Вы писали:

MK>Здравствуйте, algama, Вы писали:


A>>дык... пытался... в коде ковырялся по самые уши но так и не вкурил... совсем уже запутался...

MK>А что не вкурил то? Всё правильно ответили. Стандартный ScrollViewer знать не знает про твой собственный Presenter, чего ж ты удивляешься. Даже больше скажу: мне кажется у тебя логическая ошибка. ScrollContentPresenter по смыслу спроектирован так, что он все-лишь элемент шаблона, строющий визуальное дерево по содержимому ScrollViewer. Ты же явно запихиваешь в него своё собственное содержимое, что противоречит целям использования данного элемента. Так что не серчай на WPF, что у нее не получается догадаться о твоей задаче
MK>Можно рассмотреть другой вариант. Для второго содержимого (где кружочки всякие) использовать не ScrollContentPresenter, а Canvas. Элементам внутри Canvas сделать биндинг свойства Canvas.Left на текущую позицию PART_HorizontalScrollBar с конвертером, который будет инвертировать значение. Там, конечно, придется повозиться еще с размерами, но это всё-равно будет корректнее двух ScrollContentPresenter.

да я и не удивляюсь. прекрасно понимаю что ScrollViewer ничего не знает про второй ScrollContentPresenter. как то невзначай подумалось что можно забиндить необходимые свойства из первого на второй, но сам разобраться не смог вот и спросил у общественности.
С Canvas я начал, но получилось немного громоздко, вот и захотелось упростить.

MK>Ну или оставить вариант с обработчиком! В конце концов почему нет, в частном порядке

похоже так и оставлю... но некрасиво как то...
Re[4]: [WPF] ScrollView
От: algama  
Дата: 08.04.09 10:56
Оценка:
Здравствуйте, notacat, Вы писали:

N>а зачем именно ScrollViewer переопределять?

N>Не проще сделать свой контрол, в который два ScrollViewer'а положить?
а смыл? зачем плодить сущности без надобности?
Re[5]: [WPF] ScrollView
От: MxKazan Португалия  
Дата: 08.04.09 11:14
Оценка:
Здравствуйте, algama, Вы писали:

N>>а зачем именно ScrollViewer переопределять?

N>>Не проще сделать свой контрол, в который два ScrollViewer'а положить?
A>а смыл? зачем плодить сущности без надобности?
Да было бы чего плодить. Считай добавишь такой же ScrollContentPresenter, но с "человеческим лицом" По-моему, этот вариант даже удачнее Canvas'а.
Re[6]: [WPF] ScrollView
От: algama  
Дата: 08.04.09 12:26
Оценка:
Здравствуйте, MxKazan, Вы писали:

MK>Здравствуйте, algama, Вы писали:


N>>>а зачем именно ScrollViewer переопределять?

N>>>Не проще сделать свой контрол, в который два ScrollViewer'а положить?
A>>а смыл? зачем плодить сущности без надобности?
MK>Да было бы чего плодить. Считай добавишь такой же ScrollContentPresenter, но с "человеческим лицом" По-моему, этот вариант даже удачнее Canvas'а.
мей би... подумаю...

всем спасибо, пошёл чесать репу и раскуривать бычок.
Re[5]: [WPF] ScrollView
От: notacat  
Дата: 08.04.09 14:56
Оценка:
N>>а зачем именно ScrollViewer переопределять?
N>>Не проще сделать свой контрол, в который два ScrollViewer'а положить?
A>а смыл? зачем плодить сущности без надобности?
Почему плодить? Ну будет вместо SrollViewerEx контрол с другим названием и более простым темплейтом. Сущностей ровно столько же.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.