2013-03-24 22 views
7

Próbuję wyświetlić niektóre obrazy w ListView i nie udało się. Używam WPF MVVM i ListView jest holdover z po prostu wyświetlanie kolorów i danych rangi. (Zobacz mój poprzedni post: MVVM in WPF - How to alert ViewModel of changes in Model... or should I? jeśli jesteś zainteresowany!) To znaczy, mógłbym użyć czegoś innego niż ListView (jeśli to jest rada), ale wciąż chciałbym wiedzieć jak to zrobić z ListView, przy założeniu, że jest to wykonalne. Moja własność Jestem wiązania w ViewModel jest:Wyświetlanie obrazów w ListView (lub coś lepszego!) W WPF MVVM przy użyciu databinding

public ObservableCollection<Image> PlayerCardImages{ 
    get{ 
     ObservableCollection<Image> results = new ObservableCollection<Image>(); 
     foreach (CardModel card in PlayerCards) 
     { 
      Image img = new Image(); 
      BitmapImage bi3 = new BitmapImage(); 
      bi3.BeginInit(); 
      // TODO: Pick card based on suit/rank. Just get 1 image working now 
      bi3.UriSource = new Uri("diamond-1.png", UriKind.Relative); 
      bi3.EndInit(); 
      img.Stretch = Stretch.Fill; 
      img.Source = bi3;    
      results.Add(img); 
     } 
     return results; 
    } 
} 

W moim kodu XAML Używam:

<Window.Resources> 
<DataTemplate x:Key="ImageCell"> 
     <StackPanel Orientation="Horizontal"> 
      <Image Source="{Binding PlayerCardImages}" Width="200" Height="200" Stretch="Fill" ToolTip="Add tooltip"/> 
     </StackPanel> 
    </DataTemplate> 
</Window.Resources> 

<StackPanel Orientation="Vertical"> 
<Label Content="Player Cards"/> 
     <ListView Name="lvwTitles" ItemsSource="{Binding}" 
IsSynchronizedWithCurrentItem="True" 
SelectionMode="Single" ItemTemplate="{StaticResource ImageCell}" Height="59"> 
     </ListView> 
    </StackPanel> 

Ten pomysł został bezczelnie skradzione: WPF - bind images horizontally to ListView jednak nie robi” Wygląda na to, że nawet w Punkcie Uderzeniowym PlayerCena nie jest trafiony.

Próbowałem również następujące XAML z nieco więcej szczęścia:

<StackPanel Orientation="Vertical"> 
     <Label Content="Player Cards"/> 
     <ListView 

     AlternationCount="2" 
     DataContext="{StaticResource PlayerCardsGroups }" 
     ItemsSource="{Binding}" 
     > 
      <ListView.GroupStyle> 
       <StaticResourceExtension 
       ResourceKey="CardGroupStyle" 
       /> 
      </ListView.GroupStyle> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn> 
       <Image Height="50" Width="40"></Image> 
        </GridViewColumn> 
       </GridView>     
      </ListView.View> 
     </ListView> 
    </StackPanel> 
    <Window.Resources> 
    <CollectionViewSource x:Key="PlayerCardsGroups" 
     Source="{Binding Path=PlayerCardImages}"> 
    </CollectionViewSource> 

    <GroupStyle x:Key="CardGroupStyle"> 
     <GroupStyle.HeaderTemplate> 
      <DataTemplate> 
       <TextBlock 
     x:Name="txt" 
     Background="{StaticResource Brush_HeaderBackground}" 
     FontWeight="Bold" 
     Foreground="White" 
     Margin="1" 
     Padding="4,2,0,2" 
     Text="Cards" 
     /> 
      </DataTemplate> 
     </GroupStyle.HeaderTemplate> 
    </GroupStyle> 

    <Style x:Key="CardItemStyle" TargetType="{x:Type ListViewItem}"> 
     <!-- 
    Stretch the content of each cell so that we can 
    right-align text in the Total Sales column. 
    --> 
     <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
     <!-- 
    Bind the IsSelected property of a ListViewItem to the 
    IsSelected property of a CustomerViewModel object. 
    --> 
     <Style.Triggers> 
      <MultiTrigger> 
       <MultiTrigger.Conditions> 
        <Condition Property="ItemsControl.AlternationIndex" Value="1" /> 
        <Condition Property="IsSelected" Value="False" /> 
        <Condition Property="IsMouseOver" Value="False" /> 
       </MultiTrigger.Conditions> 
       <Setter Property="Background" Value="#EEEEEEEE" /> 
      </MultiTrigger> 
     </Style.Triggers> 
    </Style> 

    </Window.Resources> 

ten kod zdecydowanie przechodzi wiązania z danymi - mój punkt przerwania jest trafiony na początku programu i kiedy elementy są dodawane do kolekcji. Ale nie wyświetla się żaden obraz. Zamiast torturować większą ilością XAML, która nie działa, być może mógłbym poprosić kogoś, aby wskazał mi jakiś kod/przykłady/dokumenty, które pokazują, jak powiązać listę obrazów z ListView (lub inną kontrolką, jeśli naprawdę uważasz, że ListView jest niewłaściwy). Zauważ, że moja kolekcja to rzeczy, do których się zobowiązuję. Zauważam, że na wielu przykładach są one wiążące dla podwłasności. To znaczy. mogą mieć kolekcję albumów i dla każdego albumu wiążą się z jego obrazem właściwości (patrz: Showing items as images in a WPF ListView).

Wszelkie pomysły i pomoc będą mile widziane.

-Dave

Dodatkowe info.

podstawie sugestii Clemens, teraz mam ten kod do PlayerCardImages:

