
Ergebnis 1 bis 10 von 10
-
Robby Light Gast
Hi zusammen!
Ich quäle mich nun seit Tagen mit einem unerklärlichen Problem. Ich habe ein Programm, das Einträge in einer Liste A verwaltet. Wenn einer Dieser Einträge aber als EndDatum Heute haben sollte, möchte ich, dass er zusätzlich noch in einer weiten Liste B angezeigt wird. Letzteres wird nach der Rückkehr vom Eingabefenster eines Entrages mit onNavigatedTo überprüft:
Code:// Static Variables public static ObservableCollection<Item> lstToday = new ObservableCollection<Item>(); public static ObservableCollection<Item> lstWeek = new ObservableCollection<Item>(); public static ObservableCollection<Item> lstAll = new ObservableCollection<Item>(); // Constructor public MainPage() { InitializeComponent(); MessageBox.Show("Initialize Component"); lbToday.ItemsSource = lstToday; lbWeek.ItemsSource = lstWeek; lbAll.ItemsSource = lstAll; } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { DateTime currentDate = DateTime.Now; foreach (Item item in lstAll) { if (item.endDate.ToString("yyyy'-'MM'-'dd").Equals(currentDate.ToString("yyyy'-'MM'-'dd"))) { lstToday.Add(item); MessageBox.Show("Item '" + item.name + "' added to Todaylist"); } } } private void appBarNew_Click(object sender, EventArgs e) { NavigationService.Navigate(new Uri(string.Format("/EditAddItem.xaml"), UriKind.Relative)); }
Mit lbAll klappt es jedoch wunderbar :O
Kann ich per XAML direkt auf eine ObservableCollection binden? Ich weiß echt nicht, was ich noch ausprobieren soll. Habt ihr eine Idee?
Ich wäre euch sehr verbunden!
-
- 27.03.2011, 05:31
- #2
erstmal zum Binding:
Wenn du im Konstruktor "DataContext = this;" hinzufügen würdest, dann müsstest du in der xaml bei deiner List lstToday zum Beispiel mit "ItemsSource="{Binding lstToday}"" binden können.
Besser wäre es aber, ein ViewModel zu verwenden, als die Variablen static zu machen. Wobei dies auch eine Lösung ist. Vielleicht schaust du dir einfach mal ViewModels an, findet man im Internet viele Infos zu. (Einfach MVVM Suchen)
So jetzt zu deinem eigentlichen Problem.
Es kann sein, das dies genau so ein Fehler ist, wie ich ihn mal gehabt habe. Und zwar gab es bei mir mal Fehler, weil ich eine Liste sortiert habe und beim sortieren kurzzeitig 2 Elemente der Liste auf das gleiche Objekt gezeigt haben.
Als erstes würde ich einfach mal testen, ob es reicht, wenn du das Binding an die lstToday vor dem foreach aufhebst und danach wieder setzt.
Also:
Code:lbToday.ItemsSource = null; foreach (Item item in lstAll) { if (item.endDate.ToString("yyyy'-'MM'-'dd").Equals(currentDate.ToString("yyyy'-'MM'-'dd"))) { lstToday.Add(item); MessageBox.Show("Item '" + item.name + "' added to Todaylist"); } } lbToday.ItemsSource = lstToday;
Das könnte das Problem beheben.
Es gibt noch eine andere Möglichkeit, welche allerdings wahrscheinlich nicht bei dir machbar ist.
Das würde ich so erstmal vorschlagen. Vielleicht ist es aber auch viel einfacher. Es wäre mal interessant den Error zu sehen, der da dann wirklich auftritt. Nur mit dem Error werde ich dir 100% sagen können, wo genau das Problem liegt.
Ich hoffe ich konnte dir helfen
-
Robby Light Gast
Hallo dehoDev,
vorweg erste inmal vielen Dank für deine schnelle und umfangreiche Antwort.
Leider hilft sie nicht wirklich weiter.
Das Binding funktioniert nach wie vor nur mit "lbToday.ItemsSource = lstToday;" und nicht mit dem XAML Binding. Ich hänge aber gleich auch noch einmal den XAML-Code an, vielleicht hab ich ja wirklich etwas falsch gemacht.
Auf die Idee das Binding vorher aufzuheben bin ich selber auch schon gekommen, das hilft leider auch nicht weiter.
View Models haben aber direkt nichts mit der funktionalität zu tun, oder kann der Fehler auch darin liegen?
Bitte schreib mir, fals ich mich täusche, aber ich wollte ohne Viewmodels auskommen. Mein Item ist ein "PhoneUserControl" und hat daher schon seine Anzeigevorgaben.
Er gibt mir immernoch den gleichen undefinierten Fehler. Aber anbei erstmal der Code:
XAML:
Code:<!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Image Source="/whatstodo;component/Logo.png" Margin="13,-14,378,620" Stretch="Uniform" /> <controls:Pivot Title=" WHAT'S TO DO" Name="pivotAll" Loaded="pivotAll_Loaded"> <controls:PivotItem Header="today"> <ListBox Name="lbToday" ItemsSource="{Binding Path=lstToday}" /> </controls:PivotItem> <controls:PivotItem Header="this week"> <ListBox Name="lbWeek" /> </controls:PivotItem> <controls:PivotItem Header="all"> <ListBox Name="lbAll" ItemsSource="{Binding lstAll}"/> </controls:PivotItem> </controls:Pivot> </Grid>
Code:public partial class MainPage : PhoneApplicationPage { // Static Variables public static ObservableCollection<Item> lstToday = new ObservableCollection<Item>(); public static ObservableCollection<Item> lstWeek = new ObservableCollection<Item>(); public static ObservableCollection<Item> lstAll = new ObservableCollection<Item>(); // Constructor public MainPage() { InitializeComponent(); DataContext = this; //MessageBox.Show("Initialize Component"); lstToday.Add(new Item("Testitem", DateTime.Now, DateTime.Now, "My Own Categpry", "Das sind\nmeine eigenen\nNotizen zu dem Eintrag hier.", false)); lbToday.ItemsSource = lstToday; lbWeek.ItemsSource = lstWeek; lbAll.ItemsSource = lstAll; } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { DateTime currentDate = DateTime.Now; lbToday.ItemsSource = null; foreach (Item item in lstAll) { if (item.endDate.ToString("yyyy'-'MM'-'dd").Equals(currentDate.ToString("yyyy'-'MM'-'dd"))) { lstToday.Add(item); MessageBox.Show("Item '" + item.name + "' added to Todaylist"); } } lbToday.ItemsSource = lstToday; } private void appBarNew_Click(object sender, EventArgs e) { NavigationService.Navigate(new Uri(string.Format("/EditAddItem.xaml"), UriKind.Relative)); } private void pivotAll_Loaded(object sender, RoutedEventArgs e) { //MessageBox.Show("Pivot_Loaded"); } }
Wenn du dich dazu bereit erklärst, einmal drüber zu schauen (so viel ist es ja noch nicht) würde ich dir einfach mal das ganze Projekt schicken.
Danke bis hierhin schon einmal und schönes Wochenende!
-
- 27.03.2011, 12:47
- #4
Ich habe mal schnell eine App geschrieben mit deinem Code da, nur mit dem Unterschied, dass ich keine Items, sondern einfach Strings genommen habe. Dies funktioniert ohne Probleme.
Es wäre vielleicht durchaus sinnvoll, wenn ich mal das komplette Projekt sehen würde. Vielleicht finde ich dann den Fehler.
Und ich habe herausgefunden, warum das mit dem Binding von der xaml aus nicht funktioniert.
Wenn du mal schaust, wird in der MainPage, wenn du "this." in der Liste der Möglichkeiten kein "lstToday" auftauchen. Deswegen nützt es auch nichts den DataContext = this zu setzen, wenn das Item zu dem du Binden willst, gar nicht in this drin ist.
-
Robby Light Gast
Mh, in Ordnung. Danke für deine Mühen bis hier.
Ich habe das Projekt auf meinen Server geladen, den Link dau schicke ich dir per PM.
Es geht konkret um folgendes:
Ich schreibe eine ToDo-App. Ja ich weiß "Noch eine?". Ja, noch eine. Da mich keine der ToDo-Apps im Marketplace wirklich anspricht und all meine Wünsche rfüllt habe ich mich entschlossen selber eine zu basteln. Bin aber noch ganz am Anfang.
Wie du ja schon mitbekommen hast, gibt es die "all" Liste, in der alle Einträge (bei mir "Items") zu finden sind.
Wenn man also einen Eintrag erstellt wird dieser der Liste, die an die all-Listbox gebunden ist hinzugefügt.
Soblad der Nutzer vom Eingabebildschirm zurückkehrt (onNavigatedTo) prüft das Programm, ob in der All-Liste Einträge sind, die als Enddatum "Heute" haben. Ist dies der Fall, fügt es dieses Item der "today" Liste hinzu. Der Zeitpunkt mag etwas ungünstig gewäht sein, mir fällt aber derzeit kein besserer ein
Ich wäre dir wirklich sehr dankbar, wenn du dir das Projekt einmal ansehen würdest!
-
- 27.03.2011, 16:10
- #6
Also, wie ich dir schon per PM mitgeteilt habe, habe ich den "Fehler" gefunden.
Das Problem liegt daran, dass dein "Item" ein UIElement ist. Dieses hast du in der Liste "lstAll" drin. Jetzt willst du dieses aber auch in der Liste von "lstToday" einfügen.
Jetzt hättest du 2 mal das gleiche UIElement auf deiner Seite. Dies verursacht den Fehler.
Eine Lösung:
Mache dein Item ein ViewModel.
Hier mal der Vorläufige Code dafür:
Code:using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.ComponentModel; namespace whatstodo.ViewModels { public class Item : INotifyPropertyChanged { public string name, category, details; public DateTime startDate, endDate; public bool important; /// <summary> /// New Item for the To-Do-List /// </summary> /// <param name="s1">item's name</param> /// <param name="s2">start date</param> /// <param name="s3">end date</param> /// <param name="s4">category</param> /// <param name="s5">details</param> /// <param name="b1">important</param> public Item(string s1, DateTime s2, DateTime s3, string s4, string s5, bool b1) { // read values in this.name = s1; this.startDate = s2; this.endDate = s3; this.category = s4; this.details = s5; this.important = b1; } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String name) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(name)); } } }
Das sähe dann so aus für eine Variable:
Code:private string _name; public string Name{ get{ return _name;} set{ if(_name != value){ _name = value; NotifyPropertyChanged("Name");}}}
Am restlichen Code müsstest du wenig ändern.
Jetzt geht zu deinem UIElement "Item".
Hier wird nicht viel gemacht.
Du musst ein DependencyObject hinzufügen, damit wir dieses dann immer mit einem "ViewModels.Item" binden können.
Hier der von mir geänderte bzw hinzugefüge Code:
Code:public static readonly DependencyProperty ShowItemProperty = DependencyProperty.RegisterAttached("ShowItem", typeof(ViewModels.Item), typeof(Item), new PropertyMetadata(null, new PropertyChangedCallback(ShowItemPropertyChanged))); public ViewModels.Item ShowItem { get { return (ViewModels.Item)GetValue(ShowItemProperty); /*this.Textbox_Eingabe.Text;*/ } set { SetValue(ShowItemProperty, value); } } private static void ShowItemPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { if (e.NewValue != null) { Item box = (Item)sender; ViewModels.Item value = e.NewValue as ViewModels.Item; if(value != null) box.SetThis(value.name, value.startDate, value.endDate, value.category, value.details, value.important); } } /// <summary> /// New Item for the To-Do-List /// </summary> /// <param name="s1">item's name</param> /// <param name="s2">start date</param> /// <param name="s3">end date</param> /// <param name="s4">category</param> /// <param name="s5">details</param> /// <param name="b1">important</param> public Item(string s1, DateTime s2, DateTime s3, string s4, string s5, bool b1):this() { SetThis(s1, s2, s3, s4, s5, b1); } public Item() { InitializeComponent(); } /// <summary> /// New Item for the To-Do-List /// </summary> /// <param name="s1">item's name</param> /// <param name="s2">start date</param> /// <param name="s3">end date</param> /// <param name="s4">category</param> /// <param name="s5">details</param> /// <param name="b1">important</param> void SetThis(string s1, DateTime s2, DateTime s3, string s4, string s5, bool b1) { // read values in this.name = s1; this.startDate = s2; this.endDate = s3; this.category = s4; this.details = s5; this.important = b1; // show values tbName.Text = name; tbStartDate.Text = s2.ToString("dd. MMMM yyyy"); tbEndDate.Text = s3.ToString("dd. MMMM yyyy"); tbCategory.Text = category; tbDetails.Text = details; if (details.Equals("")) { btnShowDetails.Visibility = Visibility.Collapsed; } if (important) { tbImportant.Visibility = Visibility.Visible; } // adjust category's background width double recCatBgWidth = tbCategory.ActualWidth; recCatBg.Width = 23 + recCatBgWidth; }
Was jetzt noch gemacht werden muss, ist eine kleine Änderung an der xaml der MainPage:
Code:<controls:PivotItem Header="today"> <ListBox Name="lbToday" ItemsSource="{Binding Path=lstToday}" > <ListBox.ItemTemplate> <DataTemplate> <my:Item ShowItem="{Binding}" Width="Auto" Height="Auto"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </controls:PivotItem>
Zur Info:
Das Item was ich erstellt habe, habe ich bei ViewModels in den Ordner gepackt.
Dann müsstest du beim Codebehind der MainPage und deiner anderen Pages die die Listen bearbeiten jeweils deine ObservableCollection<Item>
zu ObservableCollection<ViewModels.Item> ändern.
Und natürlich auch deine anderen "Item" in "ViewModels.Item"
Und vergiss nicht, dass wenn du Edit und delete einbaust, dass du dann nicht das "Item" veränderst, bei dem dies geklickt wurde, sondern, dass du das ShowItem änderst, was in dem geklickten Item gespeichert ist.
Für das jetzt funktionierende Projekt, schick mir am besten eine mailadresse, an die ich das senden kann. Oder baue es dir selber aus meinen Codeschnippseln zusammen
Bei weiteren Fragen, einfach melden
-
Robby Light Gast
Funktioniert alles einwandfrei! Super, dass du mal drüber geguckt hast! Vielen Dank.
Ich hätte allerdings schon direkt meine nächste Frage:
ich bin jetzt, wie du ja bereits angekündigt hast soweit, dass ich eine delete und edit-funktion einbauen möchte.
Wie komme ich denn nun an das Item hinter dem Viewmodel dran, bzw. wie kann ich wenn ich das Item lösche auch alle damit verknüpften ViewModels löschen?
Vielen Dank nocheinmal für deine Mühen!
-
- 29.03.2011, 18:09
- #8
Das ist relativ einfach.
Du hast ja dein Item.xaml. Dort hast du das Contextmenü. Bei einem Klick auf delete, musst du nur einfach im Codebehind das "ShowItem" nehmen und aus der ObservableCollection löschen. Damit verschwindet es dann automatisch aus der Liste.
Also sowas:
MainPage.lstToday.Remove(ShowItem);
MainPage.lstAll.Remove(ShowItem);
Es wäre natürlich schöner, wann die Liste nicht auf der MainPage liegen würde, sondern im Mainviewmodel. Dann könntest du einfach:
App.Viewmodel.lstToday.Remove(ShowItem);
und so machen.
Das ist in dem Fall schöner, weil man dann alle Daten in diesem einem ViewModel hat und nicht mal ein paar Daten auf der MainPage und ein paar auf einer anderen Seite.
Aber das sei dir überlassen.
Da du nicht mit ViewModels arbeitest, ist das Bearbeiten ein klein wenig schwieriger.
Ich hätte das jetzt so gemacht, dass du im Mainviewmodel ein Item drin gespeichert hast und dieses dann einfach von der EditAddItem.xaml veränderst.
(In meinem Fall vom Bahn Connector sind das 2 Zeilen Code...)
In deinem Fall, musst du ein wenig Code umschreiben.
Zum einem musst du beim klicken auf Edit, dein aktuelles Item irgendwo zwischenspeichern.
Dann zu der EditAddItem.xaml navigieren.
Dort beim Laden dann die Werte vom Zwischengespeicherten Item in die Seite laden und beim klick auf speichern dann die Veränderten Daten in das zwischengespeicherte Item schreiben.
Das geht noch vom Arbeitsaufwand her, denke ich.
Ich hätte das aber anders gelöst und zwar so:
Im Mainviewmodel ein Item:
ViewModels.Item AktuellesItem; (hier als Property, so wie ich im meinem letzten Beitrag erwähnt habe)
Beim klick auf der MainPage auf neues Item, würdest du dann
App.Viewmodel.AktuellesItem = new ViewModels.Item;
machen und dann zur EditAddItem.xaml wechseln.
In der EditAddItem.xaml hätte ich dann kaum Codebehind, sondern nur Bindings verwendet, so:
<TextBox Height="72" Margin="0,25,0,0" Name="tbxName" Text="{Binding AktuellesItem.Name,Mode=TwoWay}" HorizontalScrollBarVisibility="Visible" Tag="Hello" VerticalAlignment="Top" />
Und das natürlich auch für alle anderen Felder und Variablen von dem Item.
In diesem Fall, nimmt das Fald Name, automatisch den Wert des Items an, was in App.Viewmodel.AktuellesItem.Name drin gespeichert ist.
Veränderst du über die TextBox den Namen, wird dieser ohne das du dafür Code schreiben musst, automatisch auch im AktuellesItem verändert ohne Codebehind.
Das einzige andere was du dann noch machen müsstest im Codebehind, wäre im Konstruktor:
this.DataContext = App.Viewmodel;
Was du dann machen müsstest, ist nur noch sehr wenig:
Du müsstest bei einem neuen Item handlen, dass wenn du auf der Seite EditAddItem.xaml auf speichern klickst, dass dann das App.Viewmodel.AktuellesItem zu der entsprechenden Liste hinzugefügt wird.
Und wenn das kein neues Item ist, dass nichts gemacht wird.
Dann wäre das Bearbeiten von einem Item mit 2 Zeilen Code zu erledigen, von der Item.xaml bei einem klick auf edit:
App.Viewmodel.AktuellesItem = ShowItem;
+ navigation zur EditAddItem.xaml
Das klingt jetzt vielleicht alles ein wenig kompliziert was ich geschrieben habe, aber das solltest du hinbekommen
Und wie gesagt, du musst keine Viewmodels benutzen, es wird aber deine Arbeit um einiges erleichtern, wenn deine App immer mehr Code beinhalten wird.
-
Robby Light Gast
-
- 07.04.2011, 15:14
- #10
Ganz einfach.
Beispiel:
Dein ViewModel heißt MainViewModel und ist in der App.xaml.cs
Im MainViewModel hast du 2 Itemlisten, sagen wir mal lstToday, lstDone vom Typ ObservableCollection<ViewModels.Item> (wenn ich mich richtig erinnere war das Item im Ordner ViewModels oder?)
Beim Clicken auf den Button zum verschieben, kannst du dann ganz einfach sowas machen:
Code:for(int i = 0; i < App.ViewModel.lstToday.Count; i++) { if(App.ViewModel.lstToday[i].IsChecked == true) { App.ViewModel.lstDone.Add(App.ViewModel.lstToday[i]); App.ViewModel.lstToday.RemoveAt(i); i--; } }
Da das MainViewModel Global in der App.xaml.cs gespeichert ist, kannst du von jeder Klasse, Seite und jedem Ort in deiner App darauf zugreifen.
Ähnliche Themen
-
Binding + statischer Text
Von Outlaw im Forum Windows Phone 7 EntwicklungAntworten: 3Letzter Beitrag: 25.04.2012, 10:21 -
Enum an ListBox / ComboBox binden
Von EddieDean im Forum Windows Phone 7 EntwicklungAntworten: 0Letzter Beitrag: 23.03.2011, 11:03 -
Observable Collection, PropertyChanged bereits definiert(fehler)...?
Von AEG im Forum Windows Phone 7 EntwicklungAntworten: 6Letzter Beitrag: 02.03.2011, 09:25 -
Uhrzeit Listbox
Von Schledi im Forum Windows Phone 7 EntwicklungAntworten: 3Letzter Beitrag: 25.01.2011, 20:23 -
RadioBoxen Status in Observable Collection Speichern
Von Nemoc im Forum Windows Phone 7 EntwicklungAntworten: 0Letzter Beitrag: 21.01.2011, 18:39
Pixel 10 Serie mit Problemen:...