Назначить изображение вместо потока для Windows::UI::Xaml::Controls::Image

Я создал UserControl, состоящий из Grid, который содержит один элемент управления Image.

<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>

Теперь у меня был конструктор, который брал существующий Image (недавно созданный из Stream) и назначал Image 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);
} 

Чтобы убедиться, что мой UserControl был добавлен к контейнеру макета, я сделал Background из Grid белым, и он отображался нормально. Я также добавил Image непосредственно в макет-контейнер, и он отобразился правильно.


Теперь, когда я меняю конструктор на

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);
}

все работает нормально и будет отображаться Image. В чем тут подвох?


person bash.d    schedule 07.05.2013    source источник
comment
Простите, что спрашиваю, а какой вопрос вы задаете?   -  person Jerry Nixon    schedule 07.05.2013
comment
@JerryNixon-MSFT с использованием .NET/C# Я привык к относительно простым заданиям, и мне тоже не хватает знаний о WPF. Я ожидал, что если я просто назначу Image-control-reference для Image моего UserControl, он будет отображаться правильно, но ничего не показывает, если я использовал свой первый подход. Я просто не понимаю, почему он не отображается...   -  person bash.d    schedule 08.05.2013
comment
Используя С#, да? Для меня это больше похоже на C++/CX. Сказав это, добавляете ли вы новое изображение в коллекцию Container.Children, чтобы оно было включено в визуальное дерево XAML?   -  person Jerry Nixon    schedule 08.05.2013
comment
Вежливо отметить правильный/лучший ответ.   -  person Jerry Nixon    schedule 20.06.2013
comment
Извините, я думал, что сделал...   -  person bash.d    schedule 20.06.2013


Ответы (2)


Так что на самом деле я разработчик C#/Xaml, но думаю, причина в том, что вы устанавливаете ссылку на элемент управления на новое изображение, но вообще не обновляете визуальное дерево. Возможно, вы просто меняете ссылку на объект this.AlbumPictureImage, в то время как визуальное дерево (то есть FrameworkElement со ссылками Parent/Children) сохраняет старую ссылку.

Когда вы загружаете фактическое изображение в указанный объект Image во втором примере, вы вообще не изменяете (или не пытаетесь изменить) визуальное дерево, поэтому элемент управления отображается.

Как я это вижу, если я прав, у вас есть два варианта:

  • Измените само визуальное дерево. Удалите ссылку на дочерний элемент в родительском элементе управления изображением, затем добавьте новый элемент управления изображением.

  • Установите источник изображения старого элемента управления изображением в дереве на источник нового изображения в дереве.

Первый намного сложнее и чреват опасностью, особенно если что-то из этого должно быть асинхронным. Я почти уверен, что элемент управления Image знает, как использовать диспетчер для установки источника изображения, поэтому второй вариант должен быть описан там. Вы определенно не получите эту защиту с первым, поэтому вам нужно убедиться, что вы маршалируете в поток пользовательского интерфейса (используя диспетчер), на случай, если асинхронный поток не имеет доступа к пользовательскому интерфейсу.

Второй вариант также должен быть довольно простым в реализации. Я абсолютно извиняюсь, если этот код ужасен или искажен, как я уже сказал:

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);
} 

Я не знаю, может ли источник быть одинаковым для двух элементов управления, поэтому вам может потребоваться как-то его отсоединить или взять базовый поток и создать новый объект ImageSource из самого потока.

Хорошее кодирование!

person Nate Diamond    schedule 07.05.2013
comment
+1 Спасибо за ваш ответ. Я действительно попробовал ваше второе предложение в коде. Это работает, но выглядит очень неуклюже (не то чтобы это ваша вина или что-то в этом роде!!!) - person bash.d; 07.05.2013
comment
Да, я думаю, они предпочитают, чтобы вы передавали данные, а не сам элемент управления, как в вашем втором примере. Я знаю, что это не всегда возможно, но, вероятно, безопаснее сделать так, если вы можете. - person Nate Diamond; 07.05.2013
comment
Что ж, это относится к моей работе с .NET/C#, который, на мой взгляд, немного более удобен для разработчиков, чем WinRT, по крайней мере, для новичков в этой области. - person bash.d; 08.05.2013

Что ж, давайте представим, что у вас есть usercontrol вот так:

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

Как видите, я собираюсь использовать событие loaded вместо события constructor пользовательского элемента управления. Но это должно привести к той же реализации.

В событии loaded я хочу взять stream (в данном случае я буду использовать тип BitmapImage) и установить его на существующее изображение, как вы описали в своем вопросе выше:

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;
}

Да, это C#, а не C++/CX. Но я думаю, что это имеет значение.

Затем я установил источник свойства source моего изображения usercontrol в свойство source моего существующего элемента управления image. Это простое присвоение свойств. Это прекрасно работает. Ранее существовавший элемент управления image можно выбросить. image в usercontrol покажет вам изображение предыдущего элемента управления image.

Я настоятельно рекомендую вам просмотреть свойство CacheMode вашего элемента управления image, поскольку оно может поставить вас в тупик, если вы не понимаете, что он делает. Вот что говорят мета-комментарии:

//     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.

Удачи.

person Jerry Nixon    schedule 08.05.2013