Flowdocument isnt using the full width/height - wpf

I have a FlowDocument which I want to fill the entire width and height of my window. I have tried using the FlowDocumentPageViewer (no luck) and am now using a DocumentPageView. I still can't get it to dock/fill the entire space; it's just sitting in the middle, in the minimum size it can create (does it make sense?)
Here is my code:
public DocumentPageView GetPage()
{
FlowDocumentPageViewer viewer = new FlowDocumentPageViewer();
StreamReader reader = new StreamReader(location);
string data = reader.ReadToEnd();
reader.Close();
string xamlData = HtmlToXamlConverter.ConvertHtmlToXaml(data, true);
FlowDocument result = (FlowDocument)System.Windows.Markup.XamlReader.Load(new MemoryStream(System.Text.UnicodeEncoding.Default.GetBytes(xamlData)));
viewer.Document = result;
viewer.VerticalAlignment = VerticalAlignment.Center;
viewer.HorizontalAlignment = HorizontalAlignment.Center;
DocumentPageView pageView = new DocumentPageView();
pageView.VerticalAlignment = VerticalAlignment.Center;
pageView.HorizontalAlignment = HorizontalAlignment.Center;
pageView.Stretch = System.Windows.Media.Stretch.Uniform;
pageView.PageNumber = 0;
pageView.StretchDirection = StretchDirection.Both;
pageView.DocumentPaginator = ((IDocumentPaginatorSource)result).DocumentPaginator;
return pageView;
}
Please note that this code contains the combination of my two methods but only the DocumentPageView is currently used. This is the Xaml that is created from my HTML source:
<FlowDocument xml:space="preserve" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Paragraph TextAlignment="center" FontSize="22pt" FontFamily="arial">Test Paragraph</Paragraph>
<Paragraph TextAlignment="center" FontFamily="arial">Test second paragraph</Paragraph>
</FlowDocument>
If I resize the fonts the content is only resized vertically (please note that the stretch direction is set to both). Any ideas?

I had a similar problem with FlowDocumentScrollView, but this solution also seems to work with FlowDocumentPageView:
The FlowDocument is centered because it's PagePadding property is set to auto,auto,auto,auto. Setting PagePadding to 0 fixes this behavior.
<FlowDocumentScrollViewer VerticalScrollBarVisibility="Auto">
<FlowDocument PagePadding="0">
</FlowDocument>
</FlowDocumentScrollViewer>

The following lines are causing your elements to center themselves (which is not the same as stretch):
viewer.VerticalAlignment = VerticalAlignment.Center;
viewer.HorizontalAlignment = HorizontalAlignment.Center;
pageView.VerticalAlignment = VerticalAlignment.Center;
pageView.HorizontalAlignment = HorizontalAlignment.Center;
You can safely remove them, as the default alignment here is Stretch.
If you still want to center the viewer, explicitly define the page size (remember, there are 96 points in an inch, and the Margin and PageSize are set in points):
Width= 96 * 8.5
Height= 96 * 11

Could you specify where and how do you use the result of your GetPage() method? Is it xbap or desktop application?
I'm asking this, because the following document is displayed just perfectly right in Kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<FlowDocumentPageViewer>
<FlowDocument >
<Paragraph TextAlignment="center" FontSize="22pt" FontFamily="arial">Test Paragraph</Paragraph>
<Paragraph TextAlignment="center" FontFamily="arial">Test second paragraph</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
</Grid>
</Page>
PS: If it's a desktop application you can always find who causes problems by Snoop tool, form Pete Blois.

Update: Its a desktop application, the getpage() result is posted into a grid which docks/fills perfectly.
<Window x:Class="GreenWebPlayerWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="Auto" Width="Auto" WindowStyle="None" WindowState="Maximized" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded" Closing="Window_Closing">
<Grid Width="Auto" Height="Auto" Name="TransitionContainer" Background="White" Margin="0">
//here the result from GetPage() method is inserted
</Grid>
</Window>

