FlowDocumentScrollViewer won't scroll - wpf

I'm trying to find the most expandable way to show a FlowDocument inside a window - just a FlowDocument. I have:
<FlowDocumentScrollViewer x:Name="message" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible">
Then in the constructor for the Window, I set the Document of the viewer to one I load from XAML (in code). The XAML contains:
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="{x:Null}"
FontSize="12" FontFamily="Segoe UI" PagePadding="2">
<BlockUIContainer>
<BlockUIContainer.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</BlockUIContainer.Resources>
<StackPanel MaxWidth="200">
<TextBlock Text="{Binding DefinedWord}" FontWeight="Bold" />
<ListBox ItemsSource="{Binding Definitions}"
Style="{StaticResource InvisibleListBox}" Margin="0"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="false">
...
No matter what I try, the FlowDocumentScrollViewer does not scroll and I can't see the truncated parts of the document. Does it have anything to do with the BlockUIContainer, or am I missing something else?

I eventually got this working by setting the ListBox inside the document to IsHitTestVisible="false", then binding the Width of a text block inside the ListBoxItem template to the ActualWidth of the ListBoxItem.

Flexible Content Display With Flow Documents
SUMMARY: FlowDocumentScrollViewer -
This control displays documents in a
continuous flow with a scrollbar,
similar to Web pages or the Web Layout
in Microsoft Word.

For me alternate option to FlowDocumentScrollViewer worked,
See the example in,
http://msdn.microsoft.com/en-us/library/system.windows.controls.richtextbox.aspx
The other options may be FlowDocumentPageViewer, FlowDocumentReader.

Related

Map control within Listbox

I am trying to display multiple maps within an Listbox.
<Grid Name="MainGrid">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible" >
<WrapPanel Name="wrap" >
<ListBox ItemsSource="{Binding MyList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border Margin="5" MinWidth="500" MinHeight="400" BorderThickness="2" BorderBrush="Black"
Width="200"
Height="200" >
<esri:MapView MouseDown="MapView_MouseDown" MouseUp="MapView_MouseUp" >
<esri:Map >
<esri:ArcGISTiledMapServiceLayer ID="BaseMap" ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
</esri:Map>
</esri:MapView>
</Border>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</WrapPanel>
</ScrollViewer>
</Grid>
The map does not get displayed. Only the logo "esri" gets displayed. But if I remove the listbox, it works fine. What could be the issue?
I am very sure that there are items in my listbox otherwise "esri" would not have appeared.
I have tried Itemscontrol as well but its the same result.
In WPF, we don't put UI elements into collections, we put data objects into collections. Each data item should contain whichever properties are needed to data bind to the UI control that you actually want to display. So your MyList collection should contain a collection of data objects.
Once you have created a custom class to contain these required properties, you will then need to declare a DataTemplate that defines which UI element(s) to display. (See the Data Templating Overview page on MSDN for further information on this).
<ControlTemplate x:Key="YourCustomControlTemplate">
<!-- Define your UI content here -->
</ControlTemplate>
Once you have declared your custom ControlTemplate for your custom data class, you should then put it into a Style for your data object:
<Style TargetType="{x:Type YourXamlPrefix:YourCustomDataClass}">
<Setter Property="Template" Value="{StaticResource YourCustomControlTemplate}" />
</Style>
Note that I have omitted the x:Key directive on this Style... you can add one, but without one (and as long as this Style has been declared in scope of the UI), the Style will be automatically applied to your data objects in the collection.

Keyboard navigation in WPF Grids

Suppose you have a StackPanel, which contains a ScrollViewer which contains another StackPanel with an ItemsControl with a bound ItemsSource. This ItemsSource is bound to a collection of Grids created at runtime. Each Grid contains a label and a textbox/combobox/a few checkboxes that all have a unique TabIndex value within the StackPanel.
Here is the xaml:
<ScrollViewer Name="scrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Name="stackPanel" MinWidth="500" Width="Auto">
<ItemsControl Name="itemsControl" ItemsSource="{Binding ElementName=SomeWindow, Path=GridsCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</ScrollViewer>
I want to simply tab from one control to the next, but only within the controls in the grids in the grids collection. So far I've tried different KeyboardNavigation.TabNavigation settings but without any luck. What is the best way to do this?
Set TabNavigation to KeyboardNavigationMode.Cycle for each container you want to behave like that, so the focus won't escape it as long as you use Tab and Shift+Tab:
KeyboardNavigation.SetTabNavigation(grid1, KeyboardNavigationMode.Cycle);
If you want to change Ctrl+Tab behaviour, use KeyboardNavigation.SetControlTabNavigation.
You can apply an implicit style that disables tabbing for every Control, then you re-enable it for just what you want to be tab-able:
<ScrollViewer Name="scrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ScrollViewer.Resources>
<Style TargetType="Control">
<Setter Property="IsTabStop" Value="False" />
</Style>
</ScrollViewer.Resources>
<StackPanel Name="stackPanel" MinWidth="500" Width="Auto">
<ItemsControl Name="itemsControl"
ItemsSource="{Binding ElementName=SomeWindow, Path=GridsCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</ScrollViewer>
Don't forget to set IsTabStop on your dynamically generated Grids to True

