locked
How to use DynamicResource to Load an Image Into a UserControl in an MVVM Environment RRS feed

  • Question

  • I am trying to load an image dynamically into a user control in an MVVM, Prism, Unity type environment.  I have not found any examples specific to what I am attempting, and I would be appreciative if someone could look at my code below and set me on the right track:

    My xaml, incomplete as it is, looks like this:

    <UserControl x:Class="lp.ImageLab.Views.ImageLabDisplayImageView"
                 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"
                 xmlns:my="clr-namespace:lp.ImageLab.Views"
                 mc:Ignorable="d" 
                 d:DesignHeight="200" d:DesignWidth="200">
        <UserControl.Resources>
            <Image 
        </UserControl.Resources>
        <Grid>
            <Image Width="200">
                <Image.Source>
                    <BitmapImage DecodePixelWidth="200" 
                                     UriSource="{DynamicResource ResourceKey=ImageUri}" />
                </Image.Source>
            </Image>
        </Grid>
    </UserControl>

    The codebehind for my view looks like this:

    namespace lp.ImageLab.Views
    {
        /// <summary>
        /// Interaction logic for ImageLabDisplayImage.xaml
        /// </summary>
        public partial class ImageLabDisplayImageView : UserControl, IRegionMemberLifetime
        { 
            #region Constructor
            public ImageLabDisplayImageView()
            {
                InitializeComponent();
                DataContext = new ImageLabDisplayImageViewModel(this);
            }
            #endregion
    
            #region IRegionMemberLifetime Members
            public bool KeepAlive
            {
                get { return false; }
            }
            #endregion
        }
    }

    The command from my menu control where the user picks the image file to load:

            public void OpenImageFile()
            {
                try
                {
                    // Create OpenFileDialog
                    OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
                    // Set filter for file extension and default file extension
                    dlg.DefaultExt = ".jpg";
                    dlg.Filter = "bitmat images (.jpg)|*.jpg";
                    // Display OpenFileDialog by calling ShowDialog method 
                    Nullable<bool> result = dlg.ShowDialog();
                    // Get the selected file name and display in a TextBox 
                    if (result == true)
                    {
                        string filename = dlg.FileName;
                        MessageBox.Show(filename);
                        // Initialize
                        m_Publish = "ImageLab";
                        Uri uri = new Uri(@"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg");
                        lp.ImageLab.ViewModels.ImageLabDisplayImageViewModel.ImageUri = uri;
                        var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
                        var imageLabDisplayImageView = new Uri("ImageLabDisplayImageView", UriKind.Relative);
                        regionManager.RequestNavigate("WorkspaceRegion", imageLabDisplayImageView, NavigationCompleted);
                    }
                }
                catch (Exception)
                {
                    throw new ApplicationException("Failed loading image");
                }
            }

    ... And my incomplete view model:

    namespace lp.ImageLab.ViewModels
    {
        public class ImageLabDisplayImageViewModel : ViewModelBase
        {
            #region fields
            
            ImageLabDisplayImageView m_view;
            private static ImageSource _imageLocation;
            private static Uri _imageUri;
            #endregion
            #region Constructor
    
            public ImageLabDisplayImageViewModel(ImageLabDisplayImageView view)
            {
                m_view = view;
            }
    
            #endregion
    
            public static ImageSource ImageLocation
            {
                get { return _imageLocation; }
                set { _imageLocation = value; }
            }
    
            public static Uri ImageUri
            {
                get { return _imageUri; }
                set { _imageUri = value; }
            }
        }
    }

    I apologize for uploading so much code, but I think it is necessary to illustrate where I am in this project; which is pretty much L-O-S-T.  lol


    Experience trumps brilliance.


    • Edited by REvans611 Monday, July 8, 2013 12:30 PM clarification
    Sunday, July 7, 2013 8:00 PM

Answers

  • Hey Revans,

    I could not run your code in my local system, Thats why i did a sample to explain you, i am using MVVM architecture here to upload image using OpenFileDialog.

    ViewModel has a property of type BitmapImage, once user upload image using OpenFileDialog, will read stream and set this stream to bitmapimage.

    Follow my code below and let me know if you need anything else. 

    ViewModel

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.Windows.Media.Imaging;
    
    namespace DisplayImageUsingOpenDialogMVVM
    {
        class ImageUploadViewModel : INotifyPropertyChanged
        {
    
            private BitmapImage _bitmapImage;
            public BitmapImage BitmapImage
            {
                get { return _bitmapImage; }
                set
                {
                    _bitmapImage = value;
                    RaisePropertyChanged("BitmapImage");
            }  }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void RaisePropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    }
    

    View

    <Window x:Class="DisplayImageUsingOpenDialogMVVM.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:DisplayImageUsingOpenDialogMVVM"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <local:ImageUploadViewModel x:Key="viewmodel"></local:ImageUploadViewModel>
        </Window.Resources>
        <Grid DataContext="{StaticResource viewmodel}" x:Name="LayoutRoot">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Button Background="AliceBlue" Click="Button_Click" Content="Upload Image" Width="100" Grid.Row="0" Height="30"></Button>
            <Image Width="400" Grid.Row="1"  x:Name="img" Source="{Binding Path=BitmapImage}">
            </Image>
        </Grid>
    </Window>
    

    View.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using Microsoft.Win32;
    
    namespace DisplayImageUsingOpenDialogMVVM
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private ImageUploadViewModel _imageUploadViewModel;
            public MainWindow()
            {
                InitializeComponent();
                this.Loaded += new RoutedEventHandler(MainWindowLoaded);
    
            }
    
            void MainWindowLoaded(object sender, RoutedEventArgs e)
            {
                _imageUploadViewModel = LayoutRoot.DataContext as ImageUploadViewModel;
            }
    
         
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                var openFileDialog = new OpenFileDialog { FileName = "Image", DefaultExt = ".jpg", Filter = "Image Files (.jpg)|*.jpg" };
                if (!openFileDialog.ShowDialog().Equals(true)) return;
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = openFileDialog.OpenFile();
                bitmapImage.EndInit();
    
                _imageUploadViewModel.BitmapImage = bitmapImage;
            }
        }
    }
    

    find sample solution from shared path in dropbox.

    https://www.dropbox.com/sh/sjvbop1kxdcfb71/nJI8OxlsBE


    Thanks & Regards
    Syed Amjad Sr. Silverlight/WPF Developer,
    yahoo : syedamjad6736@yahoo.com, skype : syedamjad.0786.
    Please use Marked as Answer if my post solved your problem and use Vote As Helpful if a post was useful.

    • Marked as answer by REvans611 Sunday, October 13, 2013 6:54 PM
    Monday, July 22, 2013 1:40 PM

All replies

  • As i see you have public property fro imageuri, then why are you using dynamic resource ?

    if you are using bitmap image, it requires URi, which you already have, just bind it to urisource, follow below code and let me know if you any more doubts.

      <Grid>
            <Image Width="200">
                <Image.Source>
                    <BitmapImage DecodePixelWidth="200" 
                                     UriSource="{Binding ImageUri}" />
                </Image.Source>
            </Image>
        </Grid>


    Thanks & Regards
    Syed Amjad Sr. Silverlight/WPF Developer,
    yahoo : syedamjad6736@yahoo.com, skype : syedamjad.0786.
    Please use Marked as Answer if my post solved your problem and use Vote As Helpful if a post was useful.

    Monday, July 8, 2013 8:32 AM
  • As i see you have public property fro imageuri, then why are you using dynamic resource ?

    Thanks for responding, Syed.  In my sample code for the OpenImageFile method, I have a line for the Uri:
                       
    Uri uri = new Uri(@"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg");
    I should have left that out because the intent of OpenImageFile is to allow the user to click a menu item and pick the image file to open.  My code is a bit messy, and I apologize for that.  I would have cleaned it up before posting, but if I knew how to do that then I probably wouldn't need to ask for help.

    I am using dynamic resource because the user will be changing the image during runtime, and it is my understanding that a static resource can only be loaded once.  I think that my main problem is that I do not know the syntax for declaring a dynamic resource in xaml which will be referenced in the view model.  And then, of course, I am not sure of the c# syntax that should be in the view model.

    I have looked at examples of using dynamic resource, but I have found none in an MVVM environment.


    Experience trumps brilliance.

    Monday, July 8, 2013 12:29 PM
  • Weird, I would first to have a try.

    Wednesday, July 10, 2013 11:36 AM
  • Sayed, I tried UriSpource="{Binding ImageUri}" but I get a message that says, "Property 'UriSource' or property 'StreamSource' must be set".

    I changed it up a bit and still get the same error message.  I hope the following code is enough for somebody to see what I am missing.

    <UserControl x:Class="lp.ImageLab.Views.ImageLabDisplayImageView"
                 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"
                 xmlns:my="clr-namespace:lp.ImageLab.ViewModels"
                 mc:Ignorable="d" 
                 d:DesignHeight="200" d:DesignWidth="200">
        <Grid>
            <Image Width="200">
                <Image.Source>
                    <BitmapImage DecodePixelWidth="200"
                                 UriSource="{Binding Path=ImagePath}"/>
                </Image.Source>
            </Image>
        </Grid>
    </UserControl>

    namespace lp.ImageLab.Views
    {
        /// <summary>
        /// Interaction logic for ImageLabDisplayImage.xaml
        /// </summary>
        public partial class ImageLabDisplayImageView : UserControl, IRegionMemberLifetime
        {
            
            #region Constructor
    
            public ImageLabDisplayImageView()
            {
    
                InitializeComponent();
                DataContext = new ImageLabDisplayImageViewModel(this);
            }
    
            #endregion
    
            #region IRegionMemberLifetime Members
    
            public bool KeepAlive
            {
                get { return false; }
            }
    
            #endregion
        }

    namespace lp.ImageLab.ViewModels
    {
        public class ImageLabDisplayImageViewModel : ViewModelBase
        {
            #region fields        
            private static string _imagePath;
            #endregion
            #region Constructor
    
            public ImageLabDisplayImageViewModel(ImageLabDisplayImageView view)
            {
    
            }
    
            #endregion
    
            public static string ImagePath
            {
                get { return _imagePath; }
                set { _imagePath = value; }
            }
        }
    }
    The following code is in my menu view model and successfully passes the image path to the ImagePath property in the ImageLabDisplayImageViewModel class.
    public void OpenImageFile()
    {
        string sImagePath = @"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg";
        lp.ImageLab.ViewModels.ImageLabDisplayImageViewModel.ImagePath = sImagePath;
        var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
        var imageLabDisplayImageView = new Uri("ImageLabDisplayImageView", UriKind.RelativeOrAbsolute);
        regionManager.RequestNavigate("WorkspaceRegion", imageLabDisplayImageView, NavigationCompleted);
    }

    When I plug the path string directly into the xaml, it works, but my goal is to allow the user to use an OpenFileDialog to pick the image that will be injected.

    Experience trumps brilliance.



    • Edited by REvans611 Sunday, July 21, 2013 5:03 PM clarification
    Sunday, July 21, 2013 4:55 PM
  • Hey Revans,

    I could not run your code in my local system, Thats why i did a sample to explain you, i am using MVVM architecture here to upload image using OpenFileDialog.

    ViewModel has a property of type BitmapImage, once user upload image using OpenFileDialog, will read stream and set this stream to bitmapimage.

    Follow my code below and let me know if you need anything else. 

    ViewModel

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.Windows.Media.Imaging;
    
    namespace DisplayImageUsingOpenDialogMVVM
    {
        class ImageUploadViewModel : INotifyPropertyChanged
        {
    
            private BitmapImage _bitmapImage;
            public BitmapImage BitmapImage
            {
                get { return _bitmapImage; }
                set
                {
                    _bitmapImage = value;
                    RaisePropertyChanged("BitmapImage");
            }  }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void RaisePropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    }
    

    View

    <Window x:Class="DisplayImageUsingOpenDialogMVVM.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:DisplayImageUsingOpenDialogMVVM"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <local:ImageUploadViewModel x:Key="viewmodel"></local:ImageUploadViewModel>
        </Window.Resources>
        <Grid DataContext="{StaticResource viewmodel}" x:Name="LayoutRoot">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Button Background="AliceBlue" Click="Button_Click" Content="Upload Image" Width="100" Grid.Row="0" Height="30"></Button>
            <Image Width="400" Grid.Row="1"  x:Name="img" Source="{Binding Path=BitmapImage}">
            </Image>
        </Grid>
    </Window>
    

    View.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using Microsoft.Win32;
    
    namespace DisplayImageUsingOpenDialogMVVM
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private ImageUploadViewModel _imageUploadViewModel;
            public MainWindow()
            {
                InitializeComponent();
                this.Loaded += new RoutedEventHandler(MainWindowLoaded);
    
            }
    
            void MainWindowLoaded(object sender, RoutedEventArgs e)
            {
                _imageUploadViewModel = LayoutRoot.DataContext as ImageUploadViewModel;
            }
    
         
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                var openFileDialog = new OpenFileDialog { FileName = "Image", DefaultExt = ".jpg", Filter = "Image Files (.jpg)|*.jpg" };
                if (!openFileDialog.ShowDialog().Equals(true)) return;
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = openFileDialog.OpenFile();
                bitmapImage.EndInit();
    
                _imageUploadViewModel.BitmapImage = bitmapImage;
            }
        }
    }
    

    find sample solution from shared path in dropbox.

    https://www.dropbox.com/sh/sjvbop1kxdcfb71/nJI8OxlsBE


    Thanks & Regards
    Syed Amjad Sr. Silverlight/WPF Developer,
    yahoo : syedamjad6736@yahoo.com, skype : syedamjad.0786.
    Please use Marked as Answer if my post solved your problem and use Vote As Helpful if a post was useful.

    • Marked as answer by REvans611 Sunday, October 13, 2013 6:54 PM
    Monday, July 22, 2013 1:40 PM
  • Thank you, Syed.  It may take a few days before I can address this, but I will let you know later how it works for me.

    Experience trumps brilliance.

    Monday, July 22, 2013 3:01 PM
  • Syed, it took much more than a few days to verify your solution.  Thank you very much.

    Rob E.

    Sunday, October 13, 2013 6:54 PM