Windows Phone Adding to List issue - windows-phone-7

(Windows Phone 7 SDK)
Hi,
I have a ListBox named CTransactionList, and adding some items to this listbox by using data bindings. And Here I have a class to evaulate data bindings.(I think my listbox's XAML code is not needed here as my issue comes out due to some coding problems)
public class CTransaction
{
public String Date1 { get; set; }
public String Amount1 { get; set; }
public String Type1 { get; set; }
public CTransaction(String date1, String amount1, String type1)
{
this.Date1 = date1;
this.Amount1 = amount1;
switch (type1)
{
case "FR":
this.Type1 = "Images/a.png";
break;
case "TA":
this.Type1 = "Images/b.png";
break;
case "DA":
this.Type1 = "Images/c.png";
break;
}
}
}
Here I have a function, when a move completes, this function runs;(this function is supposed to add new items when function runs)
List<CTransaction> ctransactionList = new List<CTransaction>();//Define my list
public void movecompleted()
{
String DefaultDate = "";
String DefaultAmount = "";
String RandomType = "";
DefaultDate = nameend.Text;
DefaultAmount = diffend.Text;
RandomType = "FR";
ctransactionList.Add(new CTransaction(DefaultDate, DefaultAmount, RandomType));
CTransactionList.ItemsSource = ctransactionList;
}
For the first time when move completes, it adds the required elements to my list. But for next times, it does not add to my list. The old one keeps its existence. I tried also this format by getting list definition into my function like:
public void movecompleted()
{
List<CTransaction> ctransactionList = new List<CTransaction>(); //List definition in function
String DefaultDate = "";
//...Same
}
And this time, it replaces my current item with new one. Do not append at the end of list. (Both ways, I have one item in my list, not more) How can I do everytime append to list? Where am I wrong?
Here is my Debugging report. Both ctransactionList object and CTransactionList ListBox have the needed items according to my observations in debug watcher. Only problem, CTransactionList cant refresh itself properly even if it has the resources retrieved from ctransactionList object.
Here is my XAML code for my relevant listbox.(IF NEEDED)
<Grid>
<ListBox Name="CTransactionList" Margin="0,0,0,0" >
<ListBox.ItemTemplate >
<DataTemplate>
<Button Width="400" Height="120" >
<Button.Content >
<StackPanel Orientation="Horizontal" Height="80" Width="400">
<Image Source="{Binding Type1}" Width="80" Height="80"/>
<StackPanel Orientation="Vertical" Height="80">
<StackPanel Orientation="Horizontal" Height="40">
<TextBlock Width="100" FontSize="22" Text="Name:" Height="40"/>
<TextBlock Width="200" FontSize="22" Text="{Binding Date1}" Height="40"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="40">
<TextBlock Width="100" FontSize="22" Text="Difficulty:" Height="40"/>
<TextBlock Width="200" FontSize="22" Text="{Binding Amount1}" Height="40"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Button.Content>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Thanks in advance.

As you rightly mentioned, it's not related to your XAML. Problem is in your code.
First simple fix may to clear the ItemsSource before setting the new source, like this
CTransactionList.ItemsSource = null;
CTransactionList.ItemsSource = ctransactionList;
This way, you are clearing the existing the databinding and enforcing the new list into the ListBox.
The other and suggestible fix is,
"Change your List to ObservableCollection. Because, ObservableCollection extends the INotifyPropertyChanged and hence has the ability to auto update the ListBox"
List<CTransaction> ctransactionList = new List<CTransaction>();//Change this to below
ObservableCollection<CTransaction> ctransactionList = new ObservableCollection<CTransaction>();//Define my collection

But a breakpoint before
CTransactionList.ItemsSource = ctransactionList;
And run the function twice. Do you have two items in ctransactionList now?
I suspect the binding fails and ctransactionList are in fact increasing

Related

TabControl and ObservableCollection UI Refresh

I'm becoming crazy i don't understand why my ObservableCollections have a strange behaviour. I have tabs :
<Grid Grid.Row="1">
<TabControl Grid.Row="1">
<TabItem Header="Posts instagrams">
<DataGrid ItemsSource="{Binding InstagramPhotos, Mode=TwoWay}" />
</TabItem>
<TabItem Header="Shop">
<DataGrid ItemsSource="{Binding ShopPhotos, Mode=TwoWay}" />
</TabItem>
<TabItem Header="Articles">
<DataGrid ItemsSource="{Binding ArticlePhotos, Mode=TwoWay}" />
</TabItem>
</TabControl>
</Grid>
The ObservableCollections are defined like this :
private ObservableCollection<PhotoModel> _instagramPhotos;
public ObservableCollection<PhotoModel> InstagramPhotos
{
get => _instagramPhotos ?? (_instagramPhotos = new ObservableCollection<PhotoModel>());
set
{
_instagramPhotos = value;
RaisePropertyChanged("InstagramPhotos");
}
}
private ObservableCollection<PhotoModel> _shopPhotos;
public ObservableCollection<PhotoModel> ShopPhotos
{
get => _shopPhotos ?? (_shopPhotos = new ObservableCollection<PhotoModel>());
set
{
_shopPhotos = value;
RaisePropertyChanged("ShopPhotos");
}
}
private ObservableCollection<ArticleModel> _articlePhotos;
public ObservableCollection<ArticleModel> ArticlePhotos
{
get => _articlePhotos ?? (_articlePhotos = new ObservableCollection<ArticleModel>());
set
{
_articlePhotos = value;
RaisePropertyChanged("ArticlePhotos");
}
}
I bind commands for adding/update/delete element in each collections. The update work fine on every UI. BUT where it's strange is that the Add event works correctly in first tab but delete doesn't. And in other tab, add event doesn't work but delete works. I clearly don't understand why.
FINALLY found out ! I was using this
DataContext="{Binding Source={StaticResource DataViewModel}}"
So it doesn't update. I put it in <Window.DataContext> tag and works well

Set focus of an entry from ViewModel

I've read about messaging, triggers, behaviors, etc. ... all seems a bit overkill for what I am trying to accomplish.
I have a repeating data entry screen in xaml that has 1 picker, 2 entries, and 1 button. The picker, once a value is selected, keeps that selection. The 1st entry does the same as the picker. The 2nd entry is the one that is always getting new values.
I want to collect the filled in values on click of the button and then clear the last entry field of its data and put focus back on that entry so the user can enter a new value and hit save. repeat repeat repeat etc.
I understand the MVVM model and theory - but I just want to put the focus on an entry field in the xaml view and am completely stumped.
EDIT to add code samples
view.xaml:
<StackLayout Spacing="5"
Padding="10,10,10,0">
<Picker x:Name="Direction"
Title="Select Direction"
ItemsSource="{Binding Directions}"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding SelectedDirection}"/>
<Label Text="Order"/>
<Entry Text="{Binding Order}"
x:Name="Order" />
<Label Text="Rack"/>
<Entry Text="{Binding Rack}"
x:Name="Rack" />
<Button Text="Save"
Style="{StaticResource Button_Primary}"
Command="{Binding SaveCommand}"
CommandParameter="x:Reference Rack" />
<Label Text="{Binding Summary}"/>
</StackLayout>
viewmodel.cs
public ICommand SaveCommand => new DelegateCommand<View>(PerformSave);
private async void PerformSave(View view)
{
var scan = new Scan()
{
ScanType = "Rack",
Direction = SelectedDirection.Name,
AreaId = 0,
InsertDateTime = DateTime.Now,
ReasonId = 0,
ScanItem = Rack,
OrderNumber = Order,
ScanQty = SelectedDirection.Value,
IsUploaded = false
};
var retVal = _scanService.Insert(scan);
if (!retVal)
{
await _pageDialogService.DisplayAlertAsync("Error", "Something went wrong.", "OK");
}
else
{
view?.Focus();
Rack = string.Empty;
Summary = "last scan was great";
}
}
Error shows up in this section:
private void InitializeComponent() {
global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(RackPage));
Direction = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.Picker>(this, "Direction");
Order = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.Entry>(this, "Order");
Rack = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.Entry>(this, "Rack");
}
You can send the Entry as a View parameter to your view model's command. Like that:
public YourViewModel()
{
ButtonCommand = new Command<View>((view) =>
{
// ... Your button clicked stuff ...
view?.Focus();
});
}
And from XAML you call this way:
<Entry x:Name="SecondEntry"
... Entry properties ...
/>
<Button Text="Click Me"
Command="{Binding ButtonCommand}"
CommandParameter="{Reference SecondEntry}"/>
I hope it helps.
You can set the CommandParameter in the XAML and use that in the viewmodel.
In Xaml:
<ContentView Grid.Row="0" Grid.Column="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image Source="downarrow" HeightRequest="15" WidthRequest="15" VerticalOptions="Center" HorizontalOptions="End" Margin="0,0,5,0" />
<ContentView.GestureRecognizers>
<TapGestureRecognizer Command="{Binding SecurityPopupCommand}" CommandParameter="{x:Reference AnswerEntry}"/>
</ContentView.GestureRecognizers>
</ContentView>
In view model:
public ICommand SecurityPopupCommand { get { return new Command(OpenSecurityQuestionPopup); } }
private void OpenSecurityQuestionPopup(object obj)
{
var view = obj as Xamarin.Forms.Entry;
view?.Focus();
}
Not sure you can set the focus of an entry from the XAML, but from the page, you could just use the function Focus of the Entry on the Clicked Event:
saveButton.Clicked += async (s, args) =>
{
//save the data you need here
//clear the entries/picker
yourEntry.Focus();
};

