piątek, 5 listopada 2010

Wyświetlanie listy zdjęć

Czas na kolejną kontrolkę, która jest jednym ze składników okna głównego. Mianowicie kontrolkę pozwalającą wyświetlać kolekcję zdjęć w najprostszej tabelarycznej formie. Może się ona przydać zarówno do wyświetlania zawartości albumów jak i do przeglądania struktury dysku i podglądu zdjęć z katalogów. 

Oprócz samego zdjęcia chciałbym wyświetlać także opis, jeśli taki jest przypisany do zdjęcia (jeśli nie ma to po prostu nazwę pliku). Dlatego też wygodnie będzie wykorzystać odpowiedni DataTemplate, który z listy obiektów typu Photo (dokładnie tego, który jest wykorzystywany jako jeden z modeli przy współpracy z NHibernate) utworzy szereg obrazów wraz z podpisem. Lista zdjęć przechowywana będzie w obiekcie ViewModel jako prosta właściwość implementująca IPropertyChanged:
private ObservableCollection<Photo> _photos = new ObservableCollection<Photo>();
public ObservableCollection<Photo> Photos
{
 get
 {
  return _photos;
 }

 set
 {
  if (_photos == value)
   return;

  _photos = value;

  // Update bindings, no broadcast
  RaisePropertyChanged(PhotosPropertyName);
 }
}
Na początek należy przygotować kontener, do którego zbindowane będą zdjęcia i wskazać mu szablon danych (który zostanie omówiony w następnej kolejności). 

 
  
   
    
   
  
 

Jako kontener wybrałem WrapPanel, ponieważ sam dobiera ilość wyświetlanych kolumn w zależności od dostępnego miejsca. 

Teraz pora na utworzenie szablonu itemsTemplate, który będzie definiował wygląd każdego elementu umieszczanego we WrapPanel'u. Pojedynczy element będzie składał się z obiektu Image, dla którego właściwość Source ustawiona będzie na ścieżkę dostępu do pliku ze zdjęciem oraz obiektu TextBlock wyświetlającego opis obrazka. Wewnątrz DataTemplate'u może być umieszczony tylko jeden element, dlatego też będą one opakowane w StackPanel. W uproszczeniu prezentuje się to następująco:

 
  
  
 

Dodatkowo chciałem, aby kliknięcie na zdjęcie albo podpis (ogólnie na cały StackPanel) powodowało podjęcie odpowiedniej akcji. Niestety okazało się to trudniejsze niż myślałem. Wszystkie elementy będące wewnątrz WrapPanel'u przejęły DataContext od właściwości ItemsSource z kontenera ItemsControl, czyli nie miały pojęcia o istnieniu ImageListViewModel i nie tym samym nie było możliwości wywołania odpowiedniej komendy. Rozwiązaniem okazało się zastosowanie bardzo rozbudowanego bindingu do obiektu EventToCommand pochodzącego z MVVM Light Toolkit:

 
  
   
   
  
 
 ...

Taki binding przeszukuje w górę hierarchię obiektów, aż do momentu znalezienia obiektu typu ItemsControl, wtedy wykorzystuje jego DataContext w celu wywołania komendy. Jako parametr przekazywany jest cały obiekt typu Photo przypisany do aktualnego elementu. Nie jest ona specjalnie skomplikowana, ma za zadanie jedynie przesłanie odpowiedniego komunikatu:
private RelayCommand<Photo> _onClickCommand = null;
public RelayCommand<Photo> OnClick
{
 get {
  if (_onClickCommand == null)
  {
   _onClickCommand = new RelayCommand<Photo>(
    p =>
    {
     AppMessages.PhotoSelectedChanged.Send(p);
    });
  }
  return _onClickCommand;
 }
}
Jest to bardzo podstawowy zakres funkcjonalności jakie spadają na tę kontrolkę. Nie mam do końca zdefiniowanej wizji co do ostatecznego połączenia kontrolek i ich funkcjonalności (na przykład na której powinien ciążyć obowiązek wyświetlania tagów i daty dodania). W zależności od tego co się wyklaruje być może ta kontrolka zostanie jeszcze rozszerzona.

Brak komentarzy:

Prześlij komentarz