CanContentScroll makes the horizontaloffset very large - wpf

I have the following scrollviewer in my app.
<ScrollContentPresenter Grid.Row="0" Grid.RowSpan="1" Grid.Column="0" Grid.ColumnSpan="1"
CanHorizontallyScroll="False" CanVerticallyScroll="False" CanContentScroll="True"
Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" OpacityMask="{x:Null}"
ScrollViewer.VerticalScrollBarVisibility="Disabled" />
<s:SurfaceScrollBar x:Name="PART_HorizontalScrollBar" Grid.Row="1" Height="Auto" MinWidth="30"
MinHeight="30" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch" AutomationProperties.AutomationId="HorizontalScrollBar" Foreground="{x:Null}"
LargeChange="1" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Opacity="0" Orientation="Horizontal"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="Visible"
Value="{Binding HorizontalOffset,
Mode=OneWay,
RelativeSource={RelativeSource TemplatedParent}}" />
The issue is that when I set CanContentControl = True, the scrolling becomes too fast for the user to handle, this is because the horizontal offset becomes too large even for a single flick, Any chance how I can control my horizontaloffset without writing the IScrollInfo interface?
Added Details: This scrollviewer is used in a surfacelistbox as shown below
<ControlTemplate x:Key="SurfaceListBoxHorizontalTemplate" TargetType="{x:Type s:SurfaceListBox}">
<s:SurfaceScrollViewer Background="{TemplateBinding Background}"
HorizontalScrollBarVisibility="Hidden"
Style="{StaticResource HorizontalSurfaceScrollViewerStyle}"
VerticalScrollBarVisibility="Disabled" >
<VirtualizingStackPanel IsItemsHost="True" Orientation="Horizontal" />
</s:SurfaceScrollViewer>
</ControlTemplate>
May be it is because that VirtualizingStackPanel doesnot work when CanContentScroll = True ? My content is a listbox of images.

Related

SmallChange in a XAML ScrollViewer ControlTemplate has no effect

I've created a basic Windows Desktop WPF Application. In the MainWindow, I've added the following as the body of the window:
<ScrollViewer Template="{DynamicResource ScrollViewerControlTemplate1}">
<ScrollViewer.Resources>
<ControlTemplate x:Key="ScrollViewerControlTemplate1" TargetType="{x:Type ScrollViewer}">
<Grid x:Name="Grid" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle x:Name="Corner" Grid.Column="1" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Grid.Row="1"/>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
<ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}" SmallChange="40000"/>
<ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
</Grid>
</ControlTemplate>
</ScrollViewer.Resources>
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="300"/>
<RowDefinition Height="300"/>
<RowDefinition Height="300"/>
<RowDefinition Height="300"/>
<RowDefinition Height="300"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="SteelBlue"/>
<Border Grid.Row="1" Background="Peru"/>
<Border Grid.Row="2" Background="Goldenrod"/>
<Border Grid.Row="3" Background="Tomato"/>
<Border Grid.Row="4" Background="IndianRed"/>
</Grid>
</ScrollViewer>
You'll notice that on PART_VerticalScrollbar, I've set the SmallChange="40000" (an arbitrarily large number). Yet when I click the up/down arrows on the scrollbar, it does the same very small change as it did before I set the SmallChange to anything.
I've read over the documentation a number of times, and can't figure out why this isn't having any effect on the amount that the ScrollViewer scrolls. Any ideas?
Note that I could change the ScrollBar template and change the command these button calls to Scrollbar.PageUpCommand rather than Scrollbar.LineUpCommand, but ultimately I'd like to have finer control over the scrolling than a full page.
The reason for this is a special logic implemented in the ScrollViewer and in the ScrollBar.
The ScrollBar.SmallChange property will be only considered for scrolling if the scroll bar is stand-alone. That means, when it is outside of a ScrollViewer.
If you look at the ScrollViewer.OnApplyTemplate method, you will notice the following:
public override void OnApplyTemplate()
{
// ...
ScrollBar scrollBar = GetTemplateChild(HorizontalScrollBarTemplateName) as ScrollBar;
if (scrollBar != null)
scrollBar.IsStandalone = false;
// Same for the vertical scroll bar
// ...
}
If a ScrollViewer finds scroll bars inside of it, it sets their IsStandalone (internal) properties to false, which disables the scroll command handing of the scroll bars. Instead, the ScrollViewer takes over the scroll command handing, but it ignores some ScrollBar's properties, including the SmallChange property.
TL;DR This won't work for the scroll bars inside of a ScrollViewer. You can change your template so use two "external" scroll bars. But then, you will need to connect those scroll bars with the ScrollViewer manually.
I suspect that your custom control template isn't being used because of the way you are referencing it. I would change the XAML to this:
<ScrollViewer>
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid ...>
...
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
... ScrollViewer content goes here
</ScrollViewer>
Basically, set the control's template directly, rather than using a dynamic resource.

