سؤال

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?

هل كانت مفيدة؟

المحلول

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!

نصائح أخرى

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top