简体   繁体   中英

Image control doesn't get rendered

I am trying to create a WPF application with multiple small editors. One of these editors requires to load two images, enter a name in a TextBox and hit a save button.

In the code this does work flawless. The files are saved in a model and the image can be loaded. Before hitting the save button both of the images are actually shown in the editor. However after reopening (for editing) only one image is rendered.

I tested a bit around and found out that always the first image doesn't get rendered while the second does.

For example in the XAML it looks like this:

<Image Name="BackgroundImage" Grid.Row="1" Grid.Column="0" Source="{Binding Path=Background}" Width="120" Height="90"/>
<Image Name="ForegroundImage" Grid.Row="2" Grid.Column="0" Source="{Binding Path=Foreground}" Width="120" Height="90"/>

Here BackgroundImage doesn't get rendered, even though the property Background of the model has loaded the image successfully. If I were to swap these XAML Tags, meaning putting the ForegroundImage control above the BackgroundImage , then ForegroundImage doesn't get rendered while BackgroundImage does. Even if I don't change anything else like the Grid.Row or Column.

Then I tried to load the images in the code behind in the Loaded event handler of the window:

private void LocationEditor_OnLoaded(object sender, RoutedEventArgs e)
{
    BackgroundImage.Source = ((Location)DataContext).Background;
    ForegroundImage.Source = ((Location)DataContext).Foreground;
}

The same applies to this situation. Whichever line is executed first, won't be rendered in the Window.

In case it'll help, here's the code of the Background property ( Foreground is built the same):

[JsonIgnore]
public BitmapImage Background
{
    get
    {
        if (!string.IsNullOrWhiteSpace(BackgroundFile))
        {
            SetFree();
            SetImage();
        }
        else
            _background = null;
        return _background;
    }
}

The SetFree() method frees up memory resources if the image isn't needed anymore. This occurs when the window closes or whenever the BitmapImage is needed. (It'll reload the image each time in case the file of the image has changed.)

The SetImage() method does just one simple thing: Loading the image of the BackgroundFile image file and saves it in the _background field.


I don't quite know what the problem could be. I've tried out a few things but I don't work often with images while coding.

There must be something wrong with your SetFree() or SetImage() methods.

Fortunately you don't need the Background and Foreground properties in your view model at all, because WPF provides built-in automatic type conversion from string , Uri and byte[] to ImageSource . You can hence directly bind the Image's Source properties to the appropriate path properties in the view model:

<Image ... Source="{Binding BackgroundFile}"/>
<Image ... Source="{Binding ForegroundFile}"/>

For completeness, if you still wanted to have these properties, i'd suggest a simple implementation like shown below. Built-in image caching will take care that the file is not decoded more often than necessary:

public ImageSource Background
{
    get
    {
        if (BackgroundFile != null)
        {
            try
            {
                return new BitmapImage(new Uri(BackgroundFile));
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        return null;
    }
}

Binding problems can be tricky to troubleshoot. Sometimes the timing that the binding is evaluated isn't obvious or doesn't seem to make sense. I know this is a generic answer, but one trick I use is to add a "debug converter" for bindings that I am having trouble with that can debug during evaluation. It has saved me a few times.

<UserControl
 xmlns:converters="clr-namespace:WhateverYourNamespaceIs.Converters">
<UserControl.Resources>
<converters:DebugConverter x:Key="DebugConverter"/>
</UserControl.Resources>

<Image Name="BackgroundImage" Grid.Row="1" Grid.Column="0" Source="{Binding Path=Background, Converter={StaticResource DebugConverter}" Width="120" Height="90"/>




Here is an example of the converter.

public sealed class DebugConverter : IValueConverter
    { 


        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            //Debug.WriteLine("Debug Converter Value:" + value.ToString());
            // Since you are working with graphics, maybe just dump the size
Debug.WriteLine("Debug Converter Value:" + value.Length().ToString());
            return (value);
        }


        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM