2

I have the option to add a new Customer in my application. The Customer is stored in the DB with its ID, Name, and Logo. Logo is just the string of the image file (like logo.png)

The adding of the logo seems fine. When I select an Image, it shows in the CustomerAddView.

After adding the Customer, the CustomerAddView window closes. The Customer is created in the DB, the Logo value in the DB is fine.
The list of Customers in the main window is refreshed (CustomerListView). The other Customer's Logo's are working fine. But the new Customer's Logos (added with the AddView window) throw this warning:

System.Windows.Data Warning: 6 : 'DynamicValueConverter' converter failed to convert value '../../Media/Images/Logos/testlogo.png' (type 'String'); fallback value will be used, if available. BindingExpression:Path=Logo; DataItem='Customer_5A59789E69DE0B010CE32D4E23A696EDB09551158A85050E8CA80E51475D369B' (HashCode=45868004); target element is 'Image' (Name=''); target property is 'Source' (type 'ImageSource') IOException:'System.IO.IOException: Kan bron media/images/logos/testlogo.png niet vinden.
   bij MS.Internal.AppModel.ResourcePart.GetStreamCore(FileMode mode, FileAccess access)
   bij System.IO.Packaging.PackagePart.GetStream(FileMode mode, FileAccess access)
   bij System.IO.Packaging.PackWebResponse.CachedResponse.GetResponseStream()
   bij System.IO.Packaging.PackWebResponse.GetResponseStream()
   bij System.IO.Packaging.PackWebResponse.get_ContentType()
   bij System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri, Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable, Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream, SafeFileHandle& safeFilehandle)
   bij System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
   bij System.Windows.Media.Imaging.BitmapFrame.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy)
   bij System.Windows.Media.ImageSourceConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
   bij MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)
   bij MS.Internal.Data.TargetDefaultValueConverter.Convert(Object o, Type type, Object parameter, CultureInfo culture)
   bij MS.Internal.Data.DynamicValueConverter.Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
   bij System.Windows.Data.BindingExpression.ConvertHelper(IValueConverter converter, Object value, Type targetType, Object parameter, CultureInfo culture)'
System.Windows.Data Error: 11 : Fallback value 'Default' (type 'String') cannot be converted for use in 'Source' (type 'ImageSource'). BindingExpression:Path=Logo; DataItem='Customer_5A59789E69DE0B010CE32D4E23A696EDB09551158A85050E8CA80E51475D369B' (HashCode=45868004); target element is 'Image' (Name=''); target property is 'Source' (type 'ImageSource') NullReferenceException:'System.NullReferenceException: De objectverwijzing is niet op een exemplaar van een object ingesteld.
   bij System.Windows.Media.ImageSourceConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
   bij System.Windows.Data.BindingExpressionBase.ConvertValue(Object value, DependencyProperty dp, Exception& e)'

I would like to know why my logo image is there in the File Explorer, in the specified folder, but isn't displayed in the list of Customers as it should.
And I want to know why the images do work when added via Visual Studio's Solution Explorer, but don't work when I add them (to the same folder) via the CustomerAddView(Model).

Here's the files for adding a new Customer: CustomerAddView:

<Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>

        <TextBlock Name="TBCustomerTitle" FontWeight="Bold">Customer name:</TextBlock>
        <TextBlock Grid.Column="1" FontWeight="Bold" Margin="5,0">*</TextBlock>
        <TextBox Name="TBCustomerData" Grid.Column="2" Grid.ColumnSpan="2"
                 Text="{Binding NewCustomer.Name, UpdateSourceTrigger=PropertyChanged}"></TextBox>

        <TextBlock Grid.Row="1" FontWeight="Bold">Customer logo:</TextBlock>
        <Image Grid.Row="1" Grid.Column="2" MaxHeight="100" MaxWidth="100"
               Source="{Binding NewCustomerLogo, UpdateSourceTrigger=PropertyChanged}" />
        <Button Grid.Row="1" Grid.Column="3" Content="Choose logo" 
                Command="{Binding SelectLogoCommand}"/>

        <TextBlock Margin="0,10" Grid.Row="2" Grid.ColumnSpan="4">Fields marked with * are required fields.</TextBlock>

        <Button Grid.Row="3" Grid.ColumnSpan="4" Margin="0,50,0,0"
                Command="{Binding AddConfirmCommand}">Add this customer</Button>
    </Grid>

CustomerAddViewModel:

class CustomerAddViewModel : INotifyPropertyChanged
    {
        private RelayCommand addConfirmCommand;
        private RelayCommand selectLogoCommand;
        Image customerLogo;
        string logoDirectory = "../../Media/Images/Logos/";
        DBCustomer dbCustomer = new DBCustomer();

        #region Add Customer
        public ICommand AddConfirmCommand
        {
            get { return addConfirmCommand ?? (addConfirmCommand = new RelayCommand(() => AddConfirmCustomer())); }
        }

        private void AddConfirmCustomer()
        {
            if(newCustomer.Logo != null)
            {                
                customerLogo.Save(logoDirectory + newCustomer.Logo);                
            }
            else
            {
                newCustomer.Logo = "Default.png";
            }
            if (!dbCustomer.Create(newCustomer))
            {
                return;
            }
            App.Messenger.NotifyColleagues("AddCustomerDone");
        }
        #endregion

        #region Add logo
        public ICommand SelectLogoCommand
        {
            get { return selectLogoCommand ?? (selectLogoCommand = new RelayCommand(() => SelectLogo())); }
        }

        private void SelectLogo()
        {
            OpenFileDialog chooseFile = new OpenFileDialog();
            chooseFile.Title = "Select a logo";
            chooseFile.Filter = "All supported graphics|*.jpg;*.jpeg;*.png|" +
              "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
              "Portable Network Graphic (*.png)|*.png";
            if(chooseFile.ShowDialog() == DialogResult.OK)
            {
                Stream reader = File.OpenRead(chooseFile.FileName);
                customerLogo = System.Drawing.Image.FromStream((Stream)reader);

                MemoryStream finalStream = new MemoryStream();
                customerLogo.Save(finalStream, ImageFormat.Png);

                // translate to image source
                PngBitmapDecoder decoder = new PngBitmapDecoder(finalStream, BitmapCreateOptions.PreservePixelFormat,
                                                    BitmapCacheOption.Default);
                NewCustomerLogo = decoder.Frames[0];
                newCustomer.Logo = newCustomer.Name + ".png";
            }            
        }

        private ImageSource newCustomerLogo;
        public ImageSource NewCustomerLogo
        {
            get
            {
                return newCustomerLogo;
            }
            set
            {
                newCustomerLogo = value;
                OnPropertyChanged(new PropertyChangedEventArgs("NewCustomerLogo"));
            }
        }
        #endregion

        private Customer newCustomer = new Customer();
        public Customer NewCustomer
        {
            get { return newCustomer; }
            set { newCustomer = value; OnPropertyChanged(new PropertyChangedEventArgs("NewCustomer")); }
        }

        #region PropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }
        #endregion
    }

CustomerListView

                <ListBox.ItemTemplate>
                <!-- This DataTemplate is used for every Customer object in the ListBox.-->
                <DataTemplate>
                    <Border BorderThickness="2" BorderBrush="Black"
                    Padding="10" Margin="10"
                    Name="CustomerBorder">

                        <Grid Name="ItemGrid">
                            <Grid.RowDefinitions>
                                <RowDefinition/>
                                <RowDefinition/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>

                            <!-- Logo picture -->
                            <Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" HorizontalAlignment="Center"
                                   Source="{helpers:ConcatString FrontString=../../Media/Images/Logos/, BindTo={Binding Path=Logo, FallbackValue=Default}}"                         
                                   Height="{Binding ActualHeight, ElementName=ItemGrid}"/>

                            <!-- Customer name Row-->
                            <TextBlock Grid.Row="0" Grid.Column="1" Margin="10,0,8,0" FontWeight="Bold"
                               Name="CustomerTitle">
                               Customer:
                            </TextBlock>
                            <TextBlock Grid.Row="0" Grid.Column="2" 
                               Name="CustomerDataType" 
                               Text="{Binding Path=Name}">
                            </TextBlock>

                            <!-- Environment name Row-->
                            <TextBlock Grid.Row="1" Grid.Column="1" Margin="10,0,8,0" FontWeight="Bold" />
                            <TextBlock Grid.Row="2" Grid.Column="1" Margin="10,0,8,0" FontWeight="Bold" />
                        </Grid>
                    </Border>                    
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

EDIT:
This screenshot might shed some light on my confusion. The problem I added the testlogo.png via the CustomerAddView(Model), the other 3 were added right in VS Solution Explorer. As you can see:

  • The logo's are all in the same directory.
  • Only the logo's added via VS Solution Explorer show in VS Solution Explorer. The new one doesn't.
  • The new logo doesn't show in the CustomerListView. The others do.

EDIT 2:
Is it maybe a better idea to save the image to the database instead of saving the file name as a string in the database?

Kailayla
  • 323
  • 5
  • 15
  • The binding path should certainly be `NewCustomer.Logo` not `NewCustomerLogo`. Besides that, you don't need to set `UpdateSourceTrigger=PropertyChanged` on any one-way binding. It's redundant and has no effect. – Clemens Apr 15 '16 at 12:53
  • The binding in the CustomerAddView window is working correctly as I already stated. It's the CustomerListView (which I just added in the original post) that is not showing it when added via the CustomerAddView, but when I add them directly into Visual Studio they do work. – Kailayla Apr 15 '16 at 13:04
  • And you have seen this in the output: `System.IO.IOException: Kan bron media/images/logos/testlogo.png niet vinden`? Which apparently is not `../../media/images/logos/testlogo.png`. – Clemens Apr 15 '16 at 13:07
  • It seems, from the exception that you pasted, that he cannot find the image located at `media/images/logos/testlogo.png`, that might be your issue there. – Gimly Apr 15 '16 at 13:07
  • I added a screenshot to my original post. The logo is saved in the same directory the others were in before I decided to make a function for the user to add one via the application. Yet, the old logo's do work and the new one doesn't. While they're in the same directory. It's pointing to the right directory, and according to Windows File Explorer, it is there. Windows says yes, VS says no and my application says no. This is where I am confused. – Kailayla Apr 15 '16 at 13:33

1 Answers1

0

MSDN says:

To access files stored inside the application package, but from code where there is no inferred root authority, specify the ms-appx: scheme.

var uri = new System.Uri("ms-appx:///images/logo.png");
acidbabies
  • 97
  • 7
  • I tried using this in the XAML that should get the logo, as posted in my OP. I changed the Source property of the image to `Source="{helpers:ConcatString FrontString=ms-appx:///Media/Images/Logos/, BindTo={Binding Path=Logo, FallbackValue=Default}}"` Still, it throws an exception, mostly the same as in the OP but also a new one, it says: `NotSupportedException:'System.NotSupportedException: The URI prefix is not recognized` When I just put in Source="ms-appx:///Media/Images/Logos/Vodafone.png" (an image I added throught VS and that was working b4) it shows nothing, no img and no exception. – Kailayla Apr 19 '16 at 09:05
  • 1
    That MSDN article is about Window Store/UWP apps, while the question is about WPF. An `ms-appx://` URI won't work in WPF. – Clemens Apr 21 '16 at 12:58