(this comment is written from another account)
#Anvaka: What i mean by perfectly right is that the document should "dock in container" that is the fonts should resize, it should fill the container in height and width. Now that im thinking about it, that may not seem like a proper behaviour for a flowdocument.
When i put the flow document in the container it is centered in middle of parent container (so far so good). but the parent container is not filling out its parent container so when i zoom or change font size, i would like the documentPageView container to grow in width and height, but remain centered.

Related

WPF C# Show images in stack panel

I am actually solving the issue with stack panel and images I would like to show in it.
What my approach was:
Because of just about 50 pictures to be shown , I just get ti image , make a thumbnail from it , and place that one by one to the stackpanel on left side of my program. (As bitmap)
User is able to click on image and do the action with a image.
Required amount was about 50 images.
New state:
New state is that the required amount of images is about 500 so 10 times more.
The problem is even my thumbnail is too small when I am adding it like :
foreach image in list do :
create thumbnail
add on click or and on touch event to that thumbnail
add that thumbnail to the stack panel
I saw somewhere was used a picture box , not sure if that will help me.
I am thinking about creating lists of pictures links (50 in every ) and put for instance first in a scroll bar and when scrollbar reaches the bottom, load next and when the top reaches load previous list.
The problem is I am reaching with ~ 175 images the maximum of process memory.
I am waiting for garbage collector to do its job after every cycle.
Maybe my approach is not good or should be different so this is why I am asking which approach use in order to solve this problem you suggest.
The source of the photos is simply folder of thumbnails of size 150x150 .
The images are added one by one in certain period of time ( one foto every one second or so )
Thank you
An example of implementation.
Create a collection of images sources.
The collection can contain a string or an Url with a path to the image.
In this case, the image will be created only when it is shown in the Window.
You can also set an instance of ImageSource (or rather classes derived from it).
In this case, the image will be immediately loaded into memory.
Also set the property for specifying the selected image.
using System;
using System.Collections.ObjectModel;
using System.Windows.Media.Imaging;
namespace ImagesViewer
{
public class ImagesViewerViewModel
{
public ObservableCollection<object> ImagesSource { get; }
= new ObservableCollection<object>()
{
"https://miro.medium.com/max/2400/0*UEtwA2ask7vQYW06.png",
new Uri("https://149351115.v2.pressablecdn.com/wp-content/uploads/2021/06/stackoverflow-prosus-blue-orange.png"),
new BitmapImage(new Uri("https://amazinghiring.com/wp-content/uploads/2019/03/jpddcgb89ow.jpg"))
};
public object SelectedImage { get; set; }
}
}
Bind the ListBox source to the created collection.
In the Element Template, specify the Image with the binding to the element and the thumbnail sizes you need.
Assign the selected item to the property for the selected image.
The ListBox has a VirtualizingStackPanel built in by default, so you don't need to take any additional steps to limit using memory.
In the viewing region, set the Image with a binding to the property for the selected image.
<Window x:Class="ImagesViewer.ImagesViewerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ImagesViewer"
mc:Ignorable="d"
Title="ImagesViewerWindow" Height="450" Width="800">
<FrameworkElement.DataContext>
<local:ImagesViewerViewModel/>
</FrameworkElement.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding ImagesSource}"
SelectedItem="{Binding SelectedImage}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Margin="5"
Width="100" Height="100"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Image Grid.Column="1"
Source="{Binding SelectedImage}"/>
</Grid>
</Window>
Ok but scoriling of list of 170 150x150 causing the slowinest of the program as I already mentioned . I did the test already. Can you confirm or refute that please ?
Тестирование.
More than 1200 images in JPG and PNG formats are pre-recorded in the folder "C:\150x150".
The ViewModel gets a list of files in this folder and creates a string array with their paths.
The time for this operation is also recorded.
public class ImagesViewModel
{
public IEnumerable<string> ImagesPaths { get; }
public long ExecutionTimeGetPaths {get;}
public ImagesViewModel()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
ImagesPaths = Directory.GetFiles("C:/150x150")
.Where(path => path.EndsWith(".jpg") || path.EndsWith(".png"))
.ToArray();
stopwatch.Stop();
ExecutionTimeGetPaths = stopwatch.ElapsedMilliseconds;
}
}
In View in the upper right corner displays the time taken to get the paths of all files.
On the left side is a ListBox showing images in size 150x150 for all files.
<Window x:Class="Eee.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Eee"
mc:Ignorable="d"
Title="MainWindow" Height="1000" Width="300">
<Window.DataContext>
<local:ImagesViewModel/>
</Window.DataContext>
<Grid>
<TextBlock Text="{Binding ExecutionTimeGetPaths}"
HorizontalAlignment="Right" VerticalAlignment="Top"
FontSize="30" Margin="10"/>
<ListBox ItemsSource="{Binding ImagesPaths}" HorizontalAlignment="Left">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"
Width="150" Height="150"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Results: the time of obtaining the paths is 12-14 ms, the images are displayed instantly.
There are NO LAGS AT ALL when scrolling.
The same was verified for image files of arbitrary format from 128x128 to 4200x2800.
The result is the same.

