2

I created a UserControl consisting of a Grid which contains a single Image-control.

<UserControl
    x:Class="Album.AlbumPicture"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Album"
    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"
    Width="200"
    Height="200"
    >

    <Grid Width="200" Height="200">
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Image Name="AlbumPictureImage" Width="200" Height="200" Grid.Column="0" Grid.Row="0"  />
    </Grid>
</UserControl>

Now, I had a constructor that took an existing Image (newly created from a Stream) and assigned the Image to my custom control's Image

AlbumPicture::AlbumPicture(Windows::UI::Xaml::Controls::Image^ Image){
InitializeComponent();
this->AlbumPictureImage = Image;
this->Height = 200;
this->Width = 200;
this->state = AlbumPictureState::SWIPE;
this->StartingPoint = Point(0,0);
} 

In order to make sure my UserControl was appended to the layout-container, I made the Background of the Grid white and it displayed fine. I also added the Image directly to the layout-container and it was displayed properly.


Now, when I change the constructor to

AlbumPicture::AlbumPicture(Windows::UI::Xaml::Media::ImageSource^ Source){
InitializeComponent();
this->AlbumPictureImage->Source = Source;
this->Height = 200;
this->Width = 200;
this->state = AlbumPictureState::SWIPE;
this->StartingPoint = Point(0,0);
}

everything works fine and the Image will be displayed. What is the catch here?

5
  • Forgive me for asking, but what is the question you are asking? Commented May 7, 2013 at 19:51
  • @JerryNixon-MSFT using .NET/C# I am used to relative simple assignments and I am lacking knowledge of WPF, too. I expected, that if I simply assigned an Image-control-reference to the Image of my UserControl, it will be properly displayed, but nothing shows if I used my first approach. I just don't get why it does not get displayed...
    – bash.d
    Commented May 7, 2013 at 20:12
  • Using C# huh? Looks more like C++/CX to me. Having said that, are you adding the new image to the Container.Children collection so it is included in the XAML visual tree? Commented May 8, 2013 at 15:55
  • It is polite to mark the correct/best answer. Commented Jun 20, 2013 at 15:30
  • Sorry, I thought I did...
    – bash.d
    Commented Jun 20, 2013 at 16:44

2 Answers 2

1

So I'm actually a C#/Xaml dev, but I think the reason is that you're setting the reference of control to the new Image, but not updating the Visual Tree at all. You may just be changing the reference of the 'this.AlbumPictureImage' object, while the visual tree (i.e. the FrameworkElement's with the Parent/Children references) retains the old reference.

When you load the actual image into the referenced Image object in the second example, you're not changing (or attempting to change) the visual tree at all, so the control is displayed.

The way I see it, if I'm right, you have two options:

  • Change the visual tree itself. Remove the reference to the child in the Image Control's parent, then add the new image control in.

  • Set the image source of the old image control in the tree to that of the new image in the tree.

The first one is much more difficult and fraught with peril, especially if any of this is meant to be async. I'm pretty sure the Image control knows to use the dispatcher to set its image source, so the second option should be covered there. You definitely don't get that protection with the first, so you'll want to make sure to marshal to the UI thread (using the dispatcher), just in case the async thread doesn't have UI access.

The second option should also be pretty simple to implement. I absolutely apologize if this code is horrible or mangled, as I said:

AlbumPicture::AlbumPicture(Windows::UI::Xaml::Controls::Image^ Image){
InitializeComponent();
this->AlbumPictureImage->Source = Image::Source
this->Height = 200;
this->Width = 200;
this->state = AlbumPictureState::SWIPE;
this->StartingPoint = Point(0,0);
} 

I don't know if the source can be the same for two controls, so you may need to detach it somehow, or grab the underlying stream and create a new ImageSource object from the stream itself.

Good coding!

3
  • +1 Thank you for your response. I actually tried your second suggestion in code. It works, but looks very clumsy (not that this is your fault or anything!!!)
    – bash.d
    Commented May 7, 2013 at 18:48
  • Yeah, I think they much prefer you pass around the data instead of the control itself, such as in your second example. I know that's not always possible, but it's probably safer to do it that way if you can. Commented May 7, 2013 at 19:26
  • Well, this goes to my work with .NET/C#, which is a little more "developer-friendly" than WinRT in my beliefs, at least for beginners in this area.
    – bash.d
    Commented May 7, 2013 at 20:15
1

Well, let's pretend you have a usercontrol like this:

<UserControl Loaded="UserControl_Loaded_1">
    <Grid>
        <Image x:Name="MyImage" />
    </Grid>
</UserControl>

As you can see, I am going to use the loaded event instead of the constructor of the user control. But it should result in the same implementation.

In the loaded event, I want to take a stream (in this case, I will use a BitmapImage type) and set that to an existing image, as you describe in your question above:

private void UserControl_Loaded_1(object sender, RoutedEventArgs e)
{
    var _Url = new Uri("ms-appx:///assets/logo.png");
    var _Image = new Image
    {
        Source = new BitmapImage(_Url)
    };
    this.MyImage.Source = _Image.Source;
}

Yes, that is C#, not C++/CX. But I think it makes the point.

So, I then set the source of my usercontrol's image source property to the source property of my existing image control. It's a simple property assignment. This works fine. The previously existing image control can be thrown away. The image in the usercontrol will show the previous image control's image for you.

I strongly recommend you review the CacheMode property of your image control as it might throw you for a loop if you don't understand what it is doing. Here are what the meta comments say:

//     A value that indicates that rendered content should be cached when possible.
//     If you specify a value of CacheMode, rendering operations from RenderTransform
//     and Opacity execute on the graphics processing unit (GPU), if available.
//     The default is null, which does not enable a cached composition mode.

Best of luck.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.