2013-06-05 4 views
1

Я работаю над цифровым приложением вывесок WPF и базовая структура настроена следующим образом:WPF MVVM DataTemplates - Просмотр Не обновление

У меня есть один вид с сеткой в ​​ней, связанной с объектом списка воспроизведения. Плейлист содержит панели, панели содержат элементы списка воспроизведения, а элементы списка воспроизведения содержат элемент контента. Я использую DataTemplates для создания представления для каждой части, например.

<!-- This template represents a single content pane, no real display here, just empty space with a height and width --> 
    <DataTemplate DataType="{x:Type entities:ContentPane}"> 
     <ContentControl 
      Content="{Binding CurrentPlaylistItem, Mode=OneWay}" 
      Height="{Binding Height, Mode=OneTime}" 
      Width="{Binding Width, Mode=OneTime}" 
      HorizontalAlignment="Left" 
      VerticalAlignment="Top"     
      /> 
    </DataTemplate> 

    <!-- This is a playlist item which is contained within a ContentPane. 
     This also has no real display, just a placeholder for the content item, and will likely contain some transition information--> 
    <DataTemplate DataType="{x:Type entities:PlaylistItem}"> 
     <inf:TransitionableContentControl Content="{Binding ContentItem}"></inf:TransitionableContentControl> 
    </DataTemplate> 


    <!-- image item template 
     the path can be any valid uri e.g. http://... or file://... --> 
    <DataTemplate DataType="{x:Type contentTypes:ImageContentType}"> 
     <Grid Background="Transparent" x:Name="ImageType"> 
      <Image Source="{Binding Bitmap, Mode=OneTime}"></Image> 
      <inf:BusinessAd 
         ContainerHeight="{Binding ImageHeight, Mode=OneTime}" 
         ContainerWidth="{Binding ImageWidth, Mode=OneTime}"        
         Visibility="{Binding AdText, Converter={StaticResource _VisibilityConverter}, Mode=OneWay}" 
         Text="{Binding AdText.Text, Mode=OneTime}" 
         AdFontSize="{Binding AdText.TextStyle.FontSize}" 
         AdFontFamily="{Binding AdText.TextStyle.FontFamily}"> 
       <ContentControl 
        Content="{Binding AdText, Mode=OneTime}"       
        ContentTemplate="{StaticResource BusinessAdTextTemplate}"> 
       </ContentControl> 
      </inf:BusinessAd> 
     </Grid> 
    </DataTemplate> 

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

Я попытался сделать OnPropertyChanged ("ContentItem") в классе PlaylistItem, попробовал параметр Shared = "False" в моих шаблонах данных, я попытался изменить свойства объекта ContentItem и поднял события PropertyChanged, ничего не работает. Я включил отслеживание привязки данных, чтобы увидеть, что происходит, и все работает правильно. Когда я изменяю свойства в ContentItem, он показывает новый хеш для нового элемента, но никаких изменений в пользовательском интерфейсе не происходит.

Внутри TransitionableContentControl в PlaylistItem переопределение OnContentChanged никогда не попадает при переходе от одного элемента контента к одному и тому же. Если я поменяю этот контроль с помощью обычного ContentControl, никаких изменений.

+0

Вы пытались изменить режим с 'OneTime' на' OneWay'? –

+0

Да, не имеет никакого эффекта –

+0

Если бы вы могли каким-то образом предоставить образец проекта, который воспроизводит проблему, я был бы рад изучить это дальше. – Stipo

ответ

1

Бывший сотрудник имеет правильные сведения о диагнозе. Кроме того, если вам не удастся повторно назначить внутренние datacontexts, ваши шаблоны не будут перезапускаться с самого начала, как вы заметили. Вам придется назначить свой CurrentPlaylistItem на какой-то по умолчанию пустой элемент, чтобы сбрасывать все вещи до конца. Чтобы избежать гонок и мерзкого мерцания, сделайте это на приоритете диспетчера выше, чем в режиме отображения пользовательского интерфейса. Попробуйте следующее:

// CurrentPlaylistItem = pli ; -- not good 
Application.Current.Dispatcher.Invoke (new Action (() => 
{ 
    // clear item 
    // null doesn't work, because TransitionableContentControl's 
    // inner ContentControl would be empty and the brush created 
    // from it would be a null brush (no visual effect) 
    CurrentPlaylistItem = new PlaylistItem() ; 
    this.OnPropertyChanged ("CurrentPlaylistItem") ; 
    Application.Current.Dispatcher.Invoke (new Action (() => 
    { 
     // set new item, possibly same as old item 
     // but WPF will have forgotten that because 
     // data bindings caused by the assignment above 
     // have already been queued at the same DataBind 
     // level and will execute before this assignment 
     CurrentPlaylistItem = pli ; 
     this.OnPropertyChanged ("CurrentPlaylistItem") ; 
    }), DispatcherPriority.DataBind) ; 
})) ; 
+0

Это также не имеет никакого эффекта. Он не компилируется, как есть, я обновил его, чтобы использовать DispatcherPriorty, перегрузку Action и не влиять на приложение. Я также попытался установить ContentItem из PlaylistItem на новый пустой объект и без изменений. –

+0

Yup, забыли вставить мои дополнения из вашего тестового приложения. Конечно, это не имело никакого эффекта: поскольку OnPropertyChanged не вызывался, WPF никогда не знал, что свойство изменилось. –

1

Проблема в том, что ContentControl (или, скорее, базовая инфраструктура DependencyProperty) не запускает OnContentChanged, когда .Equals верно для старого и нового контента. Одним из способов является наличие собственной зависимости и переход на CoerceValue. Я напишу вам код, и вы можете опубликовать его здесь.

+0

Отличное имя пользователя. В любом случае, как я упоминал в своем письме, он переходит, но новый элемент находится в конечном состоянии. Для видео, которое означает, что оно застряло в последнем кадре, когда оно переходит к следующему элементу. –

Смежные вопросы