How to Serialize an Image Control whose source is set at runtime? - wpf

I have a Grid containing several controls, the most important being three image controls.
I need to make a duplicate of this Grid. Serializing by saving the XAML in a MemoryStream doesnt seem to help because, obviously, when I set the source of the Image Control in the code behind at runtime, this change is not reflected in the XAML designer code. [Technically it is, but as
<Image.Source> System.Windows.Interop.InteropBitmap</Image.Source>
and I get some wierd exception]
So, how can I serialize my Image control?
More generally, how can I Clone my Grid control to reflect any changes to the UI that happened after the window loaded?

If I understood your question properly, I think you just need to create a clone of your grid at runtime. If so take a look at these threads
How can you clone a WPF object?
http://social.msdn.microsoft.com/Forums/en-HK/wpf/thread/e1a63ed2-a432-4c46-8f3b-4f172702cd7c
Use this function to clone an Object
public static T DeepClone<T>(T from)
{
using (MemoryStream s = new MemoryStream())
{
BinaryFormatter f = new BinaryFormatter();
f.Serialize(s, from);
s.Position = 0;
object clone = f.Deserialize(s);
return (T)clone;
}
}
above function was by Arcturus

Related

WPF Keeping Images in Memory

My WPF UI is keeping all of the images I use in memory. Below is the relevant retention graph. Using the ANTS Memory Profiler 8.7, I have established that none of my code is holding onto any these objects. I have written code so that multiple request for the same image create only one image, but that leaves me with the problem that there are enough images within my application to crash it when they are all loaded simultaneously. I turned off this code when I ran this memory profile. I need to flush these images. I have even resorted to manually calling GC.Collect which did not reduce the memory used. Something is holding these images and it is not my code.
Here is the code for how I expose the BitmapImage to then be bound to Image.Source. This does not contain my image-to-path dictionary caching service that is now turned off.
public BitmapImage Image
{
get
{
var image = new BitmapImage();
image.BeginInit();
image.UriSource = a_url;
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.EndInit();
image.Freeze();
return image;
}
}
// The XAML
<Image Source="{Binding Image, Mode=OneWay}"/>
NOT A DUPLICATE
I have determined that the BitmapImage is being held on to and have explicitly invoked GC.Collect which did nothing. The problem is not the GC. I also always Freeze my BitmapImage objects when I create them in code. This is not my first time around.
I can see from the object graph that you have a class called ImageAnimationController, which is holding a reference to the Image control that uses your BitmapImage as its source by a DependencyPropertyDescriptor. The ImageAnimationController uses the DependencyPropertyDescriptor to subscribe to change notifications of the Image control's Source DependencyProperty. When the ImageAnimationController class is disposed it will unsubscribe from the DependencyPropertyDescriptor notifications.
It looks like this ImageAnimationController class is a component of an open source library called WPF Animated GIF. I can't see how you are using this library as you have not included the source, but I imagine that somewhere you have either something like this:
ImageBehavior.SetAnimatedSource(img, image);
Or this:
<Image gif:ImageBehavior.AnimatedSource="{Binding Image}" />
I am not familiar with this library or your code, but I imagine that you will need to ensure that this attached behaviour is correctly detached and disposed of.

Force binding in WPF

