today I'm searching for a way to scroll a multiline, dynamically sized textbox.
I want to scroll to the Caret and don't find any helpful informations at the internet.
After trying many things i know how to scroll to the end of a line, but not how to scroll to the caret.
The scroll to the right line is already implemented, but the horizontal scroll part is already missing.
private void txtText_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down || e.Key == Key.Up)
{
var CurrentLineIndex = txtText.GetLineIndexFromCharacterIndex(((TextBox)sender).SelectionStart);
txtText.ScrollToLine(CurrentLineIndex);
}
}
This is my current code, which does scrolling to the right line for me.
Tryed to do something simular for the horizontal scrolling:
var rect = ((TextBox)sender).GetRectFromCharacterIndex(((TextBox)sender).CaretIndex);
txtText.ScrollToHorizontalOffset(Math.Max((txtText.HorizontalOffset + rect.Right - (txtText.ActualWidth - 40)), 0.0));
But it doesn't work like expected, it scrolls not to the horizontal caret position.
Think, i had to discribe it better:
if i move the caret with the left or right arrow, it will work fine without implementing anything.
It doesn't work if i do this:
Move from one line to another.
Sometimes one of these lines is longer or shorter than another and at this case i had to scroll to the caret position.
Example:
Line1 is longer than line2
I navigate with the key "end" at the keyboard to the end of line1.
Then i navigate to to line2.
It all works correctly, the caret jumps to the end of line2 and it will scrolls automatically into visibile area.
But if i go back from line2 to line1 the caret is position right at the end of line1. But it scrolls not to the end of line1.
the problem was that i used a Style template and forgot a necessary thing:
to pass
ContentTemplate="{TemplateBinding ContentTemplate}" CanContentScroll="{TemplateBinding CanContentScroll}"
to the ScrollContentPresenter.
After doing this, the standard behaviour will work well!
Related
I'm using the following controls in WPF (XAML) code to create a canvas:
<ScrollViewer x:Name="CanvasScrollViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" Background="Beige" >
<Canvas x:Name="canvas" Height="10000" Width="10000" MouseWheel="CanvasMouseWheel" >
<Canvas.RenderTransform>
<MatrixTransform/>
</Canvas.RenderTransform>
</Canvas>
In essence, this includes a canvas (which is larger than my screen resolution) and a scrollviewer, to make sure that I can navigate around the whole canvas.
Now, I want to zoom in / out at the current mouse cursor position of the canvas if I keep CTRL pressed and use the mousewheel. It works quite well using an approach similar to the one listed here.
My C# code looks like this:
private void CanvasMouseWheel(object sender, MouseWheelEventArgs e)
{
if (Keyboard.Modifiers != ModifierKeys.Control)
return;
var sentCanvas = sender as UIElement;
var position = e.GetPosition(sentCanvas);
var transform = canvas.RenderTransform as MatrixTransform;
var matrix = transform.Matrix;
var scale = e.Delta >= 0 ? 1.2 : (1.0 / 1.2);
matrix.ScaleAtPrepend(scale, scale, position.X, position.Y);
transform.Matrix = matrix;
e.handled = true;
}
This works quite nicely with one exception: If I scroll in / out, the position of the scroll bars of the scroll viewers and the actual position of the canvas are no longer synchronized. Meaning: The canvas zooms in or out, but the scroll viewer does not adjusts its scroll bar positions which ultimately means that you cannot properly scroll the canvas anymore.
Naturally (as I use the canvas to draw large diagrams which require a lot of navigation), I want to be able zoom out quite a lot from time to time, so that the whole canvas fills only part of the field of view of the scroll viewer. The attached screen shot shows that situation for clarification where I zoomed out a lot.
I tried several other approaches like first moving the scroll viewer to the mouse position and then applying the "scale(...)" operation (without "AtPrepend"), but to no avail. Performing the scale operation directly on the scrollviewer obviously doesn't work, either. Probably, the solution is trivial, but I can't see the forest for the trees...
Any help would be deeply appreciated!
Thanks to BionicCode for the hint. The following entry answers my question and works perfectly:
WPF Canvas zoom and children position
In Silverlight 4, is there a way that whenever you page down a ScrollViewer (i.e click the scroll bar in the area adjacent to the thumb) whatever item is at the top is completely visible. I still need it to scroll smoothly when the thumb is dragged or the mouse wheel is used.
My client doesn't like that an item is cut in half when he pages down the list because it is cut in half both when its at the top and when its at the bottom. I suggested some sort of integral scroll, and he didn't like it. He wants it to still scroll smoothly unless paging up or down.
Edits
Here's the catch. The items are not the same size. So I have to detect the item that is at the top of the scroll viewer and Scroll it into view. Is there an easy way to do this?
The first thing you need to do is dig out the vertical scroll bar from the internals of the ScrollViewer. You can do this with the help of VisualTreeHelper. There are a number of little chunks of code in various blogs the make its use even easier. I recommend this VisualTreeEnumeration (but I would wouldn't I). With that extensions class in place you can get the vertical scroll bar with:
ScrolBar vertSB = someScrollViewer.Descendents()
.OfType<ScrollBar>()
.FirstOrDefault(sb => sb.Name = "VerticalScrollBar");
Now you can attach to is Scroll event and determine the type of scroll that occured like this:
vertSB.Scroll += (s, args) =>
{
if (args.ScrollEventType == ScrollEventType.LargeDecrement
|| args.ScrollEventType == ScrollEventType.LargeIncrement)
{
// using args.NewValue determine the correct Integral value and assign
// using someScrollViewer.ScrollToVerticalOffset
}
};
I need to write the following component in WPF:
It should be over image, I should able to drag the lines with the mouse (drag X up and down, drag Y left and right, and Z spin from horizontal to vertical)
My backround in WPF is almost not exist,
Can you give me guidliness? do you know component that doing it, or something similar to that?
Do you know what is the name of this control?
Thanks.
I refactored the program in
http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part1.aspx
In the code I just remark
//Canvas.SetTop(designerItem, top + e.VerticalChange);
And remain
Canvas.SetLeft(designerItem, left + e.HorizontalChange);
Delete almost everything, replaced image with rectangle,
And now the verical and horizontal lines drag and drop lines work,
Now I am searching how to do the diagonal line drag and drop
(I tried to do it with path/line control, I had the problem that if I add the diagonal line, it capture all the mouse event, and I can't move the other lines)
Help still needed
I managed to do it,
You can download the code here
Let's say that I have a RichTextBox and its contents take up about 3 times the height compared to the visible height. There's no color formatting, I want to highlight keywords. If I use SelectionStart, SelectionLength and SelectionColor, then I have to set SelectionStart back to the caret's original position.
If, for example, I'm looking at the first page and my caret is half-way down the page, but I want a keyword highlighted near the end, when the caret is returned, the RichTextBox will only scroll up far enough for the caret to be on the top visible line, so my visible position has moved.
Is there any way for me to format colors out of view without affecting the view position? Or, is there any way for me to get and set/reset the view position after formatting?
The solution is here:
"Get/Set the ScrollBars’ positions"
http://codebetter.com/blogs/patricksmacchia/archive/2008/07/07/some-richtextbox-tricks.aspx
After I return the caret to its original position with SelectionStart, I can use the code shown on the blog to return the view to its original position.
I am dynamically adding text in a RichTextBox.
How can I set Focus on the last line so the user can see it?
This will move the caret to the last line:
richTextBox.CaretPosition = richTextBox.Document.ContentEnd;
But it will not scroll the richTextBox to make the caret visible. To accomplish that you also have to call ScrollToEnd():
richTextBox.CaretPosition = richTextBox.Document.ContentEnd;
richTextBox.ScrollToEnd();