Passing Object rather than selectedIndex from Databound listbox - windows-phone-7

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.

Related

Navigate to specific page defined on model when Item is Tapped

I'm trying to make a custom home page where pages are listed on an Horizontal scroll view as "Services" so each one of them should navigate to a different Page.
I have a view like this:
<controls:HorizontalScrollView HeightRequest="160"
Orientation="Horizontal"
ItemsSource="{Binding OwnerServicesList}"
x:Name="OwnerServicesSlider"
ItemSelected="OwnerServicesSlider_ItemSelected">
<controls:HorizontalScrollView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Margin="10,0,5,0" WidthRequest="100" HeightRequest="100">
<Image HorizontalOptions="Start" Source="{Binding ImgUrl}" WidthRequest="100" HeightRequest="100" />
<Label Style="{StaticResource BoldLabel}" HorizontalTextAlignment="Center" FontSize="13" LineBreakMode="TailTruncation" Text="{Binding Name}" TextColor="Black"/>
</StackLayout>
</ViewCell>
</DataTemplate>
Im using a custom made controller for a Horizontal Scroll view that works like a listview, every item on tap raises a ItemTappedEventArgs event.
Inside my model i´ve declared a public Page Page { get; set; } for each object in the scroll view.
What im trying to do is recover the tapped element and recover the Page stored in it so that I can Navigate to that specific page.
So far I have something like this:
private void OwnerServicesSlider_ItemSelected(object sender, ItemTappedEventArgs e)
{
var service = OwnerServicesSlider.SelectedItem as Services;
Navigation.PushAsync(service.Page);
}
It shows no errors but when I run it I get a
InvalidOperationException: 'Page must not already have a parent.
Any hint will be appreciated!
as Jason said,maybe the page you would push which is exist in thecurren navigation structure,there is a workaround ,before you push the page :
private void OwnerServicesSlider_ItemSelected(object sender, ItemTappedEventArgs e)
{
var service = OwnerServicesSlider.SelectedItem as Services;
service.Page.Parent = null;
Navigation.PushAsync(service.Page);
}

windows phone 8 longlistselector show and hide button based on recordid

I have a books list displayed in my long list selector like this
<DataTemplate x:Key="BooksItemTemplate">
<StackPanel Grid.Column="1" Grid.Row="0" VerticalAlignment="Top">
<TextBlock Name="booktitle" Text="{Binding BookTitle,Mode=OneWay}" Style="{StaticResource PhoneTextNormalStyle}" TextWrapping="Wrap" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
<TextBlock Text="{Binding AuthorName,Mode=OneWay}" Style="{StaticResource PhoneTextNormalStyle}" TextWrapping="Wrap" FontFamily="{StaticResource PhoneFontFamilySemiLight}"/>
<Button Content="Add To Favourites" Tag="{Binding BookId,Mode=OneWay}" Click="Button_Click_1" ></Button>
</StackPanel>
</Grid>
</DataTemplate>
<phone:LongListSelector x:Name="bookslist" Grid.Row="1"
ListFooter="{Binding}"
ItemsSource="{Binding BooksList}"
Background="Transparent"
IsGroupingEnabled="False"
ListFooterTemplate ="{StaticResource booksListFooter}"
ItemTemplate="{StaticResource BooksItemTemplate}"/>
so there is an add to favourites button beside every book in the list . pressing that button i am entering the pressed book's id in my isolatedstoragesetting like this
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Button bt = (Button)sender;
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
List<long> ListFavourites;
if (settings.Contains("ListFavourites"))
{
ListFavourites = settings["ListFavourites"] as List<long>;
}
else
{
ListFavourites = new List<long>();
}
if(!ListFavourites.Contains(Convert.ToInt64(bt.Tag)))
{
ListFavourites.Add(Convert.ToInt64(bt.Tag));
}
settings["ListFavourites"] = ListFavourites;
settings.Save();
}
problem:
now when loading the above book list(longlistselector) when the page loads i want to show or hide the add to favorites button based on whether the bookid is present in the isolatedstoragesetting or not. what i have tried here is that i have tried to bind the converter to the add to favourite button and also bind the convertparameter with bookid. but the convertparameter doesn't support binding.
so what is the technique i can use to show or hide the add to favourite button based on the book id presence in the favourite list in the isolatedstoragesetting?
how can i hide the button based when clicking it based on the bookid?
You are almost there in thinking to use a converter. The actual idea, when materialized, should look something like this.
First, you will need to implement a converter, in this case, you will need to convert the bookid to a Visibility value.
public class BookIdToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
//value is booking id here, which means that you just need to check against the isolatedStorageSettings
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return null;
}
}
In your DataTemplate, the binding should take place like this:
<Button Content="Add To Favourites" Tag="{Binding BookId,Mode=OneWay}"
Click="Button_Click_1" Visibility={Binding BookId,Converter={StaticResource TheConverterCreatedAbove}} >
</Button>
That should do the trick.
The MVVM way would be to expand your ViewModel. It would be much better to add an AddToFavoritesCommand to BookViewModel instead of putting the logic in code behind. If the button is bound to that Command it would automatically go disabled when the Command would properly (with CanExecuteChanged) switch CanExecute to false.
In your case, you can add a property IsFavourite or CanAddToFavoirtes and then use a standard BoolToVisibility converter (the Command execution would set this property and the BookViewModel would be initialized with the correct value read from IsolatedStorage).
All logic behind the presentation of Book and functionalities related to Book belong to BookViewModel.

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.

assigning the result of variable into textblock

I'm trying to get the result of variable into a textblock.text proprety, I'm using
this code:
bool isavailable = NetworkInterface.GetIsNetworkAvailable();
result = isavailable.ToString();
<TextBlock Height="62" HorizontalAlignment="Left" Margin="12,60,0,0"
Name="textBlock1" Text="{Binding result}" VerticalAlignment="Top"
Width="400" Foreground="White" TextWrapping="Wrap" />`
Do you need to keep the binding? The simplest approach here would be to simply use:
textBlock1.Text = result;
However, the better approach would be to use a ViewModel implementing INotifyPropertyChanged with an appropriate property. Then you would make your TextBlock bind to the property, and set the property from your code. The property would raise the appropriate event, and the UI would update accordingly.

Databinding with Data Template on ComboBox Select Item using LINQ

I have a little Problem.
A SP give me a several list of URL´s. The Urls are binded on a Combobox.
When I Select an Item, always the Object comes to the Combobox not the Selected Value, see the code below:
<DataTemplate x:Key="Webadressen" DataType="{x:Type src2:GetWebadressenResult}" >
<StackPanel>
<Label Content="{Binding Path=Adresse}" />
</StackPanel>
</DataTemplate>
<ComboBox Width="192" IsEditable="True" Margin="2" Name="Cbox_GDWeb" ItemTemplate="{StaticResource Webadressen}" SelectionChanged="Cbox_GDWeb_SelectionChanged">
private void Cbox_GDWeb_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
GetWebadressenResult test = (GetWebadressenResult)this.Cbox_GDWeb.SelectedValue;
MessageBox.Show(test.Adresse.ToString());
this.Cbox_GDWeb.Text = test.Adresse.ToString(); /* Not Working cause the this Event calls the same Method */
}
Change your ComboBox to this
<ComboBox Width="192" IsEditable="True" Margin="2" Name="Cbox_GDWeb" DisplayMemberPath="Adresse" SelectedValuePath="Adresse" SelectedValue="{Binding Path=Adresse}">
then you wont need the Datatemplate and it will work fine
you also wont need the SelectionChange event to change your selecteditem

Resources