[c# wpf] Binding observablecollection do treeview

Próbuję napisać swój program pocztowy w ramach nauki różnych rzeczy związanych z c# i wpf.

Mam następujący problem z wyświetleniem danych w treeview.

W głównym oknie stworzyłem coś takiego:

public ObservableCollection accounts { get; set; }

        public MainWindow()

        {

            InitializeComponent();

            accounts = new ObservableCollection();

            accounts.Add(new AccountClass("Jan Kowalski","jan_kowal","jan","@gmail.com"));

            accounts.Add(new AccountClass("Jan Porwał", "por_jan", "por", "@wp.pl"));

            accounts.Add(new AccountClass("Marek Kolski", "markol", "mar", "@gmail.com"));

            this.DataContext = accounts;

W AccountClass(własności Login,Password,Domena,Name, konstruktor 4-parametrowy jak wyżej i wszystko potrzebne do INotifyPropertyChanged). W xaml’u zaś :

I pokazują się 3 strzałeczki do rozwijania z loginami, jednak po rozwinięciu jest puste miejsce i nie mam pojęcia jak zrobić aby wyświetlały się pozostałe 3 pola (password, domena, login) dla każdego obiektu już nierozwijalne dalej (własności kolejno jak nazwy). Później na tej podstawie będę robił foldery jak w thunderbird z odebranymi itd.

Drugim pytaniem jest czy dobrze zastosowałem INotifyPropertyChanged w klasie AccountClass, aby samoczynnie zaktualiowały się dane po edycji konta.

Mam nadzieję, że opisałem to w sposób w miarę logiczny, dziękuję za wszelkie informacje.

Nie bardzo rozumiesz jak działa TreeView i HierarchicalDataTemplate, z którego to TreeView(ale w sumie nie tylko) korzysta.

HierarchicalDataTemplate używa się do danych hierarchicznych, a aktualnie masz płaską strukturę danych(jak dodasz te foldery to będzie ok), choć w praktyce to nie przeszkadza.

Cała rzecz polega na tym, że musisz wyobrazić sobie swoją strukturę danych, jako drzewo. Każdy obiekt jest elementem tego drzewa i może, ale nie musi, mieć dzieci. Z tym, że dzieckiem jest osobny obiekt, nie właściwość obiektu-rodzica.

I tak - HierarchicalDataTemplate jako “content” ustawia sobie właściwość VisualTree, która to jest nagłówkiem dla grupy. ItemsSource to lista(tablica, słownik, czy cokolwiek co implementuje IEnumerable) elementów-dzieci, dla których można wybrać szablon ustawiając ItemTemplate.

Dp.t499443.png

Niebieskimi liniami pokazałem, czemu odpowiada ten TextBlock w szablonie, a czerwonawymi klamrami(i podkreślonym ItemsSource), skąd brane są elementy do ItemsSource.

A tak wygląda klasa Data:

public class Data{    public string Name { get; set; }    public ListData Items { get; set; }[/code]

Powoli z tym walczę,póki co sam chce popróbować to rozwiązać.

Napotkałem jednak na kilka innych trudności niezwiązanych z tym problemem.

  1. Napisałem klasę, która wg. zamierzenia konwertuje stringa uzyskanego z textboxa na List

    public class Converters : IValueConverter

     {
    
    
         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
         {
    
             string temp = value.ToString();
    
             List myList = new List(temp.Split(','));
    
             return myList;
    
         }
    
    
         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
         {
    
             throw new NotImplementedException();
    
         }
    
     }
    

Podpinam to pod textboxa w ten sposób (własność ContactsToSend w oknie):

Text="{Binding ElementName=SendWindow, Converter={StaticResource Converters1}, Path=ContactsToSend}"

x:Name="SendWindow"// tak nazwałem okno

Jednak własność ContactsToSend nie dostaje żadnych elementów -dlaczego? Jest to pierwszy konwerter,który napisałem a i z bindingami jeszcze średnio sobie radzę więc proszę o wyrozumiałość.

  1. Chce także, aby wszystkie buttony obsługiwały komendy, jednak w jaki sposób to najlepiej zrobić?

Chodzi mi zwłaszcza o taką komendę, która przyjmie parametry tzn. pewne własności, utworzy obiekt pewnej klasy i uruchomi jej metodę.

  1. Binding jest nie z tej strony co potrzeba :wink: Zaimplementuj IValueConverter.ConvertBack tak jak zaimplementowałeś Convert, a Convert zrób “na odwrót”(List->string). Warto wiedzieć jak to działa - właściwość, do której binding jest podczepiony to Target, a to z której pobiera - Source - Source -> Convert -> Target i Target -> ConvertBack -> Source. Naprawdę polecam poczytać MSDN, tam jest wszystko opisane(a od w/w linka można zacząć).

  2. ButtonBase.Command, CommandParameter lub zwyczajnie obsługiwać to w zdarzeniu Click.