Document belongs to another FlowDocumentScrollViewer already exception when using scrollbar - wpf

I have a ListView of FlowDocuments:
<ListView ItemsSource="{Binding Messages}">
<ListView.ItemTemplate>
<DataTemplate>
<FlowDocumentScrollViewer Document="{Binding Message}"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Left" Margin="-10,0,0,0"
VerticalContentAlignment="Top"></FlowDocumentScrollViewer>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And whenever I use the scrollbar that gets shown after a certain amount of items in the listview to scroll back up, an External Code Exception gets thrown:
I clicked "Show External Code" to reveal the details.

Related

Listbox reversed items order

I've spend couple of hours trying to reverse the order of listbox (bottom to top) as described on the picture:
That means that newly added items should be inserted at the top of the listbox. I do not understand that something so trivial can be so difficult to implement in wpf...
I do not want to use transient effects on panel and items itself because it causes strange behavior on scrollviewer. I can not use some sort definitions on ICollectionView because I want to use a data virtualization which provides ordered data and I have to add them as is.
This is my Listbox (ListView) definition:
<ListView ItemsSource="{Binding Collection}"
VirtualizingPanel.VirtualizationMode="Recycling"
VirtualizingPanel.ScrollUnit="Pixel"
ScrollViewer.IsDeferredScrollingEnabled="True"
IsSynchronizedWithCurrentItem="True"> <!--To manage scrolling from view model using ICollectionView.ScrollTo()-->
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
<!--To auto scroll to bottom (via calling ICollectionView.ScrollToBottom()-->
<i:Interaction.Behaviors>
<Behaviors:ScrollIntoCurrentItemBehavior />
</i:Interaction.Behaviors>
<!--To pin listbox panel to bottom-->
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VerticalAlignment="Bottom"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
Is there any acceptable solution for that? I really appreciate any help! thanks

WPF DataGrid RowDetailsTemplate with Multiple Images (MVVM)

Goal
To add multiple images in a DataGrid's RowDetails template using the MVVM standards.
Background
I have an inspection window with a DataGrid designed to hold a damaged item's description along with the initials of the inspector. What is more, this DataGrid's RowDetailsTemplate needs to hold the pictures that the inspector took of the damaged item (so there might be more than one picture of the damaged item).
Problem
I have a DamagedWindow.xaml designed to create my DamagedItem entries. It looks like this:
DataGrid (.XAML)
<DataGrid ItemsSource="{Binding Pictures}" SelectedItem="{Binding SelectedPicture}" AutoGenerateColumns="False" Grid.Column="1" Grid.Row="2" Margin="5" HorizontalAlignment="Stretch" Name="DataGrid1" VerticalAlignment="Stretch" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Titre" Binding="{Binding Name}" Width="*" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Image Height="100" Source="{Binding Path}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
As you can see, my RowDetails template works fine in this DataGrid. I have a class named PicturesList which inherits an ObservableCollection Of my PictureModel(Name, Description, Path).
The text boxes that you see above the DataGrid are properties of my DamagedItemModel (Description, Initiales, PicturesList). So when the user clicks on the Accept (Checkmark) button, the DamagedItem is added to a DamagedItemsList which is then set as the ItemSource of the DataGrid from my MainWindow:
DataGrid (.XAML)
<DataGrid ItemsSource="{Binding Path=DamagedItems}" SelectedItem="{Binding Path=SelectedDamagedItem}" AutoGenerateColumns="False" Name="DataGrid1" Height="250" Margin="3" IsEnabled="True" CanUserAddRows="False" FontSize="16">
<DataGrid.Columns>
<DataGridTextColumn Header="Description" Width="*" Binding="{Binding Description}"/>
<DataGridTextColumn Header="Initiales" Width="70" Binding="{Binding Initiales}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Image Height="100" Source="{Binding Pictures.Path}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
Here when I select the row, I get an empty RowDetailsTemplate result ... Even though my object contains my images. See below for more details:
So here's my question, is it possible to add multiple images to a RowDetailsTemplate in a DataGrid while following MVVM standards? If it is, what am I doing wrong?
You can't bind that way. you need to do it like this:
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Pictures}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Height="100" Source="{Binding Path}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
The reason your method was not working is that the Binding source is always one object which is set by Binding Path, and your Binding Path was Pictures.Path which leads to nothing because Pictures object does not have Path, it's its Items which have Path.
In general, Whenever you find yourself dealing with a collection of some kind think of a control which is suitable for showing a collection, like ListBox, DataGrid or the best of all ItemsControl.
Anything that goes inside ItemTemplate of these controls, have their DataContext automatically set to the correspondent item, so you don't have to worry about it. All you have to do is to set the ItemsSource to your collection and set the Binding Paths of things inside to the properties of the Type of that collection, So that it knows where to look for data for each item.
In this code you can think of it this way, Like you have some StackPanels, first one has : Image Source="{Binding Pictures(0).Path}", seconds one has Image Source="{Binding Pictures(1).Path}" and so on. this way all Binding Paths point to an object.