Rendering templates preformances

I created a propertyGrid like.
I used an Item control which uses a viewmodel object.
The VM object has the property to be display and its relevant DataTemplates.
Everything wosrk fine. My Property grid actually act like the VS property grid
My problem is that every time the use changes the selected object (which lead to changes in the property grid) its took to much time (depends on the amount of the selected object properties). I figured out that the reason for the bad performances is the templates loading and rendering.
so I thought that I may solve this issues by creating real controls for each object, and not just uses templates. (Create buttons and text box for each property) this will solve the loading time, I hope..
1- is there any way to creates real controls (in code) using data templates?
2- is there any other way to improve the performances of my Property grid?
The main code for the propGrid is attached to this post
Thanks, Leon
CODE:
<DataTemplate x:Key="gridItemsControl" >
<Grid Visibility="{Binding Visibility}">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="60" MaxWidth="350" Width="{Binding Source={StaticResource firstCulWidth},Path=Width,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource widthToGridLenConverter}}"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderBrush="#ff333333" BorderThickness="0.5" Grid.ColumnSpan="2"
Visibility ="{Binding IsCategoryItem,Converter={StaticResource isCategoryItemToVisibilityConverter},ConverterParameter=Category}">
<StackPanel Orientation="Horizontal" Background="#FFA9BFD4" Height="25">
<Expander Template="{StaticResource SimpleExpanderTemp}" ExpandDirection="Left" IsExpanded="{Binding IsExpanded, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="3,0,5,0"/>
<Label Content="{Binding Path=CategoryName,Converter={StaticResource propertyNameToDiplayNameConverter}}" FontSize="12" Foreground="White" VerticalAlignment="Top" />
</StackPanel>
</Border>
<Border Grid.Column="0" BorderBrush="#ff333333" BorderThickness="0.5"
Visibility ="{Binding IsCategoryItem,Converter={StaticResource isCategoryItemToVisibilityConverter}}">
<Label Margin="5,0,0,0" Content="{Binding Path=DisplayName,Converter={StaticResource propertyNameToDiplayNameConverter}}"/>
</Border>
<GridSplitter Grid.Row="0" Grid.Column="0" Visibility ="{Binding IsCategoryItem,Converter={StaticResource isCategoryItemToVisibilityConverter}}" HorizontalAlignment="Right" Width="4" Background="Transparent"/>
<Border Grid.Column="1" BorderBrush="#ff333333" BorderThickness="0.5"
Visibility ="{Binding IsCategoryItem,Converter={StaticResource isCategoryItemToVisibilityConverter}}">
<ContentPresenter Grid.Column="1" Margin="10,1,10,1" HorizontalAlignment="Left"
ContentTemplate="{Binding Path=InlineTemplate}" />
</Border>
</Grid>
</DataTemplate>
Update: Here is the container
<ItemsControl Name="propsDataGrid" ItemsSource="{Binding Properties}" ItemTemplate ="{StaticResource gridItemsControl}">
<ItemsControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Close all expanders" Click="MenuItem_Click" Visibility="{Binding IsAlphaBeticSort,Converter={StaticResource boolToVisConverter},ConverterParameter=VisForFalse}"></MenuItem>
<MenuItem Header="Expand all" Name="mnExpandeAll" Click="mnExpandeAll_Click" Visibility="{Binding IsAlphaBeticSort,Converter={StaticResource boolToVisConverter},ConverterParameter=VisForFalse}"></MenuItem>
</ContextMenu>
</ItemsControl.ContextMenu>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!--<ItemsControl.ItemTemplate>
<DataTemplate >
<Grid Visibility="{Binding Visibility}">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="60" MaxWidth="350" Width="{Binding Source={StaticResource firstCulWidth},Path=Width,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource widthToGridLenConverter}}"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderBrush="#ff333333" BorderThickness="0.5" Grid.ColumnSpan="2"
Visibility ="{Binding IsCategoryItem,Converter={StaticResource isCategoryItemToVisibilityConverter},ConverterParameter=Category}">
<StackPanel Orientation="Horizontal" Background="#FFA9BFD4" Height="25">
<Expander Template="{StaticResource SimpleExpanderTemp}" ExpandDirection="Left" IsExpanded="{Binding IsExpanded, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="3,0,5,0"/>
<Label Content="{Binding Path=CategoryName,Converter={StaticResource propertyNameToDiplayNameConverter}}" FontSize="12" Foreground="White" VerticalAlignment="Top" />
</StackPanel>
</Border>
<Border Grid.Column="0" BorderBrush="#ff333333" BorderThickness="0.5"
Visibility ="{Binding IsCategoryItem,Converter={StaticResource isCategoryItemToVisibilityConverter}}">
<Label Margin="5,0,0,0" Content="{Binding Path=DisplayName,Converter={StaticResource propertyNameToDiplayNameConverter}}"/>
</Border>
<GridSplitter Grid.Row="0" Grid.Column="0" Visibility ="{Binding IsCategoryItem,Converter={StaticResource isCategoryItemToVisibilityConverter}}" HorizontalAlignment="Right" Width="4" Background="Transparent"/>
<Border Grid.Column="1" BorderBrush="#ff333333" BorderThickness="0.5"
Visibility ="{Binding IsCategoryItem,Converter={StaticResource isCategoryItemToVisibilityConverter}}">
<ContentPresenter Grid.Column="1" Margin="10,1,10,1" HorizontalAlignment="Left"
ContentTemplate="{Binding Path=InlineTemplate}" />
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>-->
</ItemsControl>
DataTemplates create "real controls" there is no gain in doing something manually which is done automatically using templates, the only thing you should worry about is virtualization (so that the controls for properties not in view are not created) and how your templates are wired up so that their creation is not triggered needlessly.
(By the way, the way you create the grid, setting its width, looks like it might be redundant, you probably can just share the size.)
To make an ItemsControl virtualize the items you need to:
Set the ItemsPanel to a VirtualizingStackPanel
Have a control template which contains a ScrollViewer around the ItemsPresenter where the VirtualizingStackPanel will be.
Set ScrollViewer.CanContentScroll to true to enable scrolling by item which allows for virtualization.
e.g.
<ItemsControl ItemsSource="{Binding Items}"
ScrollViewer.CanContentScroll="True">
<ItemsControl.Template>
<ControlTemplate>
<Border Name="Bd" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true"
Padding="1">
<ScrollViewer Padding="{TemplateBinding Padding}" Focusable="false">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- ... -->
</ItemsControl>
If this is still too slow you could make the whole ItemsControl part of a template which applies per type as presumably the contents of this grid are dependent on the type of the item, thus a different grid should only be created if the item-type changes, also you might be able to cache the resulting templates as well (i never tried doing that though).

