100% responsive UI in WPF - wpf

I have a WPF application that uses a component that sends a bitmap to my application as they become available, I receive those bitmaps in a delegate I pass to this component.
I created a new thread for this process and it works very well, the bitmaps comes as MemoryStream and I just create the BitmapSource object from this stream inside a Dispatcher.BeginInvoke method call. After I have the BitmapSource object, I add them to a StackPanel so the user can see a queue of images available to work. So far so good...
The problem is that those bitmaps are quite big, like 3000x2000+ pixels, and it takes about 50~ms to create these bitmaps and add to the queue, and when this code is executed, the onde inside the BeginInvoke call, it blocks the UI for this time, causing a very annoying behavior, (to reproduce this, just call Thread.Sleep(50) every 5 seconds).
How can I fix this so the user is always responsive?
thanks!

There are two ideas you might want to consider:
Don't create the BitmapSource inside Dispatcher.Invoke. That would practically create it inside the UI thread, slowing things down. Instead, create it in the background thread, freeze it, and then pass the frozen BitmapSource to the foreground thread.
Depending on your application, perhaps the StackPanel doesn't need the full 3000x2000 resolution? If that is the case, consider resizing down the images in the background thread, just before you freeze them.
The following code does #1 above:
Window1.xaml
<Window x:Class="BitmapFrameDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Image Name="image"/>
</Grid>
</Window>
Window1.xaml.cs
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace BitmapFrameDemo {
public partial class Window1 : Window {
private Thread thread = null;
private Dispatcher dispatcher = null;
private void ThreadMain() {
// obtain the image memory stream
WebRequest request = WebRequest.Create("http://stackoverflow.com/content/img/so/logo.png");
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
// create a bitmap source while still in the background thread
PngBitmapDecoder decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
BitmapFrame frame = decoder.Frames[0];
// freeze the bitmap source, so that we can pass it to the foreground thread
BitmapFrame frozen = (BitmapFrame) frame.GetAsFrozen();
dispatcher.Invoke(new Action(() => { image.Source = frozen; }), new object[] { });
}
public Window1() {
InitializeComponent();
dispatcher = Dispatcher.CurrentDispatcher;
thread = new Thread(new ThreadStart(this.ThreadMain));
thread.Start();
}
}
}
alt text http://www.freeimagehosting.net/uploads/66bdbce78a.png

Really all you need to do is set the IsAsync to True on your binding to the image. I would however recomend using a PriorityBinding and preparing some form of default image that the user can see so they know it isn't fully loaded.
<StackPanel>
<Image>
<Image.Source>
<PriorityBinding>
<Binding Path="SlowImage"
IsAsync="True" />
<Binding Path="DefaultImage" />
</PriorityBinding>
</Image.Source>
</Image>
</StackPanel>
public partial class Window1 : Window, INotifyPropertyChanged
{
public Window1()
{
InitializeComponent();
DefaultImage = new BitmapImage(new Uri("http://stackoverflow.com/content/img/so/logo.png"));
SlowImage = new BitmapImage(new Uri("http://serverfault.com/content/img/sf/logo.png"));
this.DataContext = this;
}
private BitmapImage myDefaultImage;
public BitmapImage DefaultImage
{
get { return this.myDefaultImage; }
set
{
this.myDefaultImage = value;
this.NotifyPropertyChanged("Image");
}
}
private BitmapImage mySlowImage;
public BitmapImage SlowImage
{
get
{
Thread.Sleep(5000);
return this.mySlowImage;
}
set
{
this.mySlowImage = value;
this.NotifyPropertyChanged("SlowImage");
}
}
#region INotifyPropertyChanged Members
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}

Two possibilities come to mind quickly.
The first is to use a BackgroundWorker to perform the transformation of the MemoryStream to a Bitmap.
the Second is to pass off that transformation to a ThreadPool.

While not an entirely satifsfactory answer for you, I would suggest you listen to this Hanselminutes podcast with Ian Griffiths as it covers a very similar program and the proper way to architect it to get the performance you are looking for.
Some specifics may be found on Ian's blog: http://www.interact-sw.co.uk/iangblog/

Related

Showing a text indicator before freezing the Silverlight UI thread