Prevent WPF control from expanding beyond viewable area

I have an ItemsControl in my user control with a scroll viewer around it for when it gets too big (Too big being content is larger than the viewable area of the UserControl). The problem is that the grid that it is all in just keeps expanding so that the scroll viewer never kicks in (unless I specify an exact height for the grid). See code below and thanks in advance.
<UserControl x:Class="BusinessObjectCreationWizard.View.TableSelectionPageView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<GroupBox FontWeight="Bold" Height="300px"
Header="Tables"
Padding="2">
<ScrollViewer>
<ItemsControl FontWeight="Normal"
ItemsSource="{Binding Path=AvailableTables}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Path=DisplayName}"
IsChecked="{Binding Path=IsSelected}"
Margin="2,3.5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</GroupBox>
</UserControl>
This user control is loaded here
<Border Background="White" Grid.Column="1" Grid.Row="0">
<HeaderedContentControl Content="{Binding Path=CurrentPage}"
Header="{Binding Path=CurrentPage.DisplayName}" />
</Border>
I would like to not specify the height.
If you remove the Height from your GroupBox (which, as far as I understand, is what you want to do), then it will fill its container, unless there's a panel upstream that imposes its own sizing rules.
I used this simplified version of your XAML. I removed the template and the binding, and hard-coded some items, to make this stand alone; those changes won't affect the way layout is done.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<GroupBox FontWeight="Bold" Header="Tables" Padding="2">
<ScrollViewer>
<ItemsControl FontWeight="Normal">
<TextBlock>Foo</TextBlock>
<TextBlock>Bar</TextBlock>
<TextBlock>Baz</TextBlock>
</ItemsControl>
</ScrollViewer>
</GroupBox>
</Window>
Run it, and you'll see that the content does indeed size to fit the window, and the scrollbar only enables when the window gets too small to see all three items. I believe this is what you want.
So the problem is most likely one of the parent panels, one you're not showing in your sample XAML. The problem you describe could occur if your GroupBox appears inside a StackPanel:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<StackPanel>
<GroupBox FontWeight="Bold" Header="Tables" Padding="2">
<ScrollViewer>
<ItemsControl FontWeight="Normal">
<TextBlock>Foo</TextBlock>
<TextBlock>Bar</TextBlock>
<TextBlock>Baz</TextBlock>
</ItemsControl>
</ScrollViewer>
</GroupBox>
</StackPanel>
</Window>
Now the GroupBox appears at the top of the Window, sized to exactly fit its contents. If you shrink the Window enough, the GroupBox will be cut off -- because it's sized to fit its content, not its container. This sounds like the problem you're describing.
The reason is that StackPanel asks its children what their ideal height is (based on their content), and uses that height. Without StackPanel (or something similar), the default is to respect the control's VerticalAlignment, and if that's set to the default value of Stretch, then the control is stretched to fill its parent. This means it won't be taller than its parent, which sounds like what you want.
Solution: remove the StackPanel (or whatever else is causing you problems) and use something else. Depending on what you're trying to accomplish, you might have better luck with a DockPanel or a Grid. Hard to tell without knowing more about your layout.
Edit: Okay, it looks like the problem is indeed the HeaderedContentControl parent -- but not directly. HeaderedContentControl isn't a panel, so it doesn't do any layout of its own (and its descendant, GroupBox, doesn't have this same problem). The problem is its default template -- which includes a StackPanel. The good news is, you're free to use a different template, let's say one with a DockPanel instead:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<HeaderedContentControl>
<HeaderedContentControl.Style>
<Style TargetType="{x:Type HeaderedContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedContentControl}">
<DockPanel>
<ContentPresenter ContentSource="Header" DockPanel.Dock="Top"/>
<ContentPresenter/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</HeaderedContentControl.Style>
<GroupBox FontWeight="Bold" Header="Tables" Padding="2">
<ScrollViewer>
<ItemsControl FontWeight="Normal">
<TextBlock>Foo</TextBlock>
<TextBlock>Bar</TextBlock>
<TextBlock>Baz</TextBlock>
</ItemsControl>
</ScrollViewer>
</GroupBox>
</HeaderedContentControl>
</Window>
If you leave off the <HeaderedContentControl.Style> part, this reproduces your problem; but with the style in place, it allows the GroupBox to fill its container, so the ScrollViewer will get a scrollbar when you want it to.
If the previous answer doesn't fix the problem, you could also try binding the Width, Height of your grid to the ActualWidth, ActualHeight of your parent UserControl. Something like:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication.UserControl1"
x:Name="UserControl">
<Grid Height="{Binding ElementName=UserControl, Path=ActualHeight}"
Width="{Binding ElementName=UserControl, Path=ActualWidth}" />
In this case you aren't setting an explicit width and height but you are limiting the Grids width/height to the constraints of the UserControl it sits in.
I had the same issue, after reading this response I replaced all StackPanels with Grids in UserControl. It resolved the Scrollbar issue.
Try removing the grid entirely and setting the HorizontalAlignment and VerticalAlignment directly on the GroupBox. If a layoutpanel has only one child, it's often redundant... this migth be true in your case.
If that doesn't work... what's the parent of your grid control?
Why not just use a listbox instead of an itemscontrol, that has a built in scrollviewer.
They are different. If you do not want to have the items selectable, then don't use a ListBox. It is going to be heavier, and will also have the deselect a selection everytime the user clicks on an entry. Just put the ItemsControl in a ScrollViewer
I had the same problema with ListBox, it wasn't expanding and the scroll viewer didn't appear. I solved it as follows:
<UserControl x:Class="TesteView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid MaxHeight="710">
....
....
<StackPanel>
<ListBox MaxHeight="515"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Path=Teste,Mode=TwoWay}">
....
....
</ListBox>
</StackPanel>
</Grid>
</UserControl>

Difference between Control Template and DataTemplate in WPF

What is difference between a ControlTemplate and a DataTemplate in WPF?
Typically a control is rendered for its own sake, and doesn't reflect underlying data. For example, a Button wouldn't be bound to a business object - it's there purely so it can be clicked on. A ContentControl or ListBox, however, generally appear so that they can present data for the user.
A DataTemplate, therefore, is used to provide visual structure for underlying data, while a ControlTemplate has nothing to do with underlying data and simply provides visual layout for the control itself.
A ControlTemplate will generally only contain TemplateBinding expressions, binding back to the properties on the control itself, while a DataTemplate will contain standard Binding expressions, binding to the properties of its DataContext (the business/domain object or view model).
Very basically a ControlTemplate describes how to display a Control while a DataTemplate describes how to display Data.
For example:
A Label is a control and will include a ControlTemplate which says the Label should be displayed using a Border around some Content (a DataTemplate or another Control).
A Customer class is Data and will be displayed using a DataTemplate which could say to display the Customer type as a StackPanel containing two TextBlocks one showing the Name and the other displaying the phone number. It might be helpful to note that all classes are displayed using DataTemplates, you will just usually use the default template which is a TextBlock with the Text property set to the result of the Object's ToString method.
Troels Larsen has a good explanation on MSDN forum
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="ButtonContentTemplate">
<StackPanel Orientation="Horizontal">
<Grid Height="8" Width="8">
<Path HorizontalAlignment="Stretch"
Margin="0,0,1.8,1.8"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FF000000"
Data="M0.5,5.7 L0.5,0.5 L5.7,0.5"/>
<Path HorizontalAlignment="Stretch"
Margin="2,3,0,0"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FFFFFFFF"
Data="M3.2,7.5 L7.5,7.5 L7.5,3.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1.2,1.4,0.7,0.7"
VerticalAlignment="Stretch" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000"
Data="M2.5,2.5 L7.5,7.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1.7,2.0,1,1"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FF000000"
Data="M3,7.5 L7.5,7.5 L7.5,3.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1,1,1,1"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FFFFFFFF"
Data="M1.5,6.5 L1.5,1 L6.5,1.5"/>
</Grid>
<ContentPresenter Content="{Binding}"/>
</StackPanel>
</DataTemplate>
<ControlTemplate TargetType="Button" x:Key="ButtonControlTemplate">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Window.Resources>
<StackPanel>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="1"/>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="2"/>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="3"/>
</StackPanel>
</Window>
(Templates blatently stolen from
http://msdn.microsoft.com/en-us/library/system.windows.controls.controltemplate.aspx
and
http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.contenttemplate%28VS.95%29.aspx
respectively)
Anyway, the ControlTemplate decides how the Button itself looks, while
the ContentTemplate decides how the Content of the button looks. So
you could bind the content to one of you data classes and have it
present itself however you wanted it.
ControlTemplate: Represents control style.
DataTemplate: Represents data style(How would you like to show your data).
All controls are using default control template that you can override through template property.
For example
Button template is a control template.
Button content template is a data template
<Button VerticalAlignment="Top" >
<Button.Template>
<ControlTemplate >
<Grid>
<Rectangle Fill="Blue" RadiusX="20" RadiusY="20"/>
<Ellipse Fill="Red" />
<ContentPresenter Content="{Binding}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="50">
<TextBlock Text="Name" Margin="5"/>
<TextBox Text="{Binding UserName, Mode=TwoWay}" Margin="5" Width="100"/>
<Button Content="Show Name" Click="OnClickShowName" />
</StackPanel>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
public String UserName
{
get { return userName; }
set
{
userName = value;
this.NotifyPropertyChanged("UserName");
}
}
ControlTemplate - Changing the appearance of element. For example Button can contain image and text
DataTemplate - Representing the underlying data using the elements.
ControlTemplate DEFINES the visual appearance, DataTemplate REPLACES the visual appearance of a data item.
Example: I want to show a button from rectangular to circle form => Control Template.
And if you have complex objects to the control, it just calls and shows ToString(), with DataTemplate you can get various members and display and change their values of the data object.
All of the above answers are great but there is a key difference that was missed. That helps make better decisions about when to use what. It is ItemTemplate property:
DataTemplate is used for elements that provide ItemTemplate property for you to replace its items' content using DataTemplates you define previously according to bound data through a selector that you provide.
But if your control does not provide this luxury for you then you still can use a ContentView that can display its content from predefined ControlTemplate. Interestingly, you can change the ControlTemplate property of your ContentView at runtime. One more thing to note that unlike controls with ItemTemplate property, you cannot have a TemplateSelector for this (ContentView) control. However, you still can create triggers to change the ControlTemplate at runtime.