Changing viewport of datagrid

I need to change viewport of datagrid to maximum so all rows are propagated in constructor. So I used Scrollview with row height set to auto.
<ScrollViewer>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<DataGrid>
</DataGrid>
</Grid>
</ScrollViewer>
This propagates all controls but now when I use scrollbar it also moves header row. I need that the scrollbar will effect only datagrid.
I dont understand this statement
... need to change viewport of datagrid to maximum so all rows are
propagated in constructor. So I used Scrollview with row height set to
auto...
... where is the Viewport setting in the code? Also what is this constructor? Your terminologies are confusing....
However I can assume what you want is the datagrid to fully render its rows (without extra space below rows) and occupy that entriely over the grid panel. But because you have used a scroll viewer abone grid, it will scroll datagrid headers as well.
If you use "Snoop" you will find that wpf datagrid has a scroll viewer as its visual child and it has a Grid panel in its own template, there the ScrollContentPresenter is under a Grid.Row which has RowDefinition that has Height as asterick (*).
Using visual children extraction method given below, accesss that Grid descendent and change its height to auto.
(GetVisualChild<Grid>(myDataGrid)).RowDefintions[1].Height="Auto"
Method to snoop through all children of a parent...
static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null) child = GetVisualChild<T>(v);
if (child != null) break;
}
return child;
}
The XAML way
Override the dataGrid Control template...
<Style TargetType="{x:Type DataGrid}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True"
Padding="{TemplateBinding Padding}">
<ScrollViewer Focusable="false"
Name="DG_ScrollViewer">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <!--This changed to Auto from '*'-->
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!--Left Column Header Corner -->
<Button Command="{x:Static dg:DataGrid.SelectAllCommand}"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type dg:DataGrid}}, Path=CellsPanelHorizontalOffset}"
Template="{StaticResource SelectAllButtonTemplate}"
Focusable="false"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type dg:DataGrid}}, Path=HeadersVisibility, Converter={x:Static dg:DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static dg:DataGridHeadersVisibility.All}}" />
<!--Column Headers-->
<dgp:DataGridColumnHeadersPresenter Grid.Column="1"
Name="PART_ColumnHeadersPresenter"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type dg:DataGrid}}, Path=HeadersVisibility, Converter={x:Static dg:DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static dg:DataGridHeadersVisibility.Column}}"/>
<!--DataGrid content-->
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />
<ScrollBar Grid.Row="1" Grid.Column="2" Name="PART_VerticalScrollBar"
Orientation="Vertical"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type dg:DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar Grid.Column="1"
Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