MVVM Binding Problems with Pivot ItemTemplates Windows Phone 7

I have a Pivot element that has a header template and an itemtemplate with a listbox which also has a itemtemplate. The header template is bound to a list of "DOWS" which i create via code. This works fine. Each DOW has a entityset TDs and i want to bind the listbox itemtemplate to this source. Once i bound it, deleting an item updates the ui fine but adding an item doesn't update the ui.
the entityset is based off of the "Local database with mvvm" example here:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh286405(v=vs.105).aspx
I've researched for a few days and cant find anything helpful. some solutions i found where to wrap the entityset in a observable collection but that didnt seem to work. Another one was to use BindingLists, but entitySets dont have "ToBindingList()" for windows phone 7. Ive created observable collections in my ViewModel that i could bind to, but then i have no way of telling the listbox itemtemplate which collection to bind to when its created.
Any ideas?
I Can post more code if needed.
Thanks!!
Example Observablen Collections in ViewModel
private ObservableCollection<TDItem> _twoDaysAgoItems;
public ObservableCollection<TDItem> TwoDaysAgoItems
{
get { return _twoDaysAgoItems; }
set
{
_twoDaysAgoItems = value;
NotifyPropertyChanged("TwoDaysAgoItems");
}
}
private ObservableCollection<TDItem> _yesterdayItems;
public ObservableCollection<TDItem> YesterdayItems
{
get { return _yesterdayItems; }
set
{
_yesterdayItems = value;
NotifyPropertyChanged("YesterdayItems");
}
}
private ObservableCollection<TDItem> _todayItems;
public ObservableCollection<TDItem> TodayItems
{
get { return _todayItems; }
set
{
_todayItems = value;
NotifyPropertyChanged("TodayItems");
}
}
EntitySet
private EntitySet<TDItem> _tds;
[Association(Storage = "_ts", OtherKey = "_dowId", ThisKey = "Id")]
public EntitySet<TDItem> TDs
{
get { return this._tds;
}
set {
NotifyPropertyChanging("TDs");
this._tds.Assign(value);
NotifyPropertyChanged("TDs");
}
}
public DOW()
{
_tds = new EntitySet<TDItem>(
new Action<TDItem>(this.attach_TD),
new Action<TDItem>(this.detach_TD)
);
}
Pivot
<controls:Pivot x:Name="TDPivotDisplay" SelectedIndex="2" Margin="0,-10,0,0" Grid.Row="0" Title="TD" Foreground="White" FontWeight="light" VerticalAlignment="Top" FontSize="29.333" Style="{StaticResource PivotStyle1}" FontFamily="{StaticResource Akzidenz Grotesk}">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="DOW" Foreground="{Binding Colour}" FontSize="110" FontFamily="{StaticResource Akzidenz Grotesk}" Text="{Binding Header}"/>
<TextBlock x:Name = "FullDate" Foreground="{Binding Colour}" FontWeight="light" FontSize="30" FontFamily="{StaticResource Akzidenz Grotesk}" HorizontalAlignment="center" Text="{Binding Date}"/>
</StackPanel>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<Grid Height="421">
<ListBox ItemsSource = "{Binding TDs}" ItemTemplate = "{StaticResource ListboxItemTemp}" x:Name ="TDLists" Margin="12, 0, 12, 0" Width="440"/>
</Grid>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>

