XPS export from WPF - only one image is exported - c#

I want to export the content from WPF app (C#,MVVM) to XPS.
I have a bunch of objects and every object contains an image (type=BitmapFrame), which is displayed using source property:
<Image Source="{Binding BusinessUnit.Picture}" />
All those objects are placed on a control called GraphCanvas. Every picture is loaded and it is properly displayed on a screen.
When using the export code:
using (var package = Package.Open(saveFileDialog.FileName, FileMode.Create))
{
var xpsDocument = new XpsDocument(package);
var writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(GraphCanvas.ExportCanvas);
xpsDocument.Close();
}
everything is exported properly except of images. Only one image is exported (and it's available in resources folder when browsing through XPS structure) and this one image is used as a substitution for every other image that should be exported.
What might be a reason that all the other images are not exported?

I've faced similar issue when printing multiple pages, and eventually I had to iterate on each Item in page and do this:
fwElement.Arrange(new Rect(new Size(fwElement.ActualWidth, fwElement.ActualHeight)));
Since you have only single element, this might work for you:
GraphCanvas.ExportCanvas.Measure(GraphCanvas.ExportCanvas.RenderSize);
GraphCanvas.ExportCanvas.Arrange(new Rect(new Size(GraphCanvas.ExportCanvas.ActualWidth, GraphCanvas.ExportCanvas.ActualHeight)));
writer.Write(GraphCanvas.ExportCanvas);

I know this question is old, but I had the same issue in my WPF MVVM (I'm using DevExpress MVVM) app, and my resolution may help others in the future.
I had a page of several images, and when printing the 1st image on the page replaced all the other images! I'm not sure why it did this.
Each of my image UI controls was bound to a byte array, and the images displayed perfectly in the app. I resolved the print issue by converting my byte arrays to a BitmapImage to which each image UI control was bound. All images print correctly now.
My View XAML:
<Image Grid.Row="0" Grid.Column="0" Source="{Binding Bitmap[0]}" />
<Image Grid.Row="0" Grid.Column="1" Source="{Binding Bitmap[1]}" />
<Image Grid.Row="0" Grid.Column="2" Source="{Binding Bitmap[2]}" />
<Image Grid.Row="0" Grid.Column="3" Source="{Binding Bitmap[3]}" />
My ViewModel bound properties:
private List<BitmapImage> bitmap;
public virtual List<BitmapImage> Bitmap
{
get { return bitmap; }
set { bitmap= value; }
}
My code for printing each child view in a TabControl (some tabs contained other UI objects other than images):
public void PrintDocument(TabControl control)
{
PrintDocumentImageableArea area = null;
XpsDocumentWriter dw = PrintQueue.CreateXpsDocumentWriter(ref area);
SerializerWriterCollator c = dw.CreateVisualsCollator();
foreach (var tabitem in ((TabControl)control).Items)
{
UIElement childVisual1 = (UIElement)((TabItem)tabitem).Content;
var outputSize = new Size(area.MediaSizeHeight, area.MediaSizeWidth);
((UIElement)childVisual1).Measure(outputSize);
((UIElement)childVisual1).Arrange(new Rect(outputSize));
((UIElement)childVisual1).UpdateLayout();
if (c != null) c.Write(childVisual1);
}
if (c != null) c.EndBatchWrite();
}
This article helped with WPF printing with XPS

Related

Image control doesn't get rendered

I am trying to create a WPF application with multiple small editors. One of these editors requires to load two images, enter a name in a TextBox and hit a save button.
In the code this does work flawless. The files are saved in a model and the image can be loaded. Before hitting the save button both of the images are actually shown in the editor. However after reopening (for editing) only one image is rendered.
I tested a bit around and found out that always the first image doesn't get rendered while the second does.
For example in the XAML it looks like this:
<Image Name="BackgroundImage" Grid.Row="1" Grid.Column="0" Source="{Binding Path=Background}" Width="120" Height="90"/>
<Image Name="ForegroundImage" Grid.Row="2" Grid.Column="0" Source="{Binding Path=Foreground}" Width="120" Height="90"/>
Here BackgroundImage doesn't get rendered, even though the property Background of the model has loaded the image successfully. If I were to swap these XAML Tags, meaning putting the ForegroundImage control above the BackgroundImage, then ForegroundImage doesn't get rendered while BackgroundImage does. Even if I don't change anything else like the Grid.Row or Column.
Then I tried to load the images in the code behind in the Loaded event handler of the window:
private void LocationEditor_OnLoaded(object sender, RoutedEventArgs e)
{
BackgroundImage.Source = ((Location)DataContext).Background;
ForegroundImage.Source = ((Location)DataContext).Foreground;
}
The same applies to this situation. Whichever line is executed first, won't be rendered in the Window.
In case it'll help, here's the code of the Background property (Foreground is built the same):
[JsonIgnore]
public BitmapImage Background
{
get
{
if (!string.IsNullOrWhiteSpace(BackgroundFile))
{
SetFree();
SetImage();
}
else
_background = null;
return _background;
}
}
The SetFree() method frees up memory resources if the image isn't needed anymore. This occurs when the window closes or whenever the BitmapImage is needed. (It'll reload the image each time in case the file of the image has changed.)
The SetImage() method does just one simple thing: Loading the image of the BackgroundFile image file and saves it in the _background field.
I don't quite know what the problem could be. I've tried out a few things but I don't work often with images while coding.
There must be something wrong with your SetFree() or SetImage() methods.
Fortunately you don't need the Background and Foreground properties in your view model at all, because WPF provides built-in automatic type conversion from string, Uri and byte[] to ImageSource. You can hence directly bind the Image's Source properties to the appropriate path properties in the view model:
<Image ... Source="{Binding BackgroundFile}"/>
<Image ... Source="{Binding ForegroundFile}"/>
For completeness, if you still wanted to have these properties, i'd suggest a simple implementation like shown below. Built-in image caching will take care that the file is not decoded more often than necessary:
public ImageSource Background
{
get
{
if (BackgroundFile != null)
{
try
{
return new BitmapImage(new Uri(BackgroundFile));
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
return null;
}
}

How to set the background of a WPF grid to an image in local folder?

I'm developing a small WPF application and I'm trying to change the background of a grid to an image the user chooses (stored somewhere on the computer on a different location from the app). Is it possible without having the images included on the project and marked as a Resource? How?
Assuming you Grid name is grid, then xaml would be:
<Grid Name="grid">
...
</Grid>
then to set an image programatically to grid, you should use the following code snippet:
string imgPath=#"E:\anImage.jpg";
grid.Background= new ImageBrush { ImageSource = new BitmapImage(new Uri(imgPath,
UriKind.RelativeOrAbsolute)) };
you just need to set the image's source URI to the image location
<Image Source="<<URI of image>>"/>
<ImageBrush ImageSource="<<URI of image>>"/>
or you can do the same via binding to allow it to be customised
<Image Source="{Binding Data}"/>
in this example Data is a byte[] stored in the model, but could be anything that converts to an image source
This works for me :
1) Add image in solution (Add => Existing Item)
2)<Grid>
<Grid.Background>
<ImageBrush ImageSource="/App;component/Chrysanthemum.jpg">
</ImageBrush>
</Grid.Background>
</Grid>

WPF Using Image Control to dynamically view Online images

Situation
I'm trying to use an image control in my program that accesses an online image by binding it to a property.
XAML:
<Image Source="{Binding TheImage}" x:Name="imgPic" HorizontalAlignment="Left" Height="113" Margin="14,89,0,0" VerticalAlignment="Top" Width="120"/>
Specifically, I'm binding to the return value of the searchMembers method (which returns an object) mempic contains a URL, and this mempic will change depending on which member is currently logged in.
View Model:
public Uri TheImage
{
get
{
return new Uri(hillracing.searchMembers(Username).mempic);
}
}
Problem
Neither this code, or a static link to the image actually works.
Here is the test image I'm actually using
wondered if anyone could tell em what I was doing wrong.
thanks.
The WPF Image control is more sophisticated than you imagine... just use the string URI value as the Image.Source directly like this:
<Image Source="http://i.imgur.com/aIf7B0P.jpg" />
Or, if you want to data bind, do this:
<Image Source="{Binding TheImage}" ... />
...
public string TheImage
{
get { return "http://i.imgur.com/aIf7B0P.jpg"; }
}

How to reuse vector images in wpf properly

X problem:
I want to use vector graphic in WPF.
I have bunch of SVG files, which I can convert into XAML by using Inkscape. Resulting xaml is ResourceDictionary with ViewBox / Canvas containing Path, etc. Dictionaries are merged into App.xaml and I can use key to access them.
Question: how to use such images? It looks like I am not using them properly.
Here is how I am using them
<Viewbox Child="{StaticResource MyImageResourceKey}" Width="100" Height="100"/>
But it looks like I can use it only once (in one place)! Attempting to use that image in multiple places simultaneously will either remove it from previous place or will throw
System.ArgumentException: Must disconnect specified child from current parent Visual before attaching to new parent Visual.
Y problem
I want to show a list of vector images. I display them like this
<ItemsControl ItemsSource="{Binding Images}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Viewbox Width="100" Height="100">
<ContentPresenter Content="{Binding Image}"/>
</Viewbox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ViewModel
public class ViewModelSomeWindow : INotifyPropertyChanged
{
public class MyImage
{
public object Image { get; set; }
}
private ObservableCollection<MyImage> _images;
public ObservableCollection<MyImage> Images
{
get { return _images; }
set { _images = value; OnPropertyChanged(); }
}
...
}
And items are added like this
Images.Add(new MyImage() { Image = App.Current.Resources["MyImageResourceKey"] });
Problem: when using same image ("MyImageResourceKey") for second item, then first item displays (blank) image. If image is already displayed with the use of StaticResource somewhere, then adding item will throw above ArgumentException.
P.S.: I need to solve Y problem, but perhaps I am not using vector graphic properly.
Please Use x:shared =false in path as shown in attached image
and visit this link too for reference

Problem assigning source property to Image Control WPF

I have a WPF C# project that I am working on and I have multiple (25) Image controls arranged in table (5 columns, 5 rows). Each Image control is called "Image[row][column]" (eg:Image15).
Assigning a different source to the control works fine with ony one problem. No matter which control I use (Image11, Image12, Image 55) it affects Image11. No matter which one I try to change I'll end up changing the first one (Image11). This is the source change code:
BitmapImage src3 = new BitmapImage();
src3.BeginInit();
src3.UriSource = new Uri(#"D:\Electricity\CONSUMER_ON.jpg");
src3.EndInit();
Image15.Source = src3;
This does change the image but acts as if I had written "Image11.Source = src3;". Here's the XAML code just in case it might have anything to do with it.
<Image Height="150" HorizontalAlignment="Left" Margin="11,10,0,0" Name="Image11" Stretch="Fill" VerticalAlignment="Top" Width="150" />
... 23 more lines removed ...
<Image Height="150" HorizontalAlignment="Left" Margin="635,634,0,0" Name="Image55" Stretch="Fill" VerticalAlignment="Top" Width="150" />
if you need any other info, please ask. The images are 200x200 and in JPEG format and are displayed correctly (in the wrong place). The Images for the controls are determined and loaded at run-time.
Are you remembering to create a new BitmapImage for each image control, or are you recycling the same object but changing its contents when you move between images? If you set the source of two Image controls to the same ImageSource and then alter that image, both controls will reflect the changes.

Categories