Is there a way to group RadioButtons generated from the ItemTemplate of an ItemsControl

<DataTemplate x:Key="Genre_DataTemplate">
<RadioButton GroupName="One" Content="{Binding...
</DataTemplate>
Above code is the ItemTemplate of my ItemsControl, I want all the Radiobuttons instantiated should behave as if it is in a group, I know the reason because the generated RadioButtons are not adjacent in the visualtree.
Any solution or workaround to group them together?. GroupName property also doesn't have any effect here.
[Update] I am trying this in Silverlight
The problem is that the RadioButton.GroupName behavior depends on the logical tree to find a common ancestor and effectively scope it's use to that part of the tree, but silverlight's ItemsControl doesn't maintain the logical tree. This means, in your example, the RadioButton's Parent property is always null
I built a simple attached behavior to fix this. It is available here: http://www.dragonshed.org/blog/2009/03/08/radiobuttons-in-a-datatemplate-in-silverlight/
I think the problem is somewhere else in the control tree. Can you post more details?
Here is a sample xaml code that works as expected:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="flickrdata" Source="http://api.flickr.com/services/feeds/photos_public.gne?tags=flower&lang=en-us&format=rss_200">
<XmlDataProvider.XmlNamespaceManager>
<XmlNamespaceMappingCollection>
<XmlNamespaceMapping Prefix="media" Uri="http://search.yahoo.com/mrss/"/>
</XmlNamespaceMappingCollection>
</XmlDataProvider.XmlNamespaceManager>
</XmlDataProvider>
<DataTemplate x:Key="itemTemplate">
<RadioButton GroupName="One">
<Image Width="75" Height="75" Source="{Binding Mode=OneWay, XPath=media:thumbnail/#url}"/>
</RadioButton>
</DataTemplate>
<ControlTemplate x:Key="controlTemplate" TargetType="{x:Type ItemsControl}">
<WrapPanel IsItemsHost="True" Orientation="Horizontal"/>
</ControlTemplate>
</Grid.Resources>
<ItemsControl
Width="375"
ItemsSource="{Binding Mode=Default, Source={StaticResource flickrdata}, XPath=/rss/channel/item}"
ItemTemplate="{StaticResource itemTemplate}"
Template="{StaticResource controlTemplate}">
</ItemsControl>
</Grid>
</Page>
P.S.: In order grouping to work elements radio buttons should have same parent (as they usually have when generated from ItemsControl)

Resources