修改TextBox ControlTemplate以限制滚动,属性设置在运行时不正确

时间:2013-08-05 17:08:24

标签: wpf textbox controltemplate scrollviewer snoop

我在为ControlTemplate 自定义TextBox时遇到问题。我们的想法是在尽可能少的用户交互下,在衬纸上自动打印文本,同时尽可能保持文本长度,字体大小等方面的灵活性。

为此,一个设置是相对于打印行的文本高度(在纸张上显示的行的接近/远处)。由于更改TextBox LineHeight会在文本下方添加空格而不在文本框上方,我一直在文本框顶部使用Padding向下翻译文本。

只要指定的LineHeight大于文本框内的剩余可见空间,就会出现问题。有可能无意中向下滚动到行的底部,导致文本向上滚动到填充区域并消失。

要解决此问题,我需要阻止MouseWheel / PgUp / PgDwn在文本框内滚动,或者弄清楚如何沿着行的下边缘而不是顶部渲染文本。

使用Snoop,我发现TextBox控件有一个ScrollContentPresenter,其CanContentScroll属性由ScrollViewer的ParentTemplate确定。在应用程序运行时禁用Snoop中的CanContentScroll禁用滚动并按我的意愿阻止此行为,但由于某些原因,在模板中指定CanContentScroll = False确实有效。它仍然是True

XAML:

<TextBox.Style>
    <Style TargetType="TextBoxBase">
        . . . 
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBoxBase}">
                    <theme:ListBoxChrome x:Name="Bd" . . . >
                        <ScrollViewer x:Name="PART_ContentHost"
                                      CanContentScroll="False"/>
                    </theme:ListBoxChrome>
                    . . . 
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</TextBox.Style>

直接从Microsoft的WPFThemes / Aero.NormalColor.xaml中提取样式,只需对controltemplate进行一次更改即可禁用滚动。对其他(省略)设置器(例如背景颜色)的更改确实有效。我直接在TextBox中指定了样式,因为它不会在其他任何地方使用,并假设本地样式先于隐式样式,但我猜这可能不适合这样做。

任何人都可以指出我在哪里出错,或者确认是否可以更改文本在一行上的呈现位置?

谢谢

编辑:以下是对此TextBox实际执行操作的更好描述

假设您有一份纸质表格,例如贷款或许可证申请表,其中有几个问题,每个问题都有3条预先打印的行,您可以在上面写下答案。 TextBox:

  • 大小/位置覆盖整个答案区域
  • 设置为包含3行
  • 提供用户字体大小,对齐方式,字体选项
  • 自动将LineHeight调整为空格线,并将Padding设置为位于打印行上方的文字
  • 即使文本输入超出预期,也不允许溢出。行数增加倍数(双倍,然后是三倍,等等),并调整字体大小以尝试在提供的空间中整齐地打印所有内容(例如,没有打印行划掉的文本行)

在实践中,这很好地非常并且导致整洁的外观形式,好像有人用旧的Selectric手工完成它。唯一的问题是偶然发生这种偶然的滚动问题。

1 个答案:

答案 0 :(得分:1)

我的问题的含义在Anatoliy提醒我CanContentScroll 启用或禁用内容滚动尽管其名称后更改了,但在按像素滚动和按项目滚动之间切换。但是我的意图是完全停止在TextBox内滚动行为,我现在已经解决了这个问题,并通过消除嵌套的ScrollViewers来改善托管它们的ListBox中的滚动行为:

首先,我发现this blog post解释了ScrollViewer始终处理MouseWheel的原因。可以将ScrollViewer子类化以防止这种情况发生,直到我想知道为什么我不能将模板中的内容主机元素更改为没有滚动的东西,因为我根本不需要它。 ContentPresenter无效,但Important Note Box on this MSDN page提到TextBox仅适用于ScrollViewerAdornerDecorator

切换到AdornerDecorator效果很好:

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type TextBoxBase}">
            . . .
            <AdornerDecorator x:Name="PART_ContentHost"
                              ClipToBounds="True"
                              Margin="{Binding GetTextOffset}"
                              />
        </ControlTemplate>
    </Setter.Value>
</Setter>

我能够将边距绑定到我现有的文本偏移属性,以便像以前一样定位文本,ClipToBounds将内容限制在可见区域。另一个主要的改进是,在ListBox中滚动浏览这些TextBox的集合现在可以正常工作,因为文本框不再处理MouseWheel了。嵌套的ScrollViewers令人不快。