I'm writing tests which will check correctness of Binding elements specified in XAML. They work so far, the only issue is that I do not know how to correctly force databinding to happen. Surprisingly it is not enough to simply set something in DataContext, binding won't happen until you show your control/window. Please not that I'm writing 'unit'-tests and I'd like to avoid showing any windows.
Take a look at following code:
// This is main class in console application where I have all WPF references added
public class Program
{
[STAThread]
public static void Main()
{
var view = new Window();
BindingOperations.SetBinding(view, Window.TitleProperty, new Binding("Length"));
view.DataContext = new int[5];
//view.Show(); view.Close(); // <-- this is the code I'm trying not to write
Console.WriteLine(view.Title);
}
}
Here I'm creating a Window and putting an array as DataContext to that window. I'm binding Window.Title to Array.Length so I expect to see number 5 printed in console. But until I Show window (commented line) I will get empty string. If I uncomment that line then I will receive desired 5 in console output.
Is there any way I can make binding happen without showing a window? It is pretty annoying to look at ~20 windows while launching tests.
P.S.: I know I can make windows more transparent and etc, but I'm looking for more elegant solution.
UPDATE Code above is simplified version of what I really have. In real code I receive a View (some UIElement with bindings) and object ViewModel. I do not know which exactly binding there were set on View, but I still want all of them to be initialized.
UPDATE 2: Answering to the questions regarding what I test and I why. I do not intend to test that classes like Binding, BindingBase, etc are working as expected, I assume they are working. I'm trying to test that in all my XAML files I have written bindings correctly. Because bindings are stringly typed things, they are not verified during compilation and by default they cause only errors in output window, which I'm missing occasionally. So if we take my example from above and if we will made a typo there in binding: {Binding Lengthhh} then my tests will notify you that there is no property with name Lengthhh available for binding. So I have around 100 XAML files and for each XAML I have a test (3-5 lines of code) and after launching my tests I know for sure that there are no binding errors in my solution.
The bindings are updated by the dispatcher with the DispatcherPriority.DataBind - so if you wait for a dummy task with SystemIdle priority you are sure that any pending databinding is done.
try
{
this.Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => { }));
}
catch
{
// Cannot perfom this while Dispatcher in suspended mode
}
If you are trying to test correctness of your view, I suggest you test your view :-)
Why not run the UI from a unit test and write code that checks content of UI after changing data.
VS2010 does have GUI testing, or you could take a look at the code of tools such as Snoop.
Edit following comment:
If ALL you want to do is test a few simple bindings, try writing a static code test that runs as a post build event using reflection on view models and regular expressions on XAMLs. Add attributes on VM or use a config file so your test will know which view receives which View Model as DataContext. Compare property names and types in View Models with binding strings in View (automatically search XAML for these) and throw exception (thus failing build) if strings do not match.
If your bindings are more complex (converters, multibindings, ...) this may be a bit more complicated to implement.
I think you should first set the DataContext and then do the Binding, e.g.:
view.DataContext = new int[5];
BindingOperations.SetBinding(view, Window.TitleProperty, new Binding("Length"));
I'm not sure if this is real solution for your general problem, but it works in this case.
I don't believe the Window's bindings will run without calling Show or ShowDialog, because that is the only way it gets associated with the UI message loop/dispatcher.
Your best bet would be to set it to be as least visible as possible, potentially using an extension method to clean things up:
public static void PokeWindowDispatcher(this Window window)
{
window.WindowState = WindowState.Minimized;
window.ShowInTaskbar = false;
window.Visibility = Visibility.None;
using (var wait = new ManualResetEvent())
{
Action<object, RoutedEventArgs> loaded = (sender, e) => wait.Set();
window.Loaded += loaded;
try
{
window.Show();
wait.WaitOne();
}
finally
{
window.Loaded -= loaded;
window.Close();
}
}
}
I had the same problem, and from sixlettervariables gave me an idea. It's very simple.
I am using WPF in WinForms application, so I use ElementHost control to host Wpf controls on WinForms control. To enforce WinForms control initialization you can just read value of Handle (which is actually Windows HWND) and this will force control to fully initialize itself including child ElementHost and all Wpf binding work.
I didn`t try to perform the same thing for pure Wpf control. But you can easily use ElementHost to initialize your Wpf controls like this:
var el = new ElementHost();
var p = new TextBlock();
p.DataContext = new { Data = "1234" };
p.SetBinding(TextBlock.TextProperty, "Data");
el.Child = p;
var t = el.Handle;
Debug.Assert(p.Text == "1234");
PS: Found, that everything work better, if you first set DataContext and only then force a Handle to be created (just like my example). But, I think, this is already the case for you, so should not be a problem.
Have you tryed to use the IsDataBound
http://msdn.microsoft.com/en-us/library/system.windows.data.bindingoperations.isdatabound.aspx
Also check this out:
System.Windows.Interop.WindowInteropHelper helper = new System.Windows.Interop.WindowInteropHelper(view).EnsureHandle();
http://msdn.microsoft.com/en-us/library/system.windows.interop.windowinterophelper.ensurehandle.aspx
My other question is why you trying to do a UNIT test on something that has been technically tested already? By the way I am not critising, just want to understand a little better.
Not sure, but maybe something like this will work?
view.GetBindingExpression(Window.TitleProperty).UpdateTarget();

How to clone Silverlight visual tree structure

I have the same problem as the question stated in "Printing in Silverlight 4".
To get around the problem, I have tried to scale transform root of my visual tree before printing.
void document_PrintPage(object sender, PrintPageEventArgs e)
{
var renderScale = 1.0D;
if (LayoutRoot.ActualWidth > e.PrintableArea.Width)
renderScale = e.PrintableArea.Width/LayoutRoot.ActualWidth;
var scaleTransform = new ScaleTransform();
scaleTransform.ScaleX *= renderScale;
scaleTransform.ScaleY *= renderScale;
e.PageVisual = LayoutRoot;
e.PageVisual.RenderTransform = scaleTransform;
}
Now above code correctly prints out with silverlight visuals fit on a piece of paper.
The problem now is that LayoutRoot itself is now scaled down on the screen.
The question is, is there a way for me to create a clone of LayoutRoot before applying scale transform?
My walk-around is to applying the scale tranformation again after printing but I'd like to know if there is a way to clone visual tree
My goodness, thanks for the question. I had the same problem but tried to fiddle about with setting the dimensions of a container (that is already in the visual tree) to the printable area, which does not work, as another layout pass seems to be required. ScaleTransform does work here however instantly.
I'm fine with the "work around" by just doing a myContainer.ClearValue(FrameworkElement.RenderTransformProperty) in the EndPrint event. Trying to clone the visual tree will yield a plethora of other issues (I have lazy loading content etc).
Check out this link for details on silverlight object clone.
also just another idea would using xamlreader/writer to read the xaml string and creating an in-memory copy of the visual tree work.
for ex
If your xaml has button called originalbutton, using the code below you will have a copy of the button in readerLoadButton
// Save the Button to a string.
string savedButton = XamlWriter.Save(originalButton);
// Load the button
StringReader stringReader = new StringReader(savedButton);
XmlReader xmlReader = XmlReader.Create(stringReader);
Button readerLoadButton = (Button)XamlReader.Load(xmlReader);

Silverlight Image Data Binding

I am new to Silverlight, and have an issue with binding.
I have a class ItemsManager, that has inside its scope another class Item.
class ItemsManager
{
...
class Item : INotifyPropertyChanged
{
...
private BitmapImage bitmapSource;
public BitmapImage BitmapSource
{
get { return bitmapSource; }
set
{
bitmapSource = value;
if(PropertyChanged != null )PropertyChanged("BitmapSource")
}
}
}
}
I do the following in code to test binding:
{
ItemsManager.Instance.AddItem("123");
//Items manager started downloading item visual
//part (in my case bitmap image png)
Binding b = new Binding("Source");
b.Source = ItemsManager.Instance.GetItem("123").BitmapSource;
b.BindsDirectlyToSource = true;
Image img = new Image();
img.SetBinding(Image.SourceProperty, b);
img.Width = (double)100.0;
img.Height = (double)100.0;
LayoutRoot.Children.Add(img);
}
Once image is loaded, image doesn't appear. Though, if I set directly after image has been loaded its source, it displays well.
I also noticed that PropertyChanged("BitmapSource") never fires, because PropertyChanged is null, like Image never binded to it.
I am looking forward to hearing from you!
PropertyChanged("BitmapSource") fires in case of two-way binding.
I.e. if you use two way binding and then manually change image source, like
img.Source = new BitmapImage(new Uri("http://...."));
the property changed event would fire.
As for the image appearance, it seems you bind data in wrong way.
Try declarative bindings.
There are several things wrong with this code:-
You've bound directly to the BitmapImage exposed by the BitmapSource property so you've taken your nested Item class out of the picture anyway.
Also for the property setter to be called you would need something to assign a value to the Image elements Source property and your binding would need to be in two way mode.
Your binding object creation is confused, it specifies a path (which is wrong anyway) but then binds direct to source.
Hence your code would need to look like this:-
Binding b = new Binding("BitmapSource");
b.Source = ItemsManager.Instance.GetItem("123");
b.Mode = BindingMode.TwoWay;
Now when a new BitmapImage is assigned the Image Source property your setter code should run. However it should be born in mind that the this property is of the more general type ImageSource. Hence this code will break if another derivative of ImageSource is assigned instead.
One other thing which may be a problem, I can't recall of the top of my head whether Silverlight supports binding to nested types. You might need to bring your Item class out of ItemsManager and give it a more specific name like ManagedItem.
First, do not bind to BitmapImage unless you have a good reason. Binding to a string is good enough. The implicit conversion will happen automatically. Second, use declaritive binding. Programatic creation and binding is a real mess. Third, only implement INotifyPropertyChanged if you need to send changes of that property to the UI.
You are likely over complicating your situation with all this extra code.
Thanks for explanations. However, I don't need a TwoWay binding. Just one way, once ItemsManager downloads Item image, it should be automatically updated in the Image control.
So, I changed my code to this:
ItemsManager.Instance.AddItem("123");
Binding b = new Binding("BitmapSource");
b.Source = ItemsManager.Instance.GetItem("123");
Image img = new Image();
img.SetBinding(Image.SourceProperty, b);
img.Width = (double)100.0;
img.Height = (double)100.0;
LayoutRoot.Children.Add(img);
I also took Item out of ItemsManager scope, so it is now in its own class file, but image still stays empty, even though bitmap image arrives, and changes in BitmapSource property of Item object.

WPF Image Formats and Binding

I have a project which requires be to convert an in memory System.Drawing.Bitmap into an in memory BitmapImage so I can bind the BitmapImage to an Image control via XAML. The problem I am running into is during the conversion the original bitmap gets shrunk and is very blurry.
This is very bad because the original bitmap is a bar code and I need this bar code to stay readable. Is there anything I can do to preserve the integrity of my bitmap? Or is it possible to bind a System.Drawing.Bitmap to an WPF Image control without first saving the bitmap and using a URI?
Also can anyone explain to me the difference between all these image formats? It seems as if there are a ton of them, they reside in numerous namespaces and it is a pain to convert between them.
EDIT.....
public static BitmapImage GetBitmapImage(Bitmap bmp)
{
MemoryStream ms = new MemoryStream();
bmp.Save(ms, ImageFormat.Bmp);
BitmapImage bmpI = new BitmapImage();
bmpI.BeginInit();
bmpI.StreamSource = ms;
bmpI.EndInit();
ms.Close();
ms.Dispose();
return bmpI;
}
Have you tried different bitmap scaling modes?
For example:
Image RenderOptions.BitmapScalingMode="HighQuality" ...
In my opinion, the easiest way to get rid of all those burdens is to create a user control, then put a
WindowsFormsHost
on to that control. After that you put a windows forms image to the host, and in the underlying code of the user control, you can create a dependency property to bind data and update changes to the image control.
Cheers.

Resources