Disable ScrollViewer VerticalScrollBarVisible if content fits

I am currently writing my very first Windows Phone (8) App which also is my very first Xaml Application. So it is likely I just did not find the solution for my problem on my own, because I don't know which words to feed google. I tried, but found nothing useful. I found that one, but it does not help:
How to disable "scroll compression" in ScrollViewer
Here is the important part of my XAML:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel VerticalAlignment="Top">
<TextBlock x:Name="InfoText" TextWrapping="Wrap" VerticalAlignment="Top" Text="VersionInfoText"/>
</StackPanel>
</ScrollViewer>
I will programmatically change the content of my TextBlock InfoText. The text might be short enough to fit in completely, or it might be rather long. That is why I embedded it into a ScrollViewer. (By the way, there will be further Controls added to the StackPanel later.)
The ScrollViewer produces these "overbounce" effects if it cannot scroll any further. That is nice if the text is large, but when there is nothing to scroll I don't want this effect to be visilbe.
I tried VerticelScrollBarVisibility="Disable", which successfully disables the effect. Now my question:
Can I automatically (by XAML-Magic) switch between Auto and Disable depending on the Height of my StackPanel and the Hight of my ScrollViewer?
I was hoping Auto would do the trick, but it does not (tested in the VS2013 Emulator WVGA).
In VS2013 setting VerticalScrollBarVisibility="Auto" worked for me.
Try adding this attribute to your ScrollViewer
VerticalScrollMode="Auto"
Also try disabling the HorizontalScrollMode and HorizontalScrollBarVisiblity attributes.
Let me know if this doesn't work. I will then have to make a sample app to see if I can make that work for you. Right now I am just guessing. Try it.
You could dynamically set the SetVerticalScrollBarVisibility to Disabled depends on your InfoText length in your cs code...
if(InfoText.Length() >n)
{
ScrollViewer.SetVerticalScrollBarVisibility(scrollViewer, ScrollBarVisibility.Auto);
}
else
{
ScrollViewer.SetVerticalScrollBarVisibility(scrollViewer, ScrollBarVisibility.Disabled);
}
You can check if TextBlock height is greater than the height of the ScrollViewer.
In xaml:
<ScrollViewer x:Name="TestScrollViewer">
<TextBlock x:Name="InfoText"
Text="Information"
TextWrapping="Wrap"
VerticalAlignment="Top" />
</ScrollViewer>
In cs:
public MainPage()
{
InitializeComponent();
Loaded += (sender, args) =>
{
TestScrollViewer.IsEnabled = InfoText.ActualHeight > TestScrollViewer.ActualHeight;
// OR
TestScrollViewer.VerticalScrollBarVisibility = InfoText.ActualHeight > TestScrollViewer.ActualHeight
? ScrollBarVisibility.Visible
: ScrollBarVisibility.Disabled;
};
}

Autosize inside a WrapPanel?

