Liste in WPF erstellen (VB)

  • WPF

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Simon9499.

    Liste in WPF erstellen (VB)

    Hallo,

    ich habe folgendes Problem:
    Ich möchte ein Programm zur Verwaltung meiner DVD-/Blu-ray-Sammlung erstellen. Ich habe das bereits in Windows Forms mit VB dieses Programm wie folgt erstellt:
    Es gibt eine Listview mit mehreren Spalten (Titel, Format, Genre, Laufzeit, FSK...) und mehreren Zeilen.
    Diese Listview wird mit Hilfe von Textboxen und einem Button gefüllt. (Listview.items.add usw.)
    (Es gibt auch noch einen Button zum Löschen eines Eintrags aus der Listview.)

    Jetzt möchte ich genau so ein Programm als WPF erstellen und weiß nicht so wirklich, wie ich das mit der Listview umsetzen soll.
    Soll ich die Auflistung mit einer Listview anzeigen oder lieber ein anderes Steuerelement verwenden und wie kann ich dann Daten einfügen/löschen?

    Bin noch Anfänger im Bereich WPF :S ?(
    Danke im Voraus! :)
    Füge einfach ganz normal ne ListView via XAML hinzu. Eventuell eignet sich ja ein DataGrid noch besser. Ist speziell für sowas ausgelegt. Würde also das nehmen.
    Musste halt Bindings, Commands etc. benutzen. Die verschiedenen Collections bzw. Datensätze etc. für die Datenverwaltung halt dafür als Property ins ViewModel, via Commands initialisieren/füllen und per Binding ans Control binden.

    Dazu eignet sich die Items-Eigenschaft des DataGrids, ist ne DataGridItemCollection, die Du verwalten kannst.
    msdn.microsoft.com/de-de/libra…grid.items(v=vs.110).aspx
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Trade“ () aus folgendem Grund: Zusatz

    Ich sag ja: bin Anfänger auf dem Gebiet WPF :/

    Bei Windows Forms hab ich das einfach mit einer Listview gelöst und dann das speichern (als .txt-Dokument) wie folgt gemacht:

    VB.NET-Quellcode

    1. Dim sw As New StreamWriter(txtSpeicherort.Text & "\Filme.txt", False, _
    2. System.Text.Encoding.Default)
    3. If lstFilme.Items.Count = 0 Then
    4. Exit Sub
    5. Else
    6. Using sw
    7. For Each li As ListViewItem In lstFilme.Items
    8. sw.Write(li.Text)
    9. sw.Write(" - ")
    10. For i As Integer = 1 To li.SubItems.Count - 1
    11. sw.Write(li.SubItems(i).Text)
    12. sw.Write(" - ")
    13. Next i
    14. sw.WriteLine()
    15. Next
    16. End Using
    17. End If


    Deshalb frag ich ja hier, wie man das unter WPF lösen kann! :)

    Also wenn du ein paar hilfreiche Tipps oder Lösungen für mich hättest, wäre ich sehr dankbar. :thumbsup:
    @Simon9499
    Haha, vor kurzem habe ich exakt genau so ein Programm geschrieben :D
    Als erstes brauchst du ein Modell, heißt, du brauchst eine Klasse mit dem Namen Movie. Ich habe das ganze in C# geschrieben, sollte aber für dich mit ihm hier kein Problem sein. Wenn du willst, kann ich dir auch das Projekt irgendwo hochladen, wenn du einen Denkanstoß brauchst. Aber erstmal will ich mein Datenmodell erläutern.
    Als erstes habe ich eine Klasse Movie:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using Film_Manager.ViewModelBase;
    7. using TMDbLib.Objects.Movies;
    8. using TMDbLib.Objects.General;
    9. using System.IO;
    10. namespace Film_Manager.Data
    11. {
    12. [Serializable]
    13. class Movie : ViewModelBase.PropertyChangedBase
    14. {
    15. public Movie()
    16. {
    17. }
    18. #region Default
    19. private String title;
    20. public String Title
    21. {
    22. get { return title; }
    23. set
    24. {
    25. SetProperty(value, ref title);
    26. }
    27. }
    28. private string originaltitle;
    29. public string OriginalTitle
    30. {
    31. get { return originaltitle; }
    32. set
    33. {
    34. SetProperty(value, ref originaltitle);
    35. }
    36. }
    37. private FSK agerating;
    38. public FSK AgeRating
    39. {
    40. get { return agerating; }
    41. set
    42. {
    43. SetProperty(value, ref agerating);
    44. }
    45. }
    46. private String description;
    47. public String Description
    48. {
    49. get { return description; }
    50. set
    51. {
    52. SetProperty(value, ref description);
    53. }
    54. }
    55. public List<MoviePath> Paths { get; set; }
    56. #endregion
    57. #region Details
    58. private DateTime year;
    59. public DateTime Year
    60. {
    61. get { return year; }
    62. set
    63. {
    64. SetProperty(value, ref year);
    65. }
    66. }
    67. private String playtime;
    68. public String Playtime
    69. {
    70. get { return playtime; }
    71. set
    72. {
    73. SetProperty(value, ref playtime);
    74. }
    75. }
    76. private List<string> genres;
    77. public List<string> Genres
    78. {
    79. get { return genres; }
    80. set
    81. {
    82. SetProperty(value, ref genres);
    83. }
    84. }
    85. private List<string> productcompanies;
    86. public List<string> ProductCompanies
    87. {
    88. get { return productcompanies; }
    89. set
    90. {
    91. SetProperty(value, ref productcompanies);
    92. }
    93. }
    94. private List<Actor> actors;
    95. public List<Actor> Actors
    96. {
    97. get { return actors; }
    98. set
    99. {
    100. SetProperty(value, ref actors);
    101. }
    102. }
    103. private String imagepath;
    104. public String ImagePath
    105. {
    106. get { return imagepath; }
    107. set
    108. {
    109. SetProperty(value, ref imagepath);
    110. }
    111. }
    112. #endregion
    113. #region Media
    114. private string resolution;
    115. public string Resolution
    116. {
    117. get { return resolution; }
    118. set
    119. {
    120. SetProperty(value, ref resolution);
    121. }
    122. }
    123. private int videobitrate;
    124. public int VideoBitrate
    125. {
    126. get { return videobitrate; }
    127. set
    128. {
    129. SetProperty(value, ref videobitrate);
    130. }
    131. }
    132. private String videocodec;
    133. public String VideoCodec
    134. {
    135. get { return videocodec; }
    136. set
    137. {
    138. SetProperty(value, ref videocodec);
    139. }
    140. }
    141. private double framerate;
    142. public double FrameRate
    143. {
    144. get { return framerate; }
    145. set
    146. {
    147. SetProperty(value, ref framerate);
    148. }
    149. }
    150. private int audiobitrate;
    151. public int AudioBitrate
    152. {
    153. get { return audiobitrate; }
    154. set
    155. {
    156. SetProperty(value, ref audiobitrate);
    157. }
    158. }
    159. private string audiocodec;
    160. public string AudioCodec
    161. {
    162. get { return audiocodec; }
    163. set
    164. {
    165. SetProperty(value, ref audiocodec);
    166. }
    167. }
    168. private int channels;
    169. public int Channels
    170. {
    171. get { return channels; }
    172. set
    173. {
    174. SetProperty(value, ref channels);
    175. }
    176. }
    177. private String formatid;
    178. public String FormatID
    179. {
    180. get { return formatid; }
    181. set
    182. {
    183. SetProperty(value, ref formatid);
    184. }
    185. }
    186. private String director;
    187. public String Director
    188. {
    189. get { return director; }
    190. set
    191. {
    192. SetProperty(value, ref director);
    193. }
    194. }
    195. private String trailer;
    196. public String Trailer
    197. {
    198. get { return trailer; }
    199. set
    200. {
    201. SetProperty(value, ref trailer);
    202. }
    203. }
    204. private String tagline;
    205. public String Tagline
    206. {
    207. get { return tagline; }
    208. set
    209. {
    210. SetProperty(value, ref tagline);
    211. }
    212. }
    213. private List<string> productCountries;
    214. public List<string> ProductCountries
    215. {
    216. get { return productCountries; }
    217. set
    218. {
    219. SetProperty(value, ref productCountries);
    220. }
    221. }
    222. public string BaseDirectory { get; set; }
    223. #endregion
    224. private bool seen;
    225. public bool Seen
    226. {
    227. get { return seen; }
    228. set
    229. {
    230. SetProperty(value, ref seen);
    231. }
    232. }
    233. [Newtonsoft.Json.JsonIgnore]
    234. private System.Windows.Media.Imaging.BitmapImage image;
    235. [Newtonsoft.Json.JsonIgnore]
    236. public System.Windows.Media.Imaging.BitmapImage Image
    237. {
    238. get
    239. {
    240. if (image == null && ImagePath != null)
    241. {
    242. image = new System.Windows.Media.Imaging.BitmapImage(new Uri(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images", ImagePath.Remove(0, 1))));
    243. }
    244. return image;
    245. }
    246. }
    247. private RelayCommand opentrailer;
    248. [Newtonsoft.Json.JsonIgnore]
    249. public RelayCommand OpenTrailer
    250. {
    251. get
    252. {
    253. if (opentrailer == null)
    254. opentrailer = new RelayCommand((object parameter) =>
    255. {
    256. if (string.IsNullOrEmpty(this.Trailer))
    257. {
    258. System.Diagnostics.Process.Start(string.Format("https://www.youtube.com/results?search_query={0}+trailer+deutsch", this.Title.Replace(" ", "+")));
    259. }
    260. else
    261. {
    262. System.Diagnostics.Process.Start(Trailer);
    263. }
    264. });
    265. return opentrailer;
    266. }
    267. }
    268. #region Load
    269. public void LoadInfos(TMDbLib.Objects.Movies.Movie tmovie, string ImageFolder)
    270. {
    271. if (tmovie.Trailers.Youtube.Count > 0)
    272. {
    273. this.Trailer = string.Format("https://www.youtube.com/watch?v={0}", tmovie.Trailers.Youtube[0].Source);
    274. }
    275. var countries = new List<string>();
    276. foreach (ProductionCountry country in tmovie.ProductionCountries)
    277. {
    278. countries.Add(country.Name);
    279. }
    280. this.ProductCountries = countries;
    281. foreach (Crew p in tmovie.Credits.Crew)
    282. {
    283. if (p.Job == "Director")
    284. {
    285. this.Director = p.Name;
    286. break;
    287. }
    288. }
    289. this.Tagline = tmovie.Tagline;
    290. this.Title = tmovie.Title;
    291. this.OriginalTitle = tmovie.OriginalTitle;
    292. var lst = new List<string>();
    293. foreach (Genre genre in tmovie.Genres)
    294. {
    295. lst.Add(genre.Name);
    296. }
    297. this.Genres = lst;
    298. this.Year = tmovie.ReleaseDate.Value;
    299. this.Description = tmovie.Overview;
    300. var lstactors = new List<Actor>();
    301. foreach (Cast cast in tmovie.Credits.Cast)
    302. {
    303. lstactors.Add(new Actor { Character = cast.Character, Name = cast.Name });
    304. }
    305. this.Actors = lstactors;
    306. var productcomp = new List<string>();
    307. foreach (ProductionCompany c in tmovie.ProductionCompanies)
    308. {
    309. productcomp.Add(c.Name);
    310. }
    311. this.ProductCompanies = productcomp;
    312. using (System.Net.WebClient wc = new System.Net.WebClient())
    313. {
    314. wc.DownloadFile(string.Format("http://image.tmdb.org/t/p/w500{0}", tmovie.PosterPath), Path.Combine(ImageFolder, tmovie.PosterPath.Remove(0, 1)));
    315. }
    316. this.ImagePath = tmovie.PosterPath;
    317. Data.FSK result = FSK.Nothing;
    318. if (!string.IsNullOrEmpty(tmovie.ImdbId))
    319. {
    320. using (System.Net.WebClient wc = new System.Net.WebClient())
    321. {
    322. string s = wc.DownloadString(string.Format("http://www.imdb.com/title/{0}", tmovie.ImdbId));
    323. System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"<span itemprop=""contentRating"">(?<rating>(.*?))<\/span>");
    324. System.Text.RegularExpressions.MatchCollection matches = regex.Matches(s);
    325. if (matches.Count > 0)
    326. {
    327. switch (matches[0].Groups["rating"].Value)
    328. {
    329. case "o.Al.":
    330. result = FSK.FSK0;
    331. break;
    332. case "6":
    333. result = FSK.FSK6;
    334. break;
    335. case "12":
    336. result = FSK.FSK12;
    337. break;
    338. case "16":
    339. result = FSK.FSK16;
    340. break;
    341. case "18":
    342. result = FSK.FSK18;
    343. break;
    344. }
    345. }
    346. }
    347. }
    348. this.AgeRating = result;
    349. image = null;
    350. OnPropertyChanged("Image");
    351. }
    352. #endregion
    353. }
    354. public enum FSK { FSK0, FSK6, FSK12, FSK16, FSK18, Nothing }
    355. public class MoviePath
    356. {
    357. public string path { get; set; }
    358. public string title { get; set; }
    359. private RelayCommand playmovie;
    360. public RelayCommand PlayMovie
    361. {
    362. get
    363. {
    364. if (playmovie == null)
    365. playmovie = new RelayCommand((object parameter) =>
    366. {
    367. System.Diagnostics.Process.Start(path);
    368. });
    369. return playmovie;
    370. }
    371. }
    372. }
    373. }


    Wie du siehst gibt es da eine Methode LoadInfos. Diese lädt die Infos von einem TMDbLib.Objects.Movies.Movie tmovie. Ich habe es so gemacht, dass man einen Ordner mit den Filmen auswählt, das Programm guckt sich die Ordnernamen an und sucht diese auf The Movie Database (TMDb). Weil The Movie Database dir das FSK nicht sagt, habe ich dann nochmal auf IMDb diese Info nachgeguckt (nen bisschen RegEx, weil IMDb leider keine API hat).

    Jedenfalls ist die Klasse Movie mit dem Serializable-Attribut gekennzeichnet. So habe ich dann noch eine Klasse (MovieData), die eine einzige Eigenschaft hat vom Typ ObservableCollection(Of Movie). Diese Klasse hat zwei Methoden: Load(Path As String) As MovieData und Save(). Außerdem zwei Konstruktoren, 1. ohne Parameter für das Serialisieren (Darf nicht benutzt werden) und eine mit Paramter, New(Path As String).

    So sieht diese Klasse aus: (In dem Fall hat sie noch ein paar andere Funktionen und Methoden, aber das sind nur ein paar Extras wie z. B. zu gucken, ob neue Video in dem Ordner sind o. ä.)
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using System.Collections.ObjectModel;
    7. using System.IO;
    8. using System.Xml.Serialization;
    9. using Newtonsoft.Json;
    10. using System.Windows;
    11. namespace Film_Manager.Data
    12. {
    13. [Serializable]
    14. class MovieData : ViewModelBase.PropertyChangedBase
    15. {
    16. public event Action MoviesChanged;
    17. public MovieData()
    18. {
    19. }
    20. private string Path;
    21. public MovieData(string path)
    22. {
    23. this.Path = path;
    24. this.movies = new ObservableCollection<Movie>();
    25. }
    26. private ObservableCollection<Movie> movies;
    27. public ObservableCollection<Movie> Movies
    28. {
    29. get { return movies; }
    30. set
    31. {
    32. SetProperty(value, ref movies);
    33. }
    34. }
    35. public static MovieData LoadMovies(string path)
    36. {
    37. MovieData result = JsonConvert.DeserializeObject<MovieData>(File.ReadAllText(path));
    38. result.Path = path;
    39. return result;
    40. }
    41. public void CheckMovies(MahApps.Metro.Controls.MetroWindow win, string folder)
    42. {
    43. List<DirectoryInfo> directorystoimport = new List<DirectoryInfo>();
    44. foreach (DirectoryInfo d in new DirectoryInfo(folder).GetDirectories("*", SearchOption.TopDirectoryOnly))
    45. {
    46. if (!ContainsMovie(d))
    47. {
    48. bool IsSkipped = false;
    49. if (SkippedMovies != null)
    50. {
    51. foreach (string str in SkippedMovies)
    52. {
    53. if (str.ToUpper() == d.FullName.ToUpper())
    54. {
    55. IsSkipped = true;
    56. break;
    57. }
    58. }
    59. }
    60. if (!IsSkipped && MovieImport.IsValidMovie(d))
    61. {
    62. directorystoimport.Add(d);
    63. }
    64. }
    65. }
    66. if (directorystoimport.Count == 0) return;
    67. MovieImport import = new MovieImport();
    68. import.FoundMovies = new ObservableCollection<MovieInfo>();
    69. foreach (DirectoryInfo di in directorystoimport)
    70. {
    71. import.ImportMovie(di);
    72. }
    73. import.ImportMovies(win);
    74. }
    75. private bool ContainsMovie(DirectoryInfo folder)
    76. {
    77. foreach (Data.Movie m in this.Movies)
    78. {
    79. if (folder.FullName == m.BaseDirectory) { return true; }
    80. }
    81. return false;
    82. }
    83. public List<string> SkippedMovies { get; set; }
    84. public void Save()
    85. {
    86. JsonSerializer serializer = new JsonSerializer();
    87. using (StreamWriter sw = new StreamWriter(Path))
    88. using (JsonWriter writer = new JsonTextWriter(sw))
    89. {
    90. serializer.Serialize(writer, this);
    91. }
    92. }
    93. public void RemoveMovie(Movie movie)
    94. {
    95. Movies.Remove(movie);
    96. MoviesChanged();
    97. }
    98. private bool DontRaiseImportedEvent = false;
    99. public void MoviesImported()
    100. {
    101. if (!DontRaiseImportedEvent) { MoviesChanged(); }
    102. }
    103. }
    104. }


    Diese Klasse wird beim Beenden des Programms gespeichert (Serialisiert) und beim Laden ausgelesen (De-serialisiert). Eine Instanz dieser Klasse befindet sich als öffentliche Eigenschaft im MainViewModel und letztendlich sieht meine ListView dann aus:

    Spoiler anzeigen

    XML-Quellcode

    1. <ListView Grid.Column="0" ex:GridViewSort.AutoSort="True" ex:GridViewSort.ShowSortGlyph="False" ctrl:ListViewLayoutManager.Enabled="True" x:Name="lst" ItemsSource="{Binding MovieData.Movies,IsAsync=True}" SelectedItem="{Binding SelectedMovie}">
    2. <ListView.View>
    3. <GridView>
    4. <GridViewColumn Header="Titel" ctrl:ProportionalColumn.Width="1" DisplayMemberBinding="{Binding Title}" ex:GridViewSort.PropertyName="Title"/>
    5. <GridViewColumn Header="Laufzeit" ctrl:FixedColumn.Width="100" DisplayMemberBinding="{Binding Playtime}" ex:GridViewSort.PropertyName="Playtime"/>
    6. <GridViewColumn Header="Gesehen" ctrl:FixedColumn.Width="50" ex:GridViewSort.PropertyName="Seen">
    7. <GridViewColumn.CellTemplate>
    8. <DataTemplate>
    9. <Image Source="{Binding Seen,Converter={StaticResource booltoimg}}" Width="16" Height="16"/>
    10. </DataTemplate>
    11. </GridViewColumn.CellTemplate>
    12. </GridViewColumn>
    13. </GridView>
    14. </ListView.View>
    15. </ListView>


    (ctrl ist der ListViewLayoutManager, einfach mal googlen, ist ne tolle Library)

    Insgesamt sieht das Programm so aus:


    (Rechts sind einfach nur ein paar Bindings zu SelectedMovie, welches im MainViewModel eine Eigenschaft vom Typ Movie ist und woran auch der ListView bindet)
    Mfg
    Vincent

    @VincentTB
    Dein Manager sieht klasse aus!
    Da ich auch schon immer sowas haben wollte und bisher nur fremdlösungen genutzt habe, sollte ich mich auch mal hinsetzen und sowas schreiben...kannst du mir vllt ein paar infos geben zu den Zugriffszeiten beim Öffnen?...dauert das mit dem Serialisieren lange?

    kannst du mir vielleicht noch weitere infos schreiben? vllt per pn damit das hier nicht zu ner OffTopic wird...
    Funktionsumfang, Ladezeiten, Hinzufügen(per Hand?)...etc
    @Simon9499 und @Runshak
    Habe das ganze gerade auf GitHub hochgeladen. Ihr könnt damit machen was ihr wollt.

    Vielleicht hilft es ja sogar dem TE, son bisschen die Logik hinter dem MVVM zu verstehen. Vielleicht komme ich ja sogar dazu, nochmal ein bisschen zu kommentieren, damit es verständlicher wird, was passiert und wozu was ist :)
    github.com/Anapher/FilmManager
    Mfg
    Vincent

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VincentTB“ ()