At some point in my Silverlight application I need to perform a heavy operation which freezes the UI thread for about 4 seconds. Before actually performing the operation I am trying to display a simple text indicator via a TextBlock control.
StatusTextBlock.Text = "Performing Some Operation...";
System.Threading.Thread.Sleep(4000); // Just as an example
The problem is that the UI thread freezes before the text of the TextBlock control gets updated. How can I get the notification text shown before the operation begins?
Also, taking the heavy operation to a background thread is not an option for me, as it deals with UI objects (it switches the visual root of the application) and should be executed on the UI thread.
My suggestion is to take it off UI thread and use background thread...
StatusTextBox.Text = "Before Sleep";
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
void bw_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(8000);}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
StatusTextBox.Text = "after Sleep";
}
I found a solution with the help of Jeff Prosise's blog post: http://www.wintellect.com/cs/blogs/jprosise/archive/2008/10/25/cool-silverlight-trick-5.aspx
The idea is to delay the call performing a long running task till a Silverlight UI rendering event fires. For this I used the CompositionTarget.Rendering event. I subscribed to it in the constructor of the user control:
CompositionTarget.Rendering += this.CompositionTargetRendering;
After I update the text of a TextBlock control I set a private flag, which indicates that some processing should be made in the event handler:
StatusTextBlock.Text = "Performing Some Operation...";
this.processRenderingEvent = true;
And here is the code of the handler:
private void CompositionTargetRendering(Object sender, EventArgs e)
{
if (this.processRenderingEvent)
{
if (++this.renderingEventCounter == 2)
{
System.Threading.Thread.Sleep(4000); // Example of long running task
this.processRenderingEvent = false;
}
}
}
An important point to mention here is that I use a private integer field renderingEventCounter to begin the long running task not the first time the event fires, but the second. The reason for this is that the CompositionTarget.Rendering event is fired just before the Silverlight UI rendering engine draws a new frame on the application's display surface, which means that at the first time the event fires the text of the TextBlock control is not yet updated. But it will be updated the second time.
I think you should implement the BackgroundWorker thread is tsiom's answer, but use the Dispatcher.BeginInvoke to operate on the UI objects, here is a MSDN article on how to use the method: http://msdn.microsoft.com/en-us/library/cc190824%28v=vs.95%29.aspx
Also, see another StackOverflow question for a more comprehensive scenario using the Dispatcher: Understanding the Silverlight Dispatcher
I just ran into this situation myself. The problem (I think) is that before the text gets updated you have already begun the intensive operation, so you have to wait.
What you can do is to attach a listened to some method on the textbox that only gets called once the text is updated (textChanged perhaps?) and THEN call your intensive operation.
This seems hackish to me though...
This is ugly but it works. By delaying the initiliazation of the long running operation using a DispatcherTimer we can allow the UI to be updated before the operation is started.
XAML:
<UserControl x:Class="SilverlightApplication13.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid x:Name="LayoutRoot"
Background="White">
<StackPanel>
<Border x:Name="Brd01"
Visibility="Collapsed"
Background="Red">
<TextBlock VerticalAlignment="Center"
Margin="30">Sleeping for 4 seconds...</TextBlock>
</Border>
<Border x:Name="Brd02"
Visibility="Collapsed"
Background="Lime">
<TextBlock VerticalAlignment="Center"
Margin="30">Done!</TextBlock>
</Border>
<Button Content="Start Operation"
Click="Button_Click_1"></Button>
</StackPanel>
</Grid>
</UserControl>
Code-behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace SilverlightApplication13
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
//Show the "working..." message
Brd01.Visibility = System.Windows.Visibility.Visible;
//Initialize a timer with a delay of 0.1 seconds
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(100);
timer.Tick += Timer_Tick;
timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
//Start the long running operation
Thread.Sleep(4000);
Brd01.Visibility = System.Windows.Visibility.Collapsed;
Brd02.Visibility = System.Windows.Visibility.Visible;
//Kill the timer so it will only run once.
(sender as DispatcherTimer).Stop();
(sender as DispatcherTimer).Tick -= Timer_Tick;
}
}
}

How do I implement a DependencyProperty on a custom wpf control for an ImageSource?

How do I implement a DependencyProperty on a custom wpf control for an ImageSource?
I created a custom control (button) which amongst other things does display an image. I want to be able to set the ImageSource for the image from the outside of the control, so I implemented a DependencyProperty. Whenever I try to change the ImageSource though, I am getting a SystemInvalidOperationException: "The calling thread cannot access this object because a different thread owns it."
OK, so the main thread cannot access the image control, so I need to use the Dispatcher - but where and how? Apparently the exception is thrown in the setter, executing SetValue(ImageProperty, value);
tv_CallStart.xaml:
<Button x:Class="EHS_TAPI_Client.Controls.tv_CallStart" x:Name="CallButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="24" d:DesignWidth="24" Padding="0" BorderThickness="0"
Background="#00000000" BorderBrush="#FF2467FF" UseLayoutRounding="True">
<Image x:Name="myImage"
Source="{Binding ElementName=CallButton, Path=CallImage}" />
</Button>
tv_CallStart.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace EHS_TAPI_Client.Controls
{
public partial class InitiateCallButton : Button
{
public ImageSource CallImage
{
get { return (ImageSource)GetValue(CallImageProperty); }
set { SetValue(CallImageProperty, value); }
}
public static readonly DependencyProperty CallImageProperty =
DependencyProperty.Register("CallImage", typeof(ImageSource), typeof(InitiateCallButton), new UIPropertyMetadata(null));
public InitiateCallButton()
{
InitializeComponent();
}
}
}
setting the image from the code-behind of the UI-thread:
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri("pack://application:,,,/EHS-TAPI-Client;component/Images/call-start.png");
bi.EndInit();
bi.Freeze();
CallButton.CallImage = bi;
and the MainWindow.xaml where the control is initialised:
<ctl:InitiateCallButton x:Name="CallButton" CallImage="/Images/call-start.png" />
Adapted the above source code to reflect my progress..
Solution:
The code posted above is working fine. The important change from the initial version is the addition of the Freeze() method from the UI thread (see accepted answer). The actual problem in my project is not the button not being initialised in the UI thread, but the new image being set from another thread. The image is set in an event handler which itself is triggered from another thread. I resolved the problem by using the Dispatcher:
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri("pack://application:,,,/EHS-TAPI-Client;component/Images/call-start.png");
bi.EndInit();
bi.Freeze();
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate()
{
CallButton.CallImage = bi;
});
}
else
{
CallButton.CallImage = bi;
}
If you use an image internally it makes sense to reuse the Image.SourceProperty and not that of ImageBrush.
Make sure to create all thread-affine elements on the UI-thread or you need to Freeze them if they are freezable before you do anything cross-thread with them. (ImageSource is a Freezable)
The property changed handler is not hooked up so it will never be called, its content is pointless anyway though, the property has already been set when the handler is called.

Kill one button event when new button clicked

How to kill one button's event when a new button is clicked.
I have one event (Button G) running.(has a while loop waiting for some input).
I have a another button for quit operation.
Now. I cannot click any other button when button G's event is running.
How can I solve that?
Thanks
Hi, #Grokodile thank you for your code. So I commented your code here, Should I put my job logic code where I commented below? Thans
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private BackgroundWorker _worker;
public MainWindow()
{
InitializeComponent();
}
private void RunButtonClickHandler(object sender, RoutedEventArgs e)
{
_worker = new BackgroundWorker {WorkerSupportsCancellation = true};
_worker.DoWork += BackgroundWorkerTask;
_worker.RunWorkerAsync();
       //I should Put my job logic here, right?
}
private void StopButtonClickHandler(object sender, RoutedEventArgs e)
{
if (_worker != null && _worker.IsBusy) _worker.CancelAsync();
//I should Put my job logic here, right?
}
private void BackgroundWorkerTask(object sender, DoWorkEventArgs e)
{
// this runs on the BackgroundWorker thread.
while (_worker.CancellationPending == false)
{
Thread.Sleep(500);
// You have to use the Dispatcher to transfer the effects of
// work done in the worker thread back onto the UI thread.
Dispatcher.BeginInvoke(new Action(UpdateTime), DispatcherPriority.Normal, null);
}
}
private void UpdateTime()
{
// Dispatcher runs this on the UI thread.
timeTextBlock.Text = DateTime.Now.ToString();
}
}
}
Futher to what H.B. and dowhilefor have said, here is a sample that shows starting a task on a background thread using BackgroundWorker with one Button and ending it with another Button, note the use of Dispatcher.BeginInvoke:
XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="80"
Width="640"
FontSize="16">
<DockPanel VerticalAlignment="Center">
<Button Margin="10,0"
x:Name="runButton"
DockPanel.Dock="Left"
Click="RunButtonClickHandler">Run</Button>
<Button Margin="10,0"
x:Name="stopButton"
DockPanel.Dock="Left"
Click="StopButtonClickHandler">Stop</Button>
<TextBlock Margin="10,0">The Time Is Now:</TextBlock>
<TextBlock x:Name="timeTextBlock"
Margin="10,0" />
</DockPanel>
</Window>
Code Behind
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private BackgroundWorker _worker;
public MainWindow()
{
InitializeComponent();
}
private void RunButtonClickHandler(object sender, RoutedEventArgs e)
{
_worker = new BackgroundWorker {WorkerSupportsCancellation = true};
_worker.DoWork += BackgroundWorkerTask;
_worker.RunWorkerAsync();
}
private void StopButtonClickHandler(object sender, RoutedEventArgs e)
{
if (_worker != null && _worker.IsBusy) _worker.CancelAsync();
}
private void BackgroundWorkerTask(object sender, DoWorkEventArgs e)
{
// this runs on the BackgroundWorker thread.
while (_worker.CancellationPending == false)
{
Thread.Sleep(500);
// You have to use the Dispatcher to transfer the effects of
// work done in the worker thread back onto the UI thread.
Dispatcher.BeginInvoke(new Action(UpdateTime), DispatcherPriority.Normal, null);
}
}
private void UpdateTime()
{
// Dispatcher runs this on the UI thread.
timeTextBlock.Text = DateTime.Now.ToString();
}
}
}
EDIT - A Little More Explanation
RunButtonClickHandler
Creates and initializes a BackgroundWorker so that it supports cancellation.
Attaches a DoWorkEventHandler to the DoWork event, i.e. BackgroundWorkerTask.
Starts excecution of the background operation with the call to RunWorkerAsync, i.e. creates a new thread (actually it uses a thread from the thread pool) and runs the code in BackgroundWorkerTask on that thread.
BackgroundWorkerTask
If you want to do work that would otherwise cause the UI to freeze when running on the main UI thread (e.g. search for undiscovered prime numbers) then you do it here in the background thread.
UpdateTime
All WPF Controls inherit from DispatcherObject and are associated with a Dispatcher which manages the execution of work done in the UI's single thread. If you need to do work such as setting the text of a TextBlock, you can't do it from the background thread, trying to do so will cause an exception to be thrown. UpdateTime is queued back onto the UI thread by the Dispatcher when Dispatcher.BeginInvoke is called from BackgroundWorkerTask. This way you can get the results of work done in the background before cancelling the background threads execution.
StopButtonClickHandler
Changes _worker.CancellationPending to true with the call to CancelAsync causing the while loop to exit and thus for execution to leave the BackgroundWorkerTask event handler.
In short, you can do work in two places, either in BackgroundWorkerTask or in UpdateTime, but you can only carry out changes to UI elements from UpdateTime.
Don't do spin-waiting operations on the UI-thread, use a new Thread or a Timer for example.
You can't. The UI is running in a single thread, usually called the main or ui thread. With your while loop you are blocking the whole ui thread, thus you can't receive any further input.
I suggest you check out BackgroundWorker class and maybe check some more MSDN articles about how the threading and background tasks should be designed to work properly in an ui enviroment.

WPF & MVVM : Update an image field without breaking the pattern

I'm currently learning how to write a WPF application using the MVVM pattern. I'm writing a little contact manager application, so my app displays a Listbox bound to my View Model, and a set of fields bound to ListBox.SelectedItem. One of these fields is the contact's photo.
I'd like to change the photo in the edit part using OpenFileDialog, so the Listbox item would be updated, as it is for all of the other fields.
I first tried to update the source property of the Image control, but doing this, I lose the Binding...
Then I wrote an handler on Button_Click to update the Contact.Photo property (its type is byte[]), and it works. But instead of binding from the "update control" to the view model, binding is from the VM to the control, as if the data came from the DB.
(In the code, LoadPhoto returns a byte[])
private void Button_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog OpenFileDialog = new OpenFileDialog();
if (OpenFileDialog.ShowDialog() == true)
{
(listbox.SelectedItem as ContactManager.ViewModel.Contact).Photo =
LoadPhoto(OpenFileDialog.FileName);
}
}
I wonder if it doesn't break the MVVM pattern... I'm not sure of what could be made in the View... Is it the right way to update the Contact object ? Does anyone have a better solution to this problem ?
Look into binding your button to a Command Binding instead of the click event.
You can find implementations of DelegateCommand using Google.
Next you can expose a ImageSource from your ViewModel that you can bind to your Image from your XAML.
I've included some code fragments to get you started.
Once you get past the basics take a look at MVVM Frameworks, like Cinch, you'll find a way to handle OpenFileDialog using the Services Interfaces IOpenFileService.cs to not violate the MVVM pattern.
Here is the XAML:
<Button Content="Update Photo" Command="{Binding UpdatePictureCommand}"/>
<Image Source="{Binding EmployeePicture}"
VerticalAlignment="Center" HorizontalAlignment="Center"
Stretch="Fill" />
Here is the ViewModel:
public MainViewModel()
{
UpdatePictureCommand = new DelegateCommand<object>(OnUpdatePictureCommand, CanUpdatePictureCommand);
}
public ICommand UpdatePictureCommand { get; private set; }
private void OnUpdatePictureCommand(object obj)
{
OpenFileDialog OpenFileDialog = new OpenFileDialog();
if (OpenFileDialog.ShowDialog() == true)
{
//(listbox.SelectedItem as ContactManager.ViewModel.Contact).Photo =
// LoadPhoto(OpenFileDialog.FileName);
Stream reader = File.OpenRead(OpenFileDialog.FileName);
System.Drawing.Image photo = System.Drawing.Image.FromStream((Stream)reader);
MemoryStream finalStream = new MemoryStream();
photo.Save(finalStream, ImageFormat.Png);
// translate to image source
PngBitmapDecoder decoder = new PngBitmapDecoder(finalStream, BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.Default);
EmployeePicture = decoder.Frames[0];;
}
private bool CanMoveFirstCommand(object obj)
{
return true;
}
private ImageSource _employeePicture;
public ImageSource EmployeePicture
{
get
{
return _employeePicture;
}
set
{
_employeePicture = value;
OnPropertyChanged("EmployeePicture");
}
}

Silverlight MVVM Prism and OpenFileDialog

I am currently working on a SilverLight 3 Application. I am using MVVM Pattern and Prism. I have everything working except the following item. On one of my views I have to use an OpenFileDialog. I attempted to do this in the ViewModel only to find out the security model of SilverLight prohibits it because it is only allowed to be user initiated. I've since moved the OpenFileDialog code to the code-behind of the View. Here is my problem though. Although I have binding to the source set to TwoWay it is not hitting the setter of the property in my ViewModel.
Example of Image control with binding:
<Image x:Name="imgCard" Height="283" Width="463" Canvas.Left="8" Canvas.Top="8" OpacityMask="White" Source="{Binding Path=CardImage, Mode=TwoWay}"/>
Button Used by user:
<Button x:Name="btnUpload" Height="20" Width="122" Canvas.Left="8" Canvas.Top="319" Content="Upload Image" Click="btnUpload_Click" />
Click Event:
private void btnUpload_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "PNG Files(*.png)|*.png";
ofd.ShowDialog();
using (Stream stream = ofd.File.OpenRead())
{
BitmapImage image = new BitmapImage();
image.SetSource(stream);
imgCard.Source = image;
}
}
My ViewModel is implementing the INotifyPropertyChanged and has the following property.
BitmapSource CardImage
{
get
{
return _imageSource;
}
set
{
_imageSource = value;
NotifyPropertyChanged("CardImage");
}
}
If I put a break point on the Setter. It never hits it.
At least in Silverlight 2, I think the following rule might explain why you are seeing this behavior. "If a Dependency Property is bound and in code the property is set to a value explicitly, the binding is removed." (source)
Maybe this has changed for Silverlight 3? In that case, I have no suggestions.
Ok this is a hack but it works. Because I have to fire the OpenFileDialog from the UI I can instead of updating the control directly reverse tether to the DataContext to update the property. This works and still renders the UI the way I expect.
NOTE: HACK Until I find a better way.
private void btnUpload_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "PNG Files(*.png)|*.png";
ofd.ShowDialog();
using (Stream stream = ofd.File.OpenRead())
{
BitmapImage image = new BitmapImage();
image.SetSource(stream);
BitmapSource b = image;
//HACK: This works but now I'm tethered a bit. This updates the context property CardImage.
((DesignerViewModel) this.DataContext).CardImage = b;
//imgCard.Source = b;
}
}

Resources