ListView with VirtualizedWrapPanel without scrolling

I have fixed a couple of lines in this implementation of a VirtualizedWrapPanel.
Ok, the window in which I have put the ListView with the VirtualizedWrapPanel as the ListView's ItemsPanel shoud not be scrollable. Instead of scrolling, the user will initiate something like pages change by clicking the button. So I'll should somehow bring into view "the next portion of items" as a response to the button click.
Here is the ListView which I have described:
<ListView x:Name="StationsListView"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
BorderThickness="0"
DataContext="{StaticResource ViewModelKey}"
SelectionMode="Extended"
Grid.Row="1" ItemsSource="{Binding Stations}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<common:VirtualizingWrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Button Style="{DynamicResource DestinationButtonStyle}">
<TextBlock Text="{Binding FullName}"
Style="{DynamicResource DestinationStationTextBlockStyle}"
TextTrimming="CharacterEllipsis" />
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
So, how can I scroll to the next portion of items manually?
After looking through the code example from your link, I'm not convinced of the author's knowledge on the subject of virtualization. The code seems to be more complicated and less efficient than it needs to be.
I have a WPF book that explains virtualisation very well with examples and you're in luck, because someone has published it online. I'm not sure if it is legal, so I can't verify how long this link will work, but it does now: Take a look at chapter 8 in Control Development Unleashed online.

WPF - Binding large amount of data in Listbox

I am creating a search page for books. There is lots of data in the database. If the data size is more than 2000 the application hangs. ItemsSource of the listbox having the data but something wrong is happening behind.
Code
<ListBox Grid.Column="1"
x:Name="lbResult"
ItemsSource="{Binding}"
SelectionChanged="lbResult_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Width="320">
<TextBlock Margin="10">
<InlineUIContainer>
<TextBlock Foreground="DarkKhaki" Text="{Binding Title}"/>
</InlineUIContainer>
<Run Text=" "/><LineBreak/>
<InlineUIContainer>
<TextBlock Text=" By "/>
</InlineUIContainer>
<Run Text=" "/>
<InlineUIContainer>
<TextBlock Text="{Binding Author}"/>
</InlineUIContainer>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
The application is apparently "hanging" because the data load is happening on the UI thread.
You should consider a different model that enables you to load the data in another thread and update the UI periodically or as and when new data arrives.
You can use an ObservableCollection for this.
The background loading thread updates the collection and this fires an event out to the UI thread indicating that an update is required.
There's an example of how to do this on GALA Soft
You create a property (read only in this case) for the collection:
private ObservableCollection<MyDataItem> dataItems;
public ObservableCollection<MyDataItem> DataItems
{
get { return dataItems; }
}
Then in your XAML:
<ListBox ItemsSource="{Binding ElementName=mainWindow, Path=DataItems}"
...>
</ListBox>
One problem that you may have is that you are using a non-virtualizing type of panel (WrapPanel) in your ItemsPanelTemplate. What this means is that all 2000 data items will be loaded even if only a fraction of those are visible. By default ListBox uses a VirtualizingStackPanel as its panel which, as the name indicates, provides virtualisation, so it will only load the visible data set elements.
So an easy fix in terms of performance would be to dispense with the WrapPanel and us a virtualizing panel instead, however this would obviously change the appearance.
If you particularly want a WrapPanel then there is no virtualised equivalent provided by WPF, but there are implementations out there, such as http://virtualwrappanel.codeplex.com/.
Try using a ListView instead, I had the same problem. Now I can load over 7000 items in an instant.
Like this:
<StackPanel Grid.Row="1" Grid.Column="0">
<ListView
Height="100"
Name="lstPlayerList">
<ListView.View>
<GridView>
<GridViewColumn
Width="100"
Header="LastName"
DisplayMemberBinding="{Binding LastName}">
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>

Why might a silverlight ListBox on Windows Phone not allow me scroll all the way down to the bottom?

I have a ListBox in a grid that gets databound when the page loads... pretty straightforward. The problem I'm having is that, after the box is databound, I can scroll... but not all the way to the bottom of the list. It stops an item or two short and won't let me scroll anymore. Here's the listbox XAML:
<Grid x:Name="ContentGrid" Grid.Row="2">
<ListBox x:Name="lbFeed" ItemsSource="{Binding Items}" SelectionChanged="lbFeed_SelectionChanged" VerticalAlignment="Top" Width="480">
<ListBox.ItemTemplate>
<DataTemplate x:Key="MyDataTemplate">
<StackPanel Orientation="Vertical" Width="430">
<TextBlock Text="Some text" TextAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I can post more code, but I'm still getting my feet wet in XAML and I'm not sure what might be causing this. If you need more context, let me know and I'll add it here.
This is a known issue at this stage of ctp release if you happen to have rows that are not fixed height. If this is the case you will likely notice your scrolling is a bit jittery too. Fix the height of your content for now if this is the case for your app and all is resolved.

Resources