what the name for the item in the green circle

what's the element name in the green circle? Whta's the event corresponding to click this element?
Interestingly, this part of the DataGrid is no-man's-land - it doesn't even have an official name, let alone a behaviour or a template. In order to handle events related to this area, see here or here.
I call it the 'select all' button. However, it doesn't have an official name. It also does not have any style properties exposed. For a simple method to style it via attached properties, see the following:
http://www.scottlogic.co.uk/blog/colin/2009/02/styling-hard-to-reach-elements-in-control-templates-with-attached-behaviours/
Colin E.
As others have stated, it's the "Select All" Button. Clicking it will select everything in the DataGrid if SelectionMode is set to Extended.
The "Select All" Button is part of the DataGrid Template. Or actually, it's part of the ScrollViewer Template that is part of the DataGrid Template so it's nested pretty deep. The ControlTemplate looks like this. From here you can do anything you want with the SelectAll Button, disable it, change the Background etc.
<Style TargetType="{x:Type DataGrid}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Here it is -->
<Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
<Grid Grid.Column="1" Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If you want to disable the selectall button you can also do like this:
//Disable select all button
datagrid.CommandBindings.Add(new CommandBinding(DataGrid.SelectAllCommand, delegate { }, (s, a) => { if (a.OriginalSource is Button) ((Button)a.OriginalSource).IsEnabled = false; }));
as a workaround.
This can also be used to wire other things up.
The "problem" with re-templating is that you have to take all the themes into account... tedious :)
In at least one example I found, clicking the gray triangle in the corner causes all rows to be selected.
But this is not a built-in feature of this control as far as I know. It is part of a custom template.
See this example:
http://www.dotnetspark.com/kb/2941-styling-wpf-datagrid.aspx
If you download the sample, and search the Resources/DataGridCustomization.xaml file for "SelectAll", you'll find the part of the template that contains this feature.

