I'm having problems customizing the ControlTemplate
for a TextBox
. 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.
This causes a problem whenever the specified LineHeight is greater than the remaining visible space inside the textbox. 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.
Using Snoop, I found the TextBox control has a ScrollContentPresenter
whose CanContentScroll property is determined by its ParentTemplate from a ScrollViewer
. 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. It remains 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>
The style is lifted directly from Microsoft's WPFThemes/Aero.NormalColor.xaml with only one change to the controltemplate to disable scrolling. 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.
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
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. The TextBox:
- Is sized/positioned to cover the entire answer area
- Is set to contain 3 lines
- Gives the user font size, alignment, typeface options
- Automatically adjusts
LineHeight
to space lines evenly and setsPadding
to position text just above the printed line - 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. 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. However my intent was to stop scrolling behavior within aTextBox
altogether, and I have solved that problem now and also improved scrolling behavior in theListBox
hosting them by eliminating the nested ScrollViewers:First, I found this blog post which explains why
ScrollViewer
always handlesMouseWheel
. 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.ContentPresenter
didn't work, but the Important Note Box on this MSDN page mentioned that TextBox only works withScrollViewer
orAdornerDecorator
.Switching to
AdornerDecorator
worked perfectly: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. The other major improvement is that scrolling through a collection of these TextBoxes in aListBox
now works as expected since the textboxes aren't handing MouseWheel anymore. Nested ScrollViewers are unpleasant.