ContentControl с ScrollViewer, фокус

В моем проекте Windows 8 Metro я использую класс, производный от ContentControl (назовем его MyControl), для представления своего контента. Внутри MyControl у меня есть ScrollViewer. Поскольку я хочу, чтобы мой элемент управления обрабатывал события клавиатуры, мне нужно иметь возможность установить фокус на свой элемент управления. Однако я также хочу, чтобы средство просмотра прокрутки обрабатывало ключевые события, такие как клавиши со стрелками и PageUp/Down. Точнее, я хочу, чтобы это была опция, которую может включать или выключать другой программист. Это означает, что иногда я хочу, чтобы MyControl был табулятором, а иногда я хочу, чтобы ScrollViewer был табулятором, но никогда и то, и другое.

Проблема в том, что я не хочу раскрывать внутреннюю работу MyControl другим программистам. То есть в идеале они должны иметь возможность использовать MyControl.IsTabStop и оставить логику размещения фактической позиции табуляции с моим элементом управления (чтобы поместить его в MyControl или ScrollViewer).

Есть ли хороший способ добиться этого, или мне как-то нужно обойти это, предоставив отдельную функцию, чтобы сделать мой элемент управления остановкой табуляции?


person Tomas    schedule 16.11.2012    source источник


Ответы (1)


Если вы посмотрите на мой тестовый XAML, вы увидите, что я ничего не делаю, но клавиши вверх/вниз в TextBox работают для перехода между строками текста и прокручивают ScrollViewer, когда нет строки текста для перехода. Вероятно, это достигается тем, что обработчики KeyDown устанавливают для параметра e.Handled значение true, когда они не хотят, чтобы ключевое событие всплывало (например, когда TextBox уже обработал его), и оставляют значение false, когда событие не обрабатывается, что позволяет ScrollViewer справляется с этим. Событие всегда будет срабатывать в текстовом поле, если оно имеет фокус, но всплывает вверх по визуальному дереву, если оно не обрабатывается. Не похоже, что вам нужно делать что-то большее, чем просто решить, хотите ли вы пометить ключевые события как обработанные или нет.

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <ScrollViewer
        IsTabStop="True">
        <Grid
            Width="2000"
            Height="2000">
            <Button
                Margin="149,342,0,311">
                <Button>
                    <TextBox
                        AcceptsReturn="True"
                        Height="400"
                        Width="200"/></Button>
            </Button>
        </Grid>
    </ScrollViewer>
</Grid>
person Filip Skakun    schedule 16.11.2012
comment
Я думаю, мой вопрос недостаточно ясен. ЕСЛИ вы нажмете клавишу табуляции, вы будете переключать фокус между TextBox и ScrollViewer. Представьте, что вы поместили ScrollViewer внутрь FlipView и установили для обоих их IsTabStop значение true. Если вы сейчас щелкнете ScrollViewer, он будет иметь фокус, а не FlipView. Однако, если вы нажмете вкладку, можно сфокусироваться как на флип-просмотре, так и на прокрутке. Теперь предположим, что у вас есть собственный элемент управления, внутри которого находится эта структура. Допустим, вы предоставляете пользователю этого элемента управления возможность отключить обработку клавиш в средстве просмотра прокрутки. Как вы сохраняете это прозрачным? - person Tomas; 17.11.2012
comment
Не уверен, что вы имеете в виду до сих пор. Вы хотите предоставить возможность делать TabStop в ScrollViewer в шаблоне элемента управления? Просто выполните {TemplateBinding} в свойстве TabStop ScrollViewer, чтобы привязать его к свойству DependencyProperty, которое вы определяете в своем элементе управления. Однако вряд ли это будет понятно пользователю этого элемента управления. Я бы сказал, что ScrollViewer никогда не должен устанавливать для TabStop значение true, но если кто-то этого хочет, он может отредактировать шаблон вашего элемента управления и сделать его таким. - person Filip Skakun; 17.11.2012
comment
Хм, если у ScrollViewer нет IsTabStop=true, как он будет получать ввод с клавиатуры? Насколько я знаю, чтобы получить ввод с клавиатуры, либо вы, либо ваш ребенок должны быть в фокусе. Если мой элемент управления находится в фокусе, а ScrollViewer является дочерним элементом моего элемента управления, то ввод с клавиатуры не будет проходить через ScrollViewer. Надеюсь, я ничего не понимаю во всем этом... - person Tomas; 17.11.2012
comment
Вот о чем был мой ответ - ему не нужно иметь фокус для получения ввода с клавиатуры, если какой-либо элемент управления внутри него имеет фокус. - person Filip Skakun; 17.11.2012
comment
Я вижу, где мы неправильно поняли друг друга. Я не хочу давать контрольный фокус. Я хочу, чтобы элемент управления, находящийся внутри, имел фокус (например, ScrollViewer). - person Tomas; 19.11.2012
comment
Что ж, если вы поместите туда что-то, что не может получить фокус, но вы все равно хотите, чтобы ваш ScrollViewer можно было использовать с клавиатурой, вы можете проверить, имеет ли визуальное дерево содержимого значение IsTabStop, установленное где-то в true, и установить для IsTabStop ScrollViewer значение true, если оно нет, но для пользователя элемента управления по-прежнему имеет смысл сделать его фокусируемым, поэтому, например, если он показывает только изображение внутри него и хочет, чтобы прокрутка работала, они установили бы IsTabStop на изображении в значение true. Добавление еще одного свойства было бы ненужным и потенциально запутанным. - person Filip Skakun; 19.11.2012
comment
Я тоже так думал о том, чтобы запутать пользователя дополнительными опциями. Однако в этом случае пользователь не контролирует прокрутку. В идеале я хочу, чтобы все было прозрачно. То есть мой элемент управления отображает некоторый контент, и пользователь просто получает преимущество автоматической прокрутки при нажатии клавиш, если элемент управления является остановкой табуляции, и никакой автоматической прокрутки, если это не так. Таким образом, пользователь может выбрать, хочет ли он создать собственное поведение прокрутки или нет. - person Tomas; 19.11.2012
comment
Что ж, тогда просто привяжите свойство IsTabStop ScrollViewer к одному из элементов управления. - person Filip Skakun; 20.11.2012
comment
Что оставляет меня только с 1 вопросом. Навигация по вкладкам станет несколько неудобной... теперь нажатие на вкладку может привести к обоим из них, поэтому иногда вы получаете поведение прокрутки, а иногда нет. О, и кстати. Спасибо, что нашли время :) - person Tomas; 20.11.2012
comment
Что ж, тогда вы можете добавить еще одно неудобное свойство и использовать его вместо свойства IsTabStop — например, IsTabStopScrollViewer на самом элементе управления, чтобы управлять им. - person Filip Skakun; 20.11.2012