简体   繁体   English

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

[英]Modifying TextBox ControlTemplate to limit scrolling, property settings aren't correct at runtime

I'm having problems customizing the ControlTemplate for a TextBox . 我在为TextBox定制ControlTemplate遇到问题 The idea is to automatically print text neatly on lined paper with as little user interaction as possible, while remaining as flexible as possible with regard to text length, font size, etc. 这个想法是自动在整齐的纸上自动整齐地打印文本,并尽可能减少用户交互,同时在文本长度,字体大小等方面保持尽可能灵活。

To that end one setting is text height relative to a printed line (how close to/far above the line it appears on paper). 为此,一个设置是相对于打印行的文本高度(距它在纸上显示的行的距离近/远)。 Since changing TextBox LineHeight adds space below text and not above it, I've been using Padding on the top of the textbox to translate text downward. 由于更改TextBox LineHeight会在文本下方而不是上方添加空间,因此我一直在使用文本框顶部的Padding向下转换文本。

This causes a problem whenever the specified LineHeight is greater than the remaining visible space inside the textbox. 每当指定的LineHeight大于文本框内的剩余可见空间时,就会引起问题。 It is possible to inadvertently scroll down to the bottom of the line, causing the text to scroll up into the padded area and disappear. 可能会无意间向下滚动到该行的底部,从而导致文本向上滚动到填充区域并消失。

To fix this, I need to prevent MouseWheel/PgUp/PgDwn scrolling inside the textbox or figure out how render text along the bottom edge of a line instead of the top. 要解决此问题,我需要防止MouseWheel / PgUp / PgDwn在文本框内滚动,或者弄清楚如何沿一行的底部边缘而不是顶部呈现文本。

Using Snoop, I found the TextBox control has a ScrollContentPresenter whose CanContentScroll property is determined by its ParentTemplate from a ScrollViewer . 使用Snoop,我发现TextBox控件具有ScrollContentPresenter其CanContentScroll属性由ScrollViewer ParentTemplate确定。 Un-checking CanContentScroll in Snoop while the application's running disables scrolling and prevents this behavior just as I want, but for some reason specifying CanContentScroll = False in the template does work. 在应用程序运行时,在Snoop中取消选中CanContentScroll会禁用滚动,并按照我的意愿阻止此行为,但是由于某些原因,在模板中指定CanContentScroll = False确实可行。 It remains True . 它仍然是True

XAML: 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>

The style is lifted directly from Microsoft's WPFThemes/Aero.NormalColor.xaml with only one change to the controltemplate to disable scrolling. 可以直接从Microsoft的WPFThemes / Aero.NormalColor.xaml提取样式,而对controltemplate进行一次更改即可禁用滚动。 Changes to other (omitted) setters such as background color did work. 对其他(省略)设置器的更改(例如背景色)确实可行。 I specified the style directly in the TextBox since it won't be used anywhere else and assuming that local styles precede implicit ones, but I'm guessing this might not be the right place to do this. 我直接在TextBox中指定了样式,因为它不会在其他任何地方使用,并且假定局部样式先于隐式样式出现,但是我猜测这可能不是执行此操作的正确位置。

Can anyone point out where I'm going wrong with this, or confirm whether it's possible to change where text is rendered on a line? 谁能指出我对此有何疑问,或确认是否可以更改文本在一行上的显示位置?

Thank you 谢谢

EDIT: Here's a better description of what this TextBox is actually doing 编辑:这是对此TextBox实际所做的更好的描述

Suppose you have a paper form such as a loan or permit application which has a several questions, each with 3 pre-printed lines on which to write your answer. 假设您有一个纸质表格,例如贷款或许可申请,其中有几个问题,每个问题都有3个预打印的行,可在上面写下您的答案。 The TextBox: 文字框:

  • Is sized/positioned to cover the entire answer area 确定大小/位置以覆盖整个答案区域
  • Is set to contain 3 lines 设置为包含3行
  • Gives the user font size, alignment, typeface options 提供用户字体大小,对齐方式,字体选项
  • Automatically adjusts LineHeight to space lines evenly and sets Padding to position text just above the printed line 自动调整LineHeight以均匀间隔行,并将Padding设置为将文本定位在打印行的正上方
  • Does not allow overflow, even if text input is longer than expected. 即使文本输入的时间比预期的长,也不允许溢出。 The # of lines increases in multiples (doubles, then triples, and so on) and font size is adjusted to try to print everything neatly in the provided space (no lines of text crossed out by printed lines, for example) 行数以倍数(双倍,然后三倍,依此类推)增加,并且调整了字体大小以尝试在提供的空间中整齐地打印所有内容(例如,没有文本行被打印行划掉)

In practice, this works very well and results in tidy looking forms, as if someone did it by hand with an old Selectric. 在实践中,这个作品非常好,导致整齐的形式看,好像有人用旧Selectric做到了手。 The only problem is this accidental scrolling issue happens once in awhile. 唯一的问题是偶然的滚动问题会不时发生。

The meaning of my question changed after Anatoliy reminded me that CanContentScroll does not enable or disable scrolling of content despite its name, but switches between scrolling by pixel and scrolling by item. 在Anatoliy提醒我, CanContentScroll尽管启用了内容名称后,它并未启用或禁用内容滚动,而是在按像素滚动和按项目滚动之间切换,但我的问题的含义发生了变化。 However my intent was to stop scrolling behavior within a TextBox altogether, and I have solved that problem now and also improved scrolling behavior in the ListBox hosting them by eliminating the nested ScrollViewers: 但是,我的目的是完全停止TextBox内的滚动行为,并且我现在已经解决了该问题,并且通过消除嵌套的ScrollViewers,还改善了托管它们的ListBox滚动行为:

First, I found this blog post which explains why ScrollViewer always handles MouseWheel . 首先,我找到了此博客文章 ,其中解释了ScrollViewer始终处理MouseWheel It is possible to subclass ScrollViewer to prevent this, which I was going to do until I wondered why I couldn't just change the content host element in the template to something without scrolling, since I don't need it at all. 可以将ScrollViewer子类化以防止这种情况,我一直想这样做,直到我想知道为什么我不能不滚动就不能将模板中的内容宿主元素更改为某种内容,因为我根本不需要它。 ContentPresenter didn't work, but the Important Note Box on this MSDN page mentioned that TextBox only works with ScrollViewer or AdornerDecorator . ContentPresenter不起作用,但是此MSDN页面上重要说明框提到TextBox仅与ScrollViewerAdornerDecorator

Switching to AdornerDecorator worked perfectly: 切换到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>

I was able to bind the margin to my existing text offset property to position text as before, and ClipToBounds confines the content to the visible area. 我能够像以前一样将页边距绑定到现有的文本偏移属性以定位文本,并且ClipToBounds将内容限制在可见区域。 The other major improvement is that scrolling through a collection of these TextBoxes in a ListBox now works as expected since the textboxes aren't handing MouseWheel anymore. 另一个主要改进是,现在滚动浏览ListBox框中的这些TextBox的集合现在可以按预期工作,因为文本框不再处理MouseWheel。 Nested ScrollViewers are unpleasant. 嵌套的ScrollViewer令人不快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM