locked
Bitmap data binding in WPF RRS feed

  • Question

  • Hello!

    I have a set of relevant documents that needs to be displayed in my WPF.

    I have implemented the MVC and I easily can update the elements in my WPF listbox.

    The problem is the BITMAP that my RlevantDocument contains. I don´t know how can I bind a bitmap object to my wpf Image element.

    Is the bitmap binding possible in WPF?

    Here is the code of my Window.xaml:

    <Window x:Class="wpfTutorial.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:compModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
        xmlns:local="clr-namespace:wpfTutorial"
    
      Title="Window1" Height="307" Width="665"
        Loaded="Window_Loaded_1">
    
      <Window.Resources>
        <local:MyModel x:Key="model" />
      </Window.Resources>
      
      <Grid>
        <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Name="documents">
          <ListBox ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollBar.Scroll="ListBox_Scroll_1" ItemsSource="{Binding Documents, Source={StaticResource model}}" >
            <ListBox.ItemTemplate>
              <DataTemplate>
                <TextBlock>
                  <Hyperlink NavigateUri="{Binding Path}" RequestNavigate="Hyperlink_RequestNavigate">
                <TextBlock Text="{Binding Title}" />
                <Image Source="{Binding Thumbnail}" />
              
            </Hyperlink>
                    
          </TextBlock>
              </DataTemplate>
            </ListBox.ItemTemplate>
    
          </ListBox>
        </StackPanel>
        <StackPanel Grid.Row="1" Name="people">
          <ListBox ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollBar.Scroll="ListBox_Scroll_2" ItemsSource="{Binding People, Source={StaticResource model}}" />
    
        </StackPanel>
      </Grid>
    </Window>
    

    And here is the code of my RelevantDocument:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Drawing;
    
    namespace wpfTutorial
    {
      public class RelevantDocument
      {
        public string Path { get; set; }
        public string Title { get; set; }
        public Bitmap Thumbnail { get; set; }
        public string ThumbnailPath { get; set; }
        
        public RelevantDocument(string path, string title,string thumbpath){
          this.Path = path;
          this.Title = title;
          this.ThumbnailPath = thumbpath;
          try
          {
    
            this.Thumbnail = ShellThumbnailSingleton.Instance.GetThumbnail(path);
          }
          catch (Exception NoThumbCache) {
            this.Thumbnail = ShellThumbnailSingleton.Instance.GetThumbnail(@"C:\PersonalWeb\Thumbnails\DefaultRelevantDocument.png");
          }
          
          
        }
      }
    }
    


    The ShellThumbnailSingleton.Instance.GetThumbnail() returns a thumbnail given the file path in the bitmap format.

     

    Thank you for your help,

    Cheers


    Booleana
    Wednesday, July 27, 2011 6:47 PM

Answers

  • Like it says, you're in a different thread.

    Dispatcher.Invoke and an anonymous delegate is youre simplest way to get from one thread to another.

    So something like

    myImage.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate() { your code setting the source });

    By "something like", I don't mean it'll guaranteed cut and paste because I don't know which was created on what thread.

     

    You probably also want to google "changing UI controls from a different thread" and "Dispatcher.Invoke" for further reading.

    And of course anonymous delegates if that's also new to you.

    Hope this helps  ( and please vote if it does ).

    • Marked as answer by Yves.Z Tuesday, August 9, 2011 9:16 AM
    Friday, July 29, 2011 11:23 AM

All replies

  • I would think you want to go get the image in your model.

    Then expose the BitMapImage and bind to that.

    So you want some code something like:

    BitmapImage image = new BitmapImage();
    image.BeginInit();
    image.UriSource = new Uri( FullPath, UriKind.Absolute );
    image.EndInit();

    And of course a public property

    Wednesday, July 27, 2011 7:03 PM
  • Hi Andy!

    Thank you in advance, 

    In fact I don´t have any value in the ThumbnailPath Relevant Document property. I forgot to remove this property.

    I just have the Bitmap created on the fly. 

    So I just made an approach similar to the one that you suggested:

     

     private BitmapImage BitMapToBitMapImage(Bitmap image,string thumbPath) {
    
       try
       {  
    image.Save(thumbPath,System.Drawing.Imaging.ImageFormat.Bmp);
        BitmapImage bImg = new BitmapImage();
        bImg.BeginInit();
        bImg.UriSource = new Uri(thumbPath, UriKind.Absolute);
        this.ThumbnailPath = thumbPath;
    
        bImg.EndInit();
    
        return bImg;
       }
       catch (Exception e) {
        return null;
       }
      
      }
    

     


    A method to conver my Bitmap into a Bitmap image.

    After all, in the Window.xaml file I just made a binding to the ThumbnailPath instead of the Thumbnail bitmap.

    Ok... it seems to work, I just run the program and it is working... but I am creating new images and since I am getting bitmaps from a function that retrieves thumbnails from Windows cache...I guess I could just present the bitmap object in the interface, instead of saving the image and then bind to its fullpath... but I don´t know if it is possible and it was my first doubt:

    I don't know whether or not in WPF I can bind to image objects such as Bitmap.

    Thank you for your help,

    CHeers


    Booleana
    Wednesday, July 27, 2011 11:43 PM
  • Yes you can.

    You just use an Image object in your xaml and source="Binding myImageProperty"

    And of course stick your image in that property of your viewmodel or whatever you're binding to.

    Thursday, July 28, 2011 7:26 PM
  • Hi again!

    I just made the bind to the BitmapImage but It seems that I can not do this because "The calling thread cannot access this object because a different thread owns it." ...

     

    System.InvalidOperationException was unhandled

      Message="The calling thread cannot access this object because a different thread owns it."

      Source="WindowsBase"

      StackTrace:

           at System.Windows.Threading.Dispatcher.VerifyAccess()

           at System.Windows.Threading.DispatcherObject.VerifyAccess()

           at System.Windows.Freezable.get_IsFrozen()

           at System.Windows.Controls.Image.UpdateBaseUri(DependencyObject d, ImageSource source)

           at System.Windows.Controls.Image.OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

           at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)

           at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)

           at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)

           at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, OperationType operationType)

           at System.Windows.StyleHelper.ApplyTemplatedParentValue(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList`1& childRecordFromChildIndex, DependencyProperty dp, FrameworkElementFactory templateRoot)

           at System.Windows.StyleHelper.InvalidatePropertiesOnTemplateNode(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList`1& childRecordFromChildIndex, Boolean isDetach, FrameworkElementFactory templateRoot)

           at System.Windows.StyleHelper.LoadOptimizedTemplateContent(DependencyObject container, ParserContext parserContext, OptimizedTemplateContent optimizedTemplateContent, FrameworkTemplate frameworkTemplate, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)

           at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)

           at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)

           at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)

           at System.Windows.FrameworkElement.ApplyTemplate()

           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)

           at System.Windows.UIElement.Measure(Size availableSize)

           at System.Windows.Controls.Border.MeasureOverride(Size constraint)

           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)

           at System.Windows.UIElement.Measure(Size availableSize)

           at System.Windows.Controls.Control.MeasureOverride(Size constraint)

           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)

           at System.Windows.UIElement.Measure(Size availableSize)

           at System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint)

           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)

           at System.Windows.UIElement.Measure(Size availableSize)

           at System.Windows.ContextLayoutManager.UpdateLayout()

           at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)

           at System.Windows.Media.MediaContext.InvokeOnRenderCallback.DoWork()

           at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()

           at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)

           at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)

           at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)

           at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

           at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

           at System.Windows.Threading.DispatcherOperation.InvokeImpl()

           at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)

           at System.Threading.ExecutionContext.runTryCode(Object userData)

           at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)

           at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

           at System.Windows.Threading.DispatcherOperation.Invoke()

           at System.Windows.Threading.Dispatcher.ProcessQueue()

           at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

           at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

           at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)

           at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)

           at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

           at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

           at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)

           at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)

           at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)

           at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)

           at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)

           at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)

           at System.Windows.Threading.Dispatcher.Run()

           at System.Windows.Application.RunDispatcher(Object ignore)

           at System.Windows.Application.RunInternal(Window window)

           at System.Windows.Application.Run(Window window)

           at System.Windows.Application.Run()

           at wpfTutorial.App.Main() in C:\Users\Juliana\Documents\Visual Studio 2008\Projects\wpfTutorial\wpfTutorial\obj\Debug\App.g.cs:line 0

           at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)

           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)

           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)

           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

           at System.Threading.ThreadHelper.ThreadStart()

      InnerException: 

     

    Thank you 


    Booleana
    Thursday, July 28, 2011 11:21 PM
  • Like it says, you're in a different thread.

    Dispatcher.Invoke and an anonymous delegate is youre simplest way to get from one thread to another.

    So something like

    myImage.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate() { your code setting the source });

    By "something like", I don't mean it'll guaranteed cut and paste because I don't know which was created on what thread.

     

    You probably also want to google "changing UI controls from a different thread" and "Dispatcher.Invoke" for further reading.

    And of course anonymous delegates if that's also new to you.

    Hope this helps  ( and please vote if it does ).

    • Marked as answer by Yves.Z Tuesday, August 9, 2011 9:16 AM
    Friday, July 29, 2011 11:23 AM
  •  

    We are marking this issue as "Answered". If you have any new findings or concerns, please feel free to unmark the issue. 

    Best regards


    Yves Zhang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, August 9, 2011 9:16 AM