WPF ListBox -> Frage zu "seltsames Verhalten"
-
Hallo zusammen,
Ich denke zwar, dass ich das Problem gelöst habe, möchte aber trotzdem die Sache noch in aller Klarheit für mich klären. Folgender Code hatte ich in C#. WPF wurde verwendet:
// m_lsbReceive <- ist eine WPF ListBox foreach(string message in messages) { m_lsbReceive.Items.Add(message); }
Das Verhalten war mehr als seltsam. Vor allem aber beim Selektieren gab es plötzlich doppelte Selektionen, obwohl nur auf ein einziges Item geklickt wurde. Und man konnte dann diese doppelt selektierten Items nicht mehr deselektieren.
Irgendwann kam mir dann in den Sinn, dass man unter XAML eigentlich einListBoxItem
mit entsprechendemContent
einfügen würde. Daher habe ich den Code abgeändert zu:// m_lsbReceive <- ist eine WPF ListBox foreach(string message in messages) { ListBoxItem item = new ListBoxItem(); item.Content = message; m_lsbReceive.Items.Add(item); }
Und alles funktioniert, wie gewollt. Ich denke mal, dass ich hier schon die richtige Lösung gesehen habe, oder?
Aber was ist dann eigentlich bei den Strings passiert? Wieso hat das überhaupt funktioniert, bzw. so seltsam? Das man Strings dazufügen kann, ist wohl klar, da die Funktion Objects erwartet. Aber wieso kam es zur Laufzeit nicht zur einer Exception oder sowas?Noch eine kleine Zusatzfrage zur
ListBox
. Ich habe den Code dann probiert zu erweitern:// m_lsbReceive <- ist eine WPF ListBox ListBoxItem item = null; foreach(string message in messages) { item = new ListBoxItem(); item.Content = message; m_lsbReceive.Items.Add(item); } if(null != item) { // Dies hat nichts gebracht: item.BringIntoView(); // Nur dies hat funktioniert: m_lsbReceive.ScrollIntoView(item); }
Wieso funktioniert hier
BringIntoView
nicht? Wäre doch irgendwie das logischere von den beiden.Grüssli
-
Hallo
Warum verwendest du nicht DataBinding?
chrische
-
chrische5 schrieb:
Warum verwendest du nicht DataBinding?
1. Weil ich mich darin noch kaum eingearbeitet habe. Bin immer noch am lernen.
2. Ich wüsste aktuell auch gar nicht, wie ich das hier damit umsetzen sollte. Ich bekomme Strings über einen Socket rein, diese müssen geparst werden, verändert usw. usf. und das Resultat wird dann in die ListBox eingetragen. Die ListBox ist aktuell also nur eine Resultatanzeige. Die Werte werden aber nicht weiterverarbeitet und werden auch sonst nirgends gespeichert. Ich wüsste nicht, wie ich hier etwas anbinden könnte, da ja nix vorhanden ist.Grüssli
-
Hallo
Du kannst messages an die ListBox binden.
chrische
-
chrische5 schrieb:
Du kannst messages an die ListBox binden.
Messages wird jedes mal neu erstellt. Dort drin sind nur die neu empfangenen Nachrichten, welche entsprechen weitergeleitet wurden, damit sie in der ListBox eingefügt werden. Danach wird die Liste nicht mehr benötigt. Es gibt keine Liste mit allen empfangenen Nachrichten, ausser halt die ListBox selber.
Grüssli
-
Hallo
Warum erstellst du sie denn immer neu? Du kannst doch einfach den Inhalt löschen und füllen und dann die Liste binden.
chrische
-
chrische5 schrieb:
Warum erstellst du sie denn immer neu? Du kannst doch einfach den Inhalt löschen und füllen und dann die Liste binden.
Weil Thread A die Liste erstellt und diese dann an Thread B weitergibt. Wenn ich die gleiche Liste verwenden würde, müsste ich die Verwendung der Liste synchronisieren. So kann ich nur den
Dispatcher
nehmen und einInvoke
machen.(so am Rande, auch wenn es gerade sehr interessant ist, darum geht es ja eigentlich nicht :))
Grüssli
-
was die doppelte markierung an geht
das laeuft so ab:
der user klickt auf ein element
das framework bekommt das mouse down event und will die markierung setzen
dafuer sagt der der liste "packe objekt x in deine selecteditems collection"
da es nur einfache strings sind - wird nur der inhalt verglichen
also sucht die liste alle elemente mit dem inhalt ab
dh das alle strings die gleich sind markiert werdendurch dein erstellen eines listboxitems erstellst du unikate die die liste genau finden und markieren kann
bezueglich des anderen wuerd ich es so machen:
(mir ist grad langweilig also denk ich mir n bissl pseudocode aus - alles hier im forum getippt - muss nichts funktionieren)
public class MessageItem : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _message; private DateTime _timeStamp; public MessageItem(string message) { Message = message; _timeStamp = DateTime.Now; } public string Message { get { return _message; } set { _message = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Message")); } } public string TimeStamp { get { return _timeStamp.ToString(CultureInfo.CurrentUICulture); } } }
partial class YourWindowClass : Window { private ObservableCollection<MessageItem> _messages = new ObservableCollection<MessageItem>(); public YourWindowClass() { InitializeComponent(); MessageHistoryListView.DataContext = _messages; } public void OnRetrieveMessages(IEnumerable<string> messages) { foreach(string message in messages) messages.Add(new MessageItem(message)); } }
<YourWindowClass ...> <!-- --> <ListView ItemSource="{Binding}" x:Name="MessageHistoryListView"> <ListView.View> <GridView> <GridViewItem Header="{DynamicResource IDS_TIME}" DisplayMemberBinding="{Binding TimeStamp}" /> <GridViewItem Header="{DynamicResource IDS_MESSAGE}" DisplayMemberBinding="{Binding Message}" /> </GridView> </ListView.View> </ListView> <!-- --> </YourWindowClass>
-
@Mr Evil,
Danke für die Erklärung.Mr Evil schrieb:
bezueglich des anderen wuerd ich es so machen: ...
Ich möchte hier nur nochmals klarstellen, dass dies von mir nicht als ein Problem angesehen wird. Das war eine Frage von chrische5, welche nichts mit meinen Fragen zu tun hatte
Allerdings finde ich deine Lösung auch nicht besser. Wieso so umheimlich kompliziert, wenn es auch einfach geht? Was ich bisher von DataBinding gesehen habe, kann das extrem praktisch sein, wenn man gleiche Daten an verschiedenen Stellen darstellen, bzw. verbinden, möchte. Aber das heisst doch nicht, dass man nun alles über DataBinding machen sollte.
Ich kann mich nur wiederholen, die Nachrichten werden bei mir nirgends gespeichert. Die werden empfangen, geparst, umgewandelt und dann direkt an die ListBox angefügt. Mehr passiert mit diesen Nachrichten nicht. Die werden nirgends sonst gespeichert und auch in der Zukunft nicht. Die müssen nur angezeigt werden, dass ist alles und das nur in dieser ListBox. Wieso sollte ich da plötzlich noch irgendwelche zusätzlichen Listen, Klassen, Delegates, Events usw. usf. erstellen, wenn ich den ganzen Kram gar nicht benötigte, nur damit dann DataBinding funktioniert? Das macht doch keinen Sinn...Naja, jetzt fehlt nur noch eine Erklärung zu
BringIntoView
, bzw. wieso das nicht funktioniertGrüssli
-
die liste hat den vorteil das du mit der gleich alles machen kannst
eintraege entfernen, hinzufuegen, aendern, exportieren, ...
wenn du spaeter planst die ausgaben zu exportieren brauchst du nur die liste speichern
du kannst dann auch einfacher die liste anders sortieren ohne die eigentliche liste zu veraenderndu bist dann direkt auf alles vorbereitet und kannst einfacher ggf die liste an anderer stelle weiterverarbeiten
wenn du es aber einfacher haben willst:
partial class YourWindowClass : Window { private ObservableCollection<string> _messages = new ObservableCollection<string>(); public YourWindowClass() { InitializeComponent(); DataContext = _messages; } public void OnRetrieveMessages(IEnumerable<string> messages) { foreach(string message in messages) messages.Add(message); } }
<YourWindowClass ...> <!-- --> <ListBox ItemSource="{Binding}" /> <!-- --> </YourWindowClass>
dann gehts auch - (nur damit dann DataBinding funktioniert)
//wenns dann mit dem selektieren nicht gehen sollte, bzw wieder mehrere selektiert werden:<YourWindowClass ...> <!-- --> <ListBox ItemSource="{Binding}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <!-- --> </YourWindowClass>
dann muesste es gehen
-
Mr Evil schrieb:
die liste hat den vorteil das du mit der gleich alles machen kannst
Ich will aber nichts mehr machen.
Mr Evil schrieb:
eintraege entfernen, hinzufuegen, aendern, exportieren, ...
Ich will nur Einträge hinzufügen, der Rest wird nicht benötigt.
Mr Evil schrieb:
wenn du spaeter planst die ausgaben zu exportieren brauchst du nur die liste speichern
Wir es nie geben.
Mr Evil schrieb:
du kannst dann auch einfacher die liste anders sortieren ohne die eigentliche liste zu veraendern
Auch nicht nötig, die Reihenfolge muss immer gleich bleiben.
Mr Evil schrieb:
du bist dann direkt auf alles vorbereitet und kannst einfacher ggf die liste an anderer stelle weiterverarbeiten
Es wird nichts anderes geben. In Zukunft wird höchstens der Teil entfernt. Das ist nur ein Randprodukt während der Entwicklung. Auch wenn die Empfehlung gut gemeint ist, es gibt auch Grenzen bei DataBinding, nicht? Man muss nicht immer alles mit dem Vorschlaghammer bearbeiten
Grüssli