ArgumentOutOfRangeException when returning to page containing List

I am having a simple list of todo's that's stored in a List-object, that's shown through a ListBox through data binding. The items are clickable, and they take you to a details page, where you can also delete the task. Everything works out fine, but when I click the back-button, I get an ArgumentOutOfRangeException and the app crashes.
Now, I gather this is because the app thinks the list still has items, but I'm not quite sure how to fix it.
The exception is raised on System.Windows.dll - nothing specific. Also, I know the exception is raised after the OnNavigatedTo-event.
XAML (just the listbox - somewhat simplified):
<ListBox Name="MyActivitiesList" ItemsSource="{Binding MyActivities}" SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<StackPanel Margin="0,0,0,12">
<-- context menu was here, but has been removed -->
<TextBlock Text="{Binding Title}" Style="{StaticResource BigHeader}"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Category.Name}" Style="{StaticResource SubtleText}"/>
<TextBlock Text=" - " Style="{StaticResource SubtleText}"/>
<TextBlock Text="{Binding VotesPercentage}" Style="{StaticResource SubtleText}"/>
<TextBlock Text="% positive" Style="{StaticResource SubtleText}" />
</StackPanel>
</StackPanel>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code-behind:
private MyActivitiesViewModel myActivitiesViewModel;
public MyActivitiesView()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
myActivitiesViewModel = new MyActivitiesViewModel();
this.DataContext = myActivitiesViewModel;
base.OnNavigatedTo(e);
}
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
MyActivitiesList.SelectedItem = null;
base.OnNavigatingFrom(e);
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (((ListBox)sender).SelectedItem != null)
{
var idea = ((ListBox)sender).SelectedItem as Idea;
((ListBox)sender).SelectedItem = null;
Dispatcher.BeginInvoke(() => NavigationUtility.Navigate(new Uri("/View/IdeaView.xaml", UriKind.Relative), idea));
}
}
Any ideas? Help would be greatly appreciated!
I think the problem might be that you are deleting an item from the list while that same item is bound to the current item in the list box.
One easy way to workaround this is to use an ObservableCollection instead of a List - the collection will tell the list box about any deletion using the INotifyCollectionChanged mechanism.

