Why does the ScrollViewer property not affect a label? - c#

I use a Label with the ScrollViewer property:
<Label ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto">
Here is many many many text.
</Label>
But no scrollbar appears. Even when using Visible instead of Auto.
What is wrong here?

You need to put the ScrollViewer around the label, it's a seperate control:
<ScrollViewer Width="50" Height="30" HorizontalScrollBarVisibility="Visible">
<Label>
Here is many many many text.
</Label>
</ScrollViewer>

Now I am wondering, why the Label can have ScrollViewer properties
when they are not affecting the label at all?
The ScrollViewer properties are attached properties. Attached properties often have default behavior that is independent from the elements they are applied to (e.g. ToolTipService properties are handled by the service, the elements themselves don't need to know anything about it), so they can always be set anywhere.
It's similar to the BorderBrush property that is on every control. A control usually passes this value along to a Border element that is within its template. Most control templates contain a Border, but many don't contain a ScrollViewer. You could write a Label template that includes one, though:
<Window.Resources>
<Style TargetType="Label">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Label ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
Content="text" />
Notice that this works even though I haven't added TemplateBindings to the ScrollViewer. This is because ScrollViewer knows about its own attached properties and actually adds the bindings by default if it is inside a template.
As you can see from the template, a label is really nothing but a content presenter with RecognizesAccessKey set. This is so that users can use Alt keyboard shortcuts based on its text. Label also defines a Target property to define which element should be selected when the keyboard shortcut is pressed. Labels are meant to be short descriptive text next to input elements. In your case (displaying long text that needs scrolling), it is probably unnecessary. In fact, you can just place the text content directly within a ScrollViewer:
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
Here is many many many text.
</ScrollViewer>

ScrollViewer attached property is there to control ScrollViewer which was defined within the control's Template (first example of such control which comes to mind is ListView). There is no ScrollViewer in Label's template, therefore setting this property on label has no effect.
Instead, you should simply wrap your Label with ScrollViewer, as was shown by JMK.

You need to add the lable inside the ScrollViewer and provide some Height and Width
<ScrollViewer HorizontalScrollBarVisibility="Visible" Height="40" Width="40" >
<Label>
Content
</Label>
</ScrollViewer>

You have to put ScrollViewer around the Label.
like--
<ScrollViewer HorizontalScrollBarVisibility="Visible">
<Label/>
</ScrollViewer>

Related

ScrollViewer thumb is not moving

I have a TreeView control, and its template is set like this:
<TreeView.Template>
<ControlTemplate>
<Border BorderBrush="DeepSkyBlue" BorderThickness="1">
<ScrollViewer CanContentScroll="False"
Height="{Binding RelativeSource={RelativeSource AncestorType=TreeView}, Path=ActualHeight}">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</TreeView.Template>
The TreeView is filled dynamically:
There are two levels of the TreeViewItem nodes:
And the thumb is moving while in sub items are present only items below:
The Thumb moving:
But when I'm trying to add these items below:
...the thumb is not scrolling, but the ScrollBar area is active:
The template of elements is completely the same, but they differ only in the textblock and the image.
I'm stuck on this and can't understand what's wrong.
Which property of the ScrollViewer may be changing, which leads to this behavior. Here is the link to the full definition of the TreeView: the treeview definition on github.

How to put an outlined textBlock (or any other control) in a TextBox

I am using this outlined textBlock that with the solution proposed by Javier G. works like a charm. I put it in a library so now it's HelperLib:OutlinedTextBlock.
Now I would like to put it in a TextBox.
So what I tried is:
Put the OutlinedTextBox as a child of a TextBlock but that didn't work since it's not accepting it as a child.
Use a RichTextBox and the put it inside a FlowDocument but something went wrong since a got a Runtime error
Use a template but again Runtime error.
If the fact of putting the outlinedTextBox makes it too peculiar I think that this can be rethought as putting anyother control inside a textbox.
I think the solution is close but somehow it still escapes me...
--EDIT--
There is an additiona problem which I have never encountered:
I have named my control otbQuery but it doesn't show up in the code!!! Why???
<TextBox Name="tbxQuery" VerticalAlignment="Center" Grid.Column="3" Width="200" Background="Transparent" CaretBrush="White" HorizontalAlignment="Center" Foreground="White" TextChanged="TextBox_TextChanged" BorderBrush="Gainsboro" BorderThickness="3">
<TextBox.Template>
<ControlTemplate>
<Border BorderBrush="Gainsboro" BorderThickness="3">
<Grid>
-----> <HelperLib:OutlinedTextBlock Name="otbQuery" Margin="1" Fill ="White" Stroke="Red" Text="{Binding Path=Content, ElementName=cp, Mode=OneWay}" VerticalAlignment="Center"/>
<ContentPresenter x:Name="cp" Content="{Binding Text, RelativeSource={RelativeSource TemplatedParent}}" TextBlock.Foreground="Transparent"/>
</Grid>
</Border>
</ControlTemplate>
</TextBox.Template>
</TextBox>
you can see the error here and no valid quick fix is proposed
You will need to override the ControlTemplate of the TextBox control in order to make that happen. Below is a simple example of how to do that, and still have the TextBox.Text property bound to the Text property of the TexBlock.
<TextBox>
<TextBox.Template>
<ControlTemplate>
<Border BorderBrush="Black"
BorderThickness="1">
<Grid>
<TextBlock Margin="1"
Foreground="Red"
Text="{Binding Path=Content, ElementName=cp, Mode=OneWay}"/>
<ContentPresenter x:Name="cp"
Content="{Binding Text, RelativeSource={RelativeSource TemplatedParent}}"
TextBlock.Foreground="Transparent"/>
</Grid>
</Border>
</ControlTemplate>
</TextBox.Template>
</TextBox>
Where I have put a standard TextBlock inside the ControlTemplate, you would put your custom TextBlock control.
EDIT
The above solution works, but it's a serious kludge. Basically, it puts a transparent ContentPresenter on top of the TextBlock . The TextBlock display the text in the manner you want and the ContentPresenter allows you to type in the TextBox.
One problem that still exists is that the cursor bar does not show up when clicking on, or typing in the TextBox. I suspect that problem could be overcome with some more styling done to the template of the TextBox.

How to center Content in a Button Template and keep mouse events in empty area

I am using a Button Template to customize the look and feel of my buttons like so:
<ControlTemplate TargetType="Button">
<Border x:Name="Border" CornerRadius="6" BorderThickness="1">
<ContentPresenter Margin="3" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" ContentSource="Content"/>
</Border>
</ControlTemplate>
I want to center horizontally and vertically the Content, but when I do it the "empty" areas of the Button don't react to the Mouse. When I use Stretch the entire Button behaves alright, but the Content is aligned top-right.
How do I do both?
To make whole area of a Border hit test visible you need to initialise its Background property with some Brush. Can be even Transparent which will have same visual effect as default null.
<Border ... Background="Transparent" />

How to increase the thickness of a `Slider` control

I have a slider control in my grid:
<Slider x:Name="MainSlider"
Margin="659,145,417,146"
Grid.Row="1"
Orientation="Vertical"
SmallChange="1"
RenderTransformOrigin="0.0799999982118607,0.5"/>
I want it to be wider though, so that the whole bar is stretched out.
I've gone through the properties and Width doesn't actually change the thickness of the slider itself, just the frame.
How can I make the actual Slider thicker?
You will probably need to define your own style. You can copy the default style (using Expression Blend for example) and tweak the individual component values.
Use the "Edit Style" option to take a copy of the template and then work on that.
There's more information on MSDN
You can customize the style template of Slider as per your requirement:
http://codingsense.wordpress.com/2010/02/01/customize-a-slider-in-wpf-step-by-step-tutorial/
http://msdn.microsoft.com/en-us/library/vstudio/ms753256%28v=vs.90%29.aspx
If you make a template from a copy of the slider template:
Right-Click Slider->"Edit Template" -> "Edit a Copy"
Then you can change the TrackBackground and PART_SelectionRange WIDTH to whatever you want. They were "4.0" by default for my case:
<Border x:Name="TrackBackground"
Grid.Column="1"
Width="XX.X"
Margin="0,5"
HorizontalAlignment="center"
Background="{StaticResource HorizontalSliderTrackNormalBackground}"
BorderBrush="{StaticResource VerticalSliderTrackNormalBorder}"
BorderThickness="1"
CornerRadius="1">
<Canvas Margin="-1,-6">
<Rectangle x:Name="PART_SelectionRange"
Width="XX.X"
Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"
Stroke="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}"
StrokeThickness="1.0"
Visibility="Hidden" />
</Canvas>
</Border>

Putting ListBox in ScrollViewer: mouse wheel does not work

My mouse wheel does not work when putting a ListBox in a ScrollViewer.
Does the ListBox somehow "steal" this event?
<ScrollViewer VerticalScrollBarVisibility="Auto" Style="{StaticResource myStyle}">
<ListBox>
<ListBoxItem>Test 1</ListBoxItem>
<ListBoxItem>Test 2</ListBoxItem>
<ListBoxItem>Test 3</ListBoxItem>
<ListBoxItem>Test 4</ListBoxItem>
<ListBoxItem>Test 5</ListBoxItem>
<ListBoxItem>Test 6</ListBoxItem>
<ListBoxItem>Test 7</ListBoxItem>
</ListBox>
</ScrollViewer>
Edit: as requested by Joel, added the reason why I did this..
I did this because I don't like what the ListBox's internal ScrollViewer does with my layout. I have a background image, and on top of that a ListBox as shown here:
alt text http://robbertdam.nl/share/1.png
Now when the scrollbar appears, the following happens:
alt text http://robbertdam.nl/share/2.png
I've created a Style for a ScrollViewer that shows the scroll bar on top of the ListBox item's content. In the ListBox item's datatemplate I've reserved some space for the scrollbar to appear.
Thanks,
Robbert Dam
Firstly, I think you need to elaborate on what your limitations are and what you're trying to achieve. Without that, I can only explain why what you're doing isn't working. Somebody may even have a better idea about how to get the result you're after.
If you put ListBox inside a ScrollViewer, then the control template for ListBox still has its own ScrollViewer inside. When the mouse cursor is over the ListBox and you scroll the mousewheel, that event bubbles up until it reaches the ScrollViewer that's part of ListBox. That one handles it by scrolling and marks the event as handled, so then the ScrollViewer you put the ListBox inside of ignores the event.
If you make the ListBox taller and narrower than the outer ScrollViewer, and give it enough items so that the ListBox itself can scroll the items, you'll see 2 vertical scroll bars: 1 in the ListBox, and 1 outside the ListBox for your outer ScrollViewer. When the mouse cursor is inside the ListBox, the ListBox will scroll the items with its internal ScrollViewer, and its Border will stay in place. When the mouse cursor is outside the ListBox and inside the outer ScrollViewer, that ScrollViewer will scroll its contents -- the ListBox -- which you can verify by noting that the ListBox's Border changes position.
If you want an outer ScrollViewer to scroll the entire ListBox control (including the Border and not just the items), you'll need to re-style the ListBox so that it does not have an internal ScrollViewer, but you'll also need to make sure it automatically gets bigger according to its items.
I don't recommend this approach for a couple reasons. It might make sense if there are other controls inside the ScrollViewer along with the ListBox, but your sample does not indicate that. Also, if you're going to have a lot of items in the ListBox, you'll be creating ListBoxItems for every single one, eliminating any advantage that the default, non-re-styled ListBox gives you due to the default VirtualizingStackPanel.
Please let us know what your actual requirements are.
Edit: Ok, now I have a little better idea, with the addition of those images. The effect you're getting is that when there are enough items to scroll and the scrollbar appears, the available area has to shrink a bit horizontally because the ScrollViewer's template uses a Grid. These seem to be your options, in order of lesser-to-better:
Re-style the ListBox to not have a ScrollViewer and use your re-styled ScrollViewer outside the ListBox. You'd then also have to force the ListBox to also be tall enough to show every item in that same Style, and now you've lost UI virtualization. If you're going to be showing hundreds of items in the list, you definitely don't want to lose that.
Re-style the ListBox and set the ControlTemplate to use a ScrollViewer with the style you already created for it that puts the scrollbar over the content rather than in a separate column. This one's ok (ListBox gets to limit its height and use a VirtualizingStackPanel, yay), but as you said, it necessitates awareness of that in your DataTemplate.
Re-style the ScrollViewer to leave space for vertical scrollbar even when it is not visible. Here's what this option looks like:
By default, ScrollViewer uses 2 columns in a Grid equivalent to this:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
So the Width of the scrollbar's column is 0 when the scrollbar is not visible since Width="Auto". To leave space for the scrollbar even when it is hidden, we bind the Width of that column to the Width of the vertical scroll bar:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition
Width="{Binding ElementName=PART_VerticalScrollBar, Path=Width}" />
</Grid.ColumnDefinitions>
So now the ControlTemplate in the custom Style for ScrollViewer might look like this:
<ControlTemplate
TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition
Width="{Binding ElementName=PART_VerticalScrollBar, Path=Width}" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition
Height="Auto" />
</Grid.RowDefinitions>
<ScrollContentPresenter />
<ScrollBar
Grid.Column="1"
Name="PART_VerticalScrollBar"
Value="{TemplateBinding VerticalOffset}"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
<ScrollBar
Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Value="{TemplateBinding HorizontalOffset}"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
</Grid>
</ControlTemplate>
You could even make the content column a fixed size and the scrollbar column Width="*", which might work better in the long run if your image is not stretched. Now the DataTemplate does not have to compenstate for the width of a scrollbar, as it gets a consistent area to use whether the scrollbar is visible or not.
You'll probably want to check out the rest of the example ControlTemplate for ScrollViewer, but those examples are not the default styles. Note that the example puts the vertical scrollbar on the left! Also note the comment at the bottom about ContentScrollPresenter.
I was dealing with the same issue. I set the ListBox.ItemsPanel Property, without any ScrollViewer:
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ListBox>
<ListBox.Template>
<ControlTemplate TargetType="ItemsControl">
<Border>
<ItemsPresenter />
</Border>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<\ListBox>
<\ScrollViewer>
Hope this helps.
see this link for another answer:Scroll in ScrollViewer when mouse over ListBox
Hello, I think you can handle the whole ListBox’s PreviewMouseWheel event. This will also affect individual items as long as you don’t handle each item’s
PreviewMouseWheel and mark the event as handled:
private void ListBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta < 0)
{
scrollViewer1.LineDown();
}
else
{
scrollViewer1.LineUp();
}
}
If you just want to make work the mouse scrolling and don't need a style for the ScrollViewer:
Remove the outer ScrollViewer.
Use the attached properties of the ScrollViewer, which is inside of the ListBox.
See first two lines of this example:
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBoxItem>Test 1</ListBoxItem>
<ListBoxItem>Test 2</ListBoxItem>
<ListBoxItem>Test 3</ListBoxItem>
<ListBoxItem>Test 4</ListBoxItem>
<ListBoxItem>Test 5</ListBoxItem>
<ListBoxItem>Test 6</ListBoxItem>
<ListBoxItem>Test 7</ListBoxItem>
</ListBox>

Categories

Resources