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
LineHeightto space lines evenly and setsPaddingto 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
CanContentScrolldoes 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 aTextBoxaltogether, and I have solved that problem now and also improved scrolling behavior in theListBoxhosting them by eliminating the nested ScrollViewers:First, I found this blog post which explains why
ScrollVieweralways 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.ContentPresenterdidn't work, but the Important Note Box on this MSDN page mentioned that TextBox only works withScrollViewerorAdornerDecorator.Switching to
AdornerDecoratorworked perfectly:I was able to bind the margin to my existing text offset property to position text as before, and
ClipToBoundsconfines the content to the visible area. The other major improvement is that scrolling through a collection of these TextBoxes in aListBoxnow works as expected since the textboxes aren't handing MouseWheel anymore. Nested ScrollViewers are unpleasant.