Passing Object rather than selectedIndex from Databound listbox

I'm having an issue when I try to pass the selectedIndex of my list from my "List" screen.
On my List screen I have the following binding:
Code Behind:
lbPrograms.ItemsSource = App.ViewModel.Items;
XAML:
<ListBox x:Name="lbPrograms" ItemsSource="{Binding Items}" SelectionChanged="lbPrograms_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="DataTemplateStackPanel" Orientation="Horizontal">
<Image x:Name="ItemImage" Source="/images/ArrowImg.png" Height="43" Width="43" VerticalAlignment="Top" Margin="10,0,20,0"/>
<StackPanel>
<TextBlock x:Name="ItemText" Text="{Binding programName}" Margin="-2,-13,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock x:Name="DetailsText" Text="{Binding createDate}" Margin="0,-6,0,3" Style="{StaticResource PhoneTextSubtleStyle}"/>
<TextBlock x:Name="programId" Text="{Binding programId}" Margin="0,-6,0,3" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
<!--<Image x:Name="ItemFavs" Source="/images/favs.png" Height="43" Width="43" VerticalAlignment="Top" Margin="10,0,20,0"/>
<Image x:Name="ItemDelete" Source="/images/delete.png" Height="43" Width="43" VerticalAlignment="Top" Margin="10,0,20,0"/>-->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In my detail screen I look up using the selectedIndex value:
App.ViewModel.Refresh();
DataContext = App.ViewModel.Items[index].nValDictionary;
However, since I can't figure out how to just update a value in my iEnumerable collection I have been removingAt[index] and then re-adding to the collection.
So can anyone tell me, how do use update an existing element in my collection? If not, can I pass the programId (that is in my binding) instead of the selectedIndex as the indexes are getting all messed up after the Delete/Add functionality.
Please Advise.
UPDATE:
After speaking in several forums I should clear up that I am implement INotifyChanged Event on my properties in my object.
Basically the following snippet of code is my current issue:
private void FavBtn_Click(object sender, EventArgs e)
{
foreach (var item in App.ViewModel.Items)
{
if ((item.currentProgram == true) && (item.programId != index))
{
item.currentProgram = false;
}
if (item.programId == index)
{
item.currentProgram = true;
}
}
When I run this everything looks to be ok.
However, when I navigate to another page, I re-load the object and the changes are lost. It is almost like I need to save them before navigating, however, if I do a item.Save(); I get duplicates in my list.
I'm guessing you haven't implemented INotifyPropertyChanged on your Items class yet.
Implementing this will allow updates made in these objects to be updated through your data bindings.
Here's a walkthrough on how to implement INotifyPropertyChanged.
How to: Implement the INotifyPropertyChanged Interface
Is App.ViewModel.Items of type ObservableCollection<T>?
If so, when you modify a property of one of the collection items and raise a property change event (via INotifyPropertyChanged) indicating the collection property that your ListBox.ItemsSource is bound to, the DataTemplate bindings will do the rest.

Resources