Disabling text selection in DocumentViewer

Simple question. How do you disable the text selection of DocumentViewer in WPF? This is the feature where an XPS document is displayed by the viewer and then text can be highlighted via mouse. The highlighted text can also be copied but I have already disabled this. I just don't know how to disable the highlighting.
Thanks!
you may use IsFocusable=false. But search box will be disabled too...
We have solved this by overriding the ControlTemplate of the ScrollViewer embedded in the DocumentViewer control. Insert the Style below in "Window.Resources":
<Style TargetType="{x:Type ScrollViewer}" x:Key="CustomScrollPresenter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid Background="{TemplateBinding Panel.Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Rectangle Grid.Column="1" Grid.Row="1" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
<ScrollContentPresenter
PreviewMouseLeftButtonDown="ScrollContentPresenter_PreviewMouseLeftButtonDown"
Grid.Column="0"
Grid.Row="0"
Margin="{TemplateBinding Control.Padding}"
Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}" />
<ScrollBar
x:Name="PART_VerticalScrollBar"
Grid.Column="1"
Grid.Row="0"
Minimum="0"
Maximum="{TemplateBinding ScrollViewer.ScrollableHeight}"
ViewportSize="{TemplateBinding ScrollViewer.ViewportHeight}"
Value="{Binding Path=VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Visibility="{TemplateBinding ScrollViewer.ComputedVerticalScrollBarVisibility}"
Cursor="Arrow" AutomationProperties.AutomationId="VerticalScrollBar" />
<ScrollBar
x:Name="PART_HorizontalScrollBar"
Orientation="Horizontal" Grid.Column="0" Grid.Row="1" Minimum="0"
Maximum="{TemplateBinding ScrollViewer.ScrollableWidth}" ViewportSize="{TemplateBinding ScrollViewer.ViewportWidth}" Value="{Binding Path=HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" Visibility="{TemplateBinding ScrollViewer.ComputedHorizontalScrollBarVisibility}" Cursor="Arrow" AutomationProperties.AutomationId="HorizontalScrollBar" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then override the Style of ScrollViewer with it in the ControlTemplate for DocumentViewer:
<Style
x:Key="MyDVStyleExtend"
BasedOn="{StaticResource {x:Type DocumentViewer}}"
TargetType="{x:Type DocumentViewer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DocumentViewer">
<Border BorderThickness="2,2,2,2"
BorderBrush="SlateBlue" Focusable="False">
<Grid Background="{StaticResource GridBackground}"
KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition Width ="*"/>
</Grid.ColumnDefinitions>
<ScrollViewer Style="{StaticResource CustomScrollPresenter}" Grid.Column ="0"
CanContentScroll="True"
HorizontalScrollBarVisibility="Auto"
x:Name="PART_ContentHost"
IsTabStop="True"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then create a function for the "PreviewMouseLeftButtonDown="ScrollContentPresenter_PreviewMouseLeftButtonDown"" attribute stated in the CustomScrollPresenter style.
private void ScrollContentPresenter_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
Another way would be to add e.g. a dockpanel:
<DockPanel Name="pnlTouchTaker"
VerticalAlignment="Bottom" HorizontalAlignment="Left"
Background="Transparent">
</DockPanel>
lying "above" the documentviewer and set it´s width and height to the actual width and height of the scrollviewer content in e.g. page loading event.
You might have to add additional logic if using zoom options and the horizontal toolbar becomes visible.
Implement the following code in xaml.cs part (DocumentViewerInstance x:Name of your DocumentViewer in your xaml.)
DocumentViewerInstance.GetType().GetProperty("IsSelectionEnabled", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(DocumentViewerInstance, false, null);
You can use the IsFocusable=false or IsHitTestVisible = false or handle any preview event (for example in accepted answer) for disable selection but the hyperlinks won't work! If you set IsSelectionEnabled = false, the selection will be disabled but hyperlinks will work too. (Warning! IsSelectionEnabled can be changed for true value after you set false, so you should check the value often.)

Resources