Hallo,
ich erkläre euch mal kurz mein vorhaben:
Ich habe eine ListView, diese ist an ein Objekt gebunden. Das ganze sieht so aus:
<ListView Grid.Row="1" Grid.Column="0" MinHeight="75" Width="305" Foreground="Black" Name="ListSongs">
<ListView.View>
<GridView>
<GridViewColumn Width="210" Header="Song" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="65" Header="Genre" DisplayMemberBinding="{Binding Genre}"/>
</GridView>
</ListView.View>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip" Value="{Binding Path=Content}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Click="ListSongsDelete_Click"/>
<MenuItem Header="Play" Click="ListSongsPlay_Click"/>
<MenuItem Header="Stop" Click="ListSongsStop_Click"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
Nun habe ich noch mehrere Felder, die ich an das ausgewählte Objekt in der ListView binden möchte, dass heißt wenn ich ein anderes Item auswähle, werden die anderen Felder aktualisiert.
Leider habe ich seit stunden Probleme damit.
<TextBox Text="{Binding ElementName=ListSongs, Path=<-- Hier das Objekt + Eigenschaft -->}"/>
Könnte mir von euch vielleicht jemand auf die Sprünge helfen?
Danke euch!
Hallo Rioma,
hab mit ListView noch nicht gearbeitet, aber klappt das nicht?
<TextBox Text="{Binding ElementName=ListSongs, Path="{SelectedItem.Eigenschaft}"/>
Schöne Grüße
Quaneu
Danke schonmal, aber
genauso hatte ich es versucht, vielleicht mache ich auch noch wo anders einen Fehler.
Die ListView hängt an einer CollectionView mit Filtermöglichkeit. Gefüttert wird die CollectionView von einer List<T> wobei T das Objekt ist.
Jemand schon erfahrung damit gemacht?
Hmmm...
Hätte noch zwei Vorschläge:
Leider sind dies nur sehr wage Vorschläge.
Schöne Grüße
Quaneu
Hallöchen,
also erstmal :
Wenn mal ein Binding-Fehler auftritt, schau in die Ausgabe, da stehen meist Fehlermeldungen mit denen man mehr anfangen kann als mit :"klappt nicht" 😃
Bei Binding-Fehler irgendwas mit :error 40 : Binding Path not found... da steht dann auch in der langen Fehlermeldung der Typ gegen den du das Binding gesetzt hast.
Wenn das nicht hilft müsstest du etwas mehr posten, da ich so nur raten kann.
vg
Wenn's zum weinen nicht reicht, lach drüber!
Danke euch, es klappt nun mit:
<TextBox Text="{Binding ElementName=ListSongs, Path=SelectedValue.Name}"/>
Er sagt mir nur im Designer: > Fehlermeldung:
Cannot resolve propertie Name in DataContext of type object.
Irgendjemand ne ahnung warum er meckert?
Hier der relevante C# Code
private void CmdSongsHinzufügen_OnClick(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = true;
if (ofd.ShowDialog() == true)
{
mBand = new List<MusicBand>();
foreach (var fileName in ofd.FileNames)
{
using (TagLib.File file = TagLib.File.Create(fileName))
{
mBand.Add(new MusicBand(file, fileName));
}
}
ListSongs.ItemsSource = MusicSongs.MSongs;
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(ListSongs.ItemsSource);
view.Filter = MusicFilter;
}
}
private bool MusicFilter(object item)
{
if (String.IsNullOrEmpty(TxtFilter.Text))
return true;
else
return ((item as MusicSongs).Name.IndexOf(TxtFilter.Text, StringComparison.OrdinalIgnoreCase) >= 0);
}
private void TxtFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
CollectionViewSource.GetDefaultView(ListSongs.ItemsSource).Refresh();
}
Irgendjemand ne ahnung warum er meckert?
Hallo Rioma,
ja, weil das SelectedItem zur Design-Zeit nicht gesetzt ist (vermute ich). Mein Tipp: Lass den Designer ganz weg. Du schreibst schöneren XAML-Code, weisst was er tut und andere tun das auch, wenn sie ihn sehen. Du nach 3 Wochen auch noch 😉. Ausserdem lädt VS schneller (je nach Grösse der View).
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Danke das wird warscheinlich das Problem sein. Also ich Klicke mir meine GUI nicht zusammen, ich schreibe den XAML Code und habe darüber sofort das Ergebnis. Deswegen sprach ich vom Designer 😃
2 Fragen haben sich jetzt aber leider noch aufgetan:
1)
Alle Felder werden nun aktualisiert, soabalb ich ein anderes Item ausgewählt habe. Nur meine ImageSource nicht.
So sieht mein Xaml Code aus:
<Image DockPanel.Dock="Right" Height="125" Source="{Binding ElementName=ListSongs, Path=SelectedValue.SongCover}">
<Image.ContextMenu>
<ContextMenu>
<MenuItem Header="Entfernen" Click="CoverEntfernen_Click"/>
</ContextMenu>
</Image.ContextMenu>
</Image>
und hier der C# code:
try
{
TagLib.IPicture p = _tagLibFile.Tag.Pictures[0];
string coverPath = "Image/" + _tagLibFile.Tag.FirstAlbumArtist + "/" + _tagLibFile.Tag.Album + "/Cover.jpg";
if (!Directory.Exists("Image/" + _tagLibFile.Tag.FirstAlbumArtist + "/" + _tagLibFile.Tag.Album))
Directory.CreateDirectory("Image/" + _tagLibFile.Tag.FirstAlbumArtist + "/" + _tagLibFile.Tag.Album);
if (!System.IO.File.Exists(coverPath))
System.IO.File.WriteAllBytes(coverPath, p.Data.Data);
this.SongCover = new BitmapImage(new Uri(coverPath, UriKind.Relative));
}
catch { }
Das mit dem Cover rausziehen und extern speichern funktioniert übrigens und der Pfad stimmt natürlich auch. Beachte ich bei der ImageSource irgendetwas nicht?
Wenn ich per per
private void CoverHinzufügen_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == true)
{
_albumImage = new BitmapImage(new Uri(ofd.FileName));
MusicSongs mSong = (MusicSongs)ListSongs.SelectedValue;
mSong.SongCover = _albumImage;
}
}
Das Cover hinzufüge, wird es in der Gui sofort geladen.
2)
Deswegen auch meine 2te Frage, wie bekommt die Gui mit, dass ich etwas am Objekt geändert habe? Auch wenn ich in den Textboxen etwas änder, wird es sofort in die ListView übernommen.
Ich habe inotifypropertychanged nicht implementiert und eigentlich, ist dass doch ein KO Kriterium oder nicht?
Ich habe inotifypropertychanged nicht implementiert und eigentlich, ist dass doch ein KO Kriterium oder nicht?
Ja, das ist es. Implementier es und schmeiss das Event.
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Wie gesagt ich habe es getestet. Es funktioniert aus irgendeinem Grund auch ohne, ich habe mir einen Haltepunkt im Setter gesetzt und Sobald ich in der TextBox (SongName) etwas änder, und in der ListView das Item wechsel, springt er in den Setter und ändert die Eigenschaft.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using File = TagLib.File;
namespace MusicBox
{
public class MusicSongs
{
public static List<MusicSongs> MSongsTemp = new List<MusicSongs>();
private TagLib.File _tagLibFile;
private string _songName;
public string SongName
{
get { return _songName; }
set { _songName = value; } //HALTEPUNKT
}
public string SongGenre { get; set; }
public string SongInterpret { get; set; }
public string SongYear { get; set; }
public TimeSpan SongTime { get; set; }
public ImageSource SongCover { get; set; }
public string SongKind { get; set; }
public DateTime SongDateAdded { get; set; }
public string SongContent { get; set; }
public string SongPath { get; set; }
public MusicSongs(File tagLibFile, string path)
{
_tagLibFile = tagLibFile;
SongPath = path;
FillProperties();
MSongsTemp.Add(this);
}
private void FillProperties()
{
SongName = _tagLibFile.Tag.Title;
SongGenre = _tagLibFile.Tag.FirstGenre;
SongYear = _tagLibFile.Tag.Year.ToString(CultureInfo.InvariantCulture);
SongTime = _tagLibFile.Properties.Duration;
SongKind = SongPath.Substring(SongPath.Length - 4, 4);
SongInterpret = _tagLibFile.Tag.FirstAlbumArtist;
SongDateAdded = DateTime.Now;
try
{
TagLib.IPicture p = _tagLibFile.Tag.Pictures[0];
string coverPath = "Image/" + _tagLibFile.Tag.FirstAlbumArtist + "/" + _tagLibFile.Tag.Album + "/Cover.jpg";
if (!System.IO.File.Exists(coverPath))
{
if (!Directory.Exists("Image/" + _tagLibFile.Tag.FirstAlbumArtist + "/" + _tagLibFile.Tag.Album))
Directory.CreateDirectory("Image/" + _tagLibFile.Tag.FirstAlbumArtist + "/" +
_tagLibFile.Tag.Album);
System.IO.File.WriteAllBytes(coverPath, p.Data.Data);
}
this.SongCover = new BitmapImage(new Uri(coverPath, UriKind.Relative));
}
catch { }
SongContent = "Published: " + SongYear + Environment.NewLine +
"Time: " + Math.Round(SongTime.TotalMinutes, 2) + " min " + Environment.NewLine +
"Kind: " + SongKind;
}
}
}
Ist natürlich unpraktisch, wenn man immer erst das Item wechseln muss, aber es wäre auch unpraktisch, wenn ich inotifypropertychanged implementiere und die Eigenschaft 2 mal geändert wird, obwohl 1 mal reicht.
Hat jemand eine Idee woran es liegt?
Edit: Sorry, es reicht wenn ich aus der Textbox rausgehe. Es wird dann die Eigenschaft gesetzt. Wenn ich inotifypropertychanged implementiere, macht es keinen unterscheid. Es wird nur einmal gesetzt. Sehr komisch...
Edit2: Könnte daran liegen, das der DefaultWert vom UpdateSourceTrigger bei Textboxen LostFocus ist und nicht PropertyChanged, oder?
Hi Rioma,
Sobald ich in der TextBox (SongName) etwas änder, und in der ListView das Item wechsel, springt er in den Setter und ändert die Eigenschaft.
Ja, das tut es.
Allerdings wird die Benutzeroberfläche dann nicht über die Änderung informiert und daher nicht aktualisiert. Bitte belies dich in der Doku über Sinn und Zweck des INotifyPropertyChanged-Ereignisses und beachte bitte die Hinweise der anderen Benutzer.
Bitte beachte auch in Zukunft [Hinweis] Wie poste ich richtig? , besonders Punkt 1 ("Erst suchen und in die Doku schauen, dann posten" und "Nicht nach Grundlagen fragen") und 8 ("Tut, worum man euch bittet").
Christian
Weeks of programming can save you hours of planning
Das sind alles wichtige hinweise, aber wie bereits gesagt, wird meine GUI aktualisiert und deswegen war ich so verwundert.
Eine CollectionView wird gefüttert mit einer List<T>, die CollectionView hängt an einer ListView.
Dann gibt es Textboxen, die an der SelectedValue.Eigenschaft hängen.
Sobald ich hier aktualsiere und die Textbox den Focus verliert, wird die Eigenschaft gesetzt und die ListView akktualisiert. Alles ohne INotifyPropertyChanged.