Need help with a xaml Layout.
I have a Wrapanel with two elements inside. The left one, MainGrid, needs to be fixed at 900 pixels. The second one, AuxillaryDataScrollViewer, I would like to be a minimum of 650 and a maximum of 100% if the WrapPanel wraps it. Is this possible?
Here's what I got so far:
<Window x:Class="scratch.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="768" Width="1024">
<Grid>
<ScrollViewer>
<WrapPanel>
<Grid Width="900" Height="800" Background="Bisque"></Grid>
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Hidden" Width="650">
<Grid Width="1500" Height="700" Background="Tomato"></Grid>
</ScrollViewer>
</WrapPanel>
</ScrollViewer>
</Grid>
</Window>
Thanks!
Edit adding more detail:
Client would like to do data entry and see the calculated results realtime in a panel to the right, but some of the computers in his lab are only capable of 1280pixels width so on those machines he would like the results to wrap to below the data entry form.
Since the requirement is so well defined, you could simply add a SizeChanged handler, and set the second element's width manually per the container's width. If the container is less than 900 + 650, then stretch the second element to 100% of the container.
public MainWindow()
{
SizeChanged += MainWindow_SizeChanged;
}
void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
double firstElementWidth = MainGrid.Width; // 900
double secondElementMinWidth = AuxillaryDataScrollViewer.MinWidth; // 650
double secondElementWidth;
// if wrapped, stretch to the container
if (e.NewSize.Width < firstElementWidth + secondElementMinWidth)
secondElementWidth = e.NewSize.Width;
// otherwise (not wrapped), fill the remainder of the first row
else
secondElementWidth = e.NewSize.Width - firstElementWidth;
}
Obviously this is quick-and-dirty. If you need something more robust, then I suggest writing a custom panel that adheres to the conventions you need. The WrapPanel can't stretch elements to the overall width, but there's no reason you couldn't design a panel that does.

resize text to largest possible size to fit a drawing rect with wraping

this are many similar questions asked to this but no good answer? i use context drawing to draw input text on a certain rect size "720,576", now i need to fit the whole text in that to the maximum font size, while maintaining the rows count?
i tried to create an equation to calculate that but no use. i even tried to loop size till text is clipped but i couldn't test that condition, and i searched for a week to see something similar but no avail!
lastly i tried to use a view box which is near what i want but it wont let the textblock inside to multiline as it always re-size the width contain all text in one line.
here is what i got:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="720" Width="576">
<Viewbox >
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center Text="how are you doining how are you doining how are you doining how are you doining how are you doining how are you doining how are you doining how are you doining how are you doining" " />
</Viewbox>
any help would be appreciated, thanks.
i cannot reproduce the behaviour you describe with just you example copy/pasted into a new project. It does write the text on several lines; Maybe you have a default setter on one object, maybe textbox...
OK very easy : set the width on your TextBox, so your TextBox will wrap. Maybe you wanna have as width the width of the ViewBox (ancestor binding).
I've had the same issue. Here is a fix:
<Viewbox StretchDirection="DownOnly">
<Grid MaxWidth="1000" MaxHeight="100">
<TextBlock TextWrapping="Wrap" FontSize="42" VerticalAlignment="Center" Text="very very very very very very very very very very very very very very very very long line"/>
</Grid>
</Viewbox>
So with extending the text line it will be resized till it is not so small, then it will be wrapped to next line

ScrollViewer Content size change then ScrollToOffset not working

I am using a scrollviewer to display an Image within it.
<ScrollViewer Name="scrollViewer1" Height="500" Width="500" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Padding="0" >
<Image x:Name="img1" Width="100" Source="/MyApp;component/Images/Test.jpg" />
</ScrollViewer>
But when I re-size the image in code, and immediately use the scrollViewer.ScrollToHorizontalOffset() (to reposition the image) it does not work :
img1.Width = 1000;
scrollViewer1.ScrollToHorizontalOffset(500);
I verified the ScrollableWidth property after the img1.Width = 1000 indeed it is not updated yet. So I used the UpdateLayout() right after I resize the image, great now the ScrollableWidth is updated :
img1.Width = 1000;
scrollViewer1.UpdateLayout();
scrollViewer1.ScrollToHorizontalOffset(500);
but the ScrollToHorizontalOffset is still not working. If I do it afterwards, on another user button click it works though. :/
Anyone has a clue?
Nevermind... My error, the example above works. In my project I was basing the ScrollToHorizontalOffset on the img1.ActualWidth which was not updated.
Sorry :/

Resources