public ObservableCollection<ImageSource> PlayerCardImages 
    { 
     get 
     { 
      var results = new ObservableCollection<ImageSource>(); 

      //if (PlayerCards.Count == 0) 
      // return results; 
      //else 
      //{ 
      // results.Add(new BitmapImage(new Uri(@"Images\\" + "diamond-1.png", UriKind.Relative))); 
      //} 
      foreach (var card in PlayerCards) 
      { 
       results.Add(new BitmapImage(new Uri(@"Images\\" + GetCardFileName(card), UriKind.Relative))); 

      } 
      return results; 

     } 

użyłem dokładnie XAML zasugerował. To prawie działa. Mówię "prawie", ponieważ zauważyłem dziwne zachowanie, w którym czasami pokazywałam 1 kartę, a czasem nie (nigdy nie dostałem 2 kart). Wydaje mi się, że wszystkie karty z plików i powiązania działają, a ja wyśledziłem, co uważam za kluczowe dla ostatniego błędu (i jest to BIZARRE). Jeśli w debugerze sprawdzam wyniki i dalej otwieram wyniki [0] w debugerze, wyświetlam tę kartę! Muszę otworzyć [0] (widzisz informacje o wysokości, szerokości itp.), Aby to działało. Ponadto, jeśli otworzę [1], zamiast tego wyświetlam tę kartę. Dlaczego otwarcie informacji o debuggerze ma jakikolwiek wpływ? Dla tych, którzy mogą zapytać, co się stanie, jeśli otworzysz obie karty w debugerze ... to nie działa. Został przekroczony limit czasu operacji. Powiem, że być może moje pliki obrazów są duże. 10 KB do 30 KB. Czy to jest problem? Zgaduję, że nie, i że jest to subtelny problem z czytaniem obrazów lub wiązaniem. Co się dzieje? Dzięki, Dave

Odpowiedz

10

Po pierwsze, nie należy używać formantów obraz w ViewModel. Masz już Kontrolkę obrazu w DataTemplate swojego widoku. Użytkownik chce powiązać właściwość Source tego konwoju obrazu, a właściwość źródłowa tego powiązania nie może być kolejnym obrazem.

Zamiast Twój ViewModel byłoby użyć ImageSource (lub klasy pochodnej jak BitmapImage) jako typ obrazu, tak:

public ObservableCollection<ImageSource> PlayerCardImages 
{ 
    get 
    { 
     var results = new ObservableCollection<ImageSource>(); 
     foreach (var card in PlayerCards) 
     { 
      results.Add(new BitmapImage(new Uri(card.ImageUrl))); 
     } 
     return results; 
    } 
} 

lub po prostu URI obrazu lub ścieżki, ponieważ nie jest automatyczna konwersja z string do ImageSource wbudowana w WPF:

public ObservableCollection<string> PlayerCardImages 
{ 
    get 
    { 
     var results = new ObservableCollection<string>(); 
     foreach (var card in PlayerCards) 
     { 
      results.Add(card.ImageUrl); 
     } 
     return results; 
    } 
} 

można by teraz powiązać listBox za ItemsSource obiekt do kolekcji PlayerCardGames, aw DataTemplate powiązać bezpośrednio do elementu kolekcji. DataContext ListView musi być ustawiony na instancję obiektu, która definiuje właściwość PlayerCardGames.

<ListView ItemsSource="{Binding PlayerCardGames}"> 
    <ListView.ItemTemplate> 
     <DataTemplate> 
      <StackPanel> 
       <Image Source="{Binding}" /> 
      </StackPanel> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

UPDATE: Ponieważ nie wydaje się być problem z ładowanie plików graficznych, można spróbować następującej metody. Ładuje obrazy synchronicznie i możesz przejść przez debugger.

public static ImageSource LoadImage(string fileName) 
{ 
    var image = new BitmapImage(); 

    using (var stream = new FileStream(fileName, FileMode.Open)) 
    { 
     image.BeginInit(); 
     image.CacheOption = BitmapCacheOption.OnLoad; 
     image.StreamSource = stream; 
     image.EndInit(); 
    } 

    return image; 
} 

Można użyć tej metody w swojej PlayerCardGames własności getter tak:

foreach (var card in PlayerCards) 
{ 
    results.Add(LoadImage(@"Images\\" + GetCardFileName(card))); 
} 
+0

Clemens, Dziękuję bardzo za odpowiedź. Zaimplementowałem Twoje sugestie i myślę, że jestem bardzo blisko. Czy możesz zobaczyć moje zmiany u dołu mojego pierwotnego postu? (Nie było miejsca w komentarzach do wprowadzenia dodatkowego kodu). Dzięki. Dave – Dave

+0

Trudno powiedzieć, co jest nie tak, ale możesz wypróbować metodę dodawania pomocnika dodaną do mojej odpowiedzi. – Clemens

+0

Clemens, dziękuję! Dziękuję Ci! Dziękuję Ci! To działa. Co jest warte, wydaje się, że kluczem jest linia o CacheOption. Skomentowałem to, a obrazy się nie wyświetlały. Co ciekawe, nie mogłem ich przekonać, wykorzystując moją sztuczkę do otwierania wyników w oknie zegarka i sprawdzania jednej karty. Twoje zdrowie. – Dave

0

naprawdę nie spróbować odtworzyć problem, ale zrobię, jeśli to nie jest rozwiązanie go:

W pierwszym bloku xaml, myślę, że miesza się powiązań. Tak właśnie się spodziewam, ItemsSource do ObservableCollection of Images, Image source do Image.

<Image Source="{Binding}" ... /> 
<ListView Name="lvwTitles" ItemsSource="{Binding PlayerCardImages}" ... /> 

w drugim bloku, należy pominąć źródła wiążące ogóle:

<Image Source="{Binding}" Height="50" Width="40" /> 
Powiązane problemy