I have a databound xml reader. MainPage is connected to DetailsPage: When user clicks on the name in Main Page, She gets the details of this name (Age, Gender, Date of Birth etc.) in the DetailsPage.
I am in trouble with tombstoning atm. When I click on windows button, then click on back button I get into an empty DetailsPage.
What would be the easiest way to solve this problem? I tried to use TombstoneHelper but it also shows empty page.
DetailsPage.xaml
<controls:PanoramaItem Header="" Margin="0,0,0,80">
<ScrollViewer>
<StackPanel>
<TextBlock TextWrapping="Wrap" Width="432" Style="{StaticResource PhoneTextExtraLargeStyle}" Margin="0,0,0,10" d:LayoutOverrides="Width" Foreground="#DEFFFFFF"><Run Text="Personal D"/><Run Text="e"/><Run Text="tails"/></TextBlock>
<StackPanel HorizontalAlignment="Left" Width="432" Orientation="Horizontal">
<TextBlock TextWrapping="Wrap" Margin="20,0,7,0" Foreground="#DEFFFFFF"><Run Text="Name"/><Run Text=":"/></TextBlock>
<TextBlock x:Name="username" TextWrapping="Wrap" Text="{Binding Name}" Foreground="#DEFFFFFF" />
</StackPanel>
<StackPanel HorizontalAlignment="Left" Width="432" Orientation="Horizontal">
<TextBlock TextWrapping="Wrap" Margin="20,0,7,0" Foreground="#DEFFFFFF"><Run Text="Age"/><Run Text=":"/></TextBlock>
<TextBlock x:Name="age" TextWrapping="Wrap" Text="{Binding Age}" Foreground="#DEFFFFFF"/>
</StackPanel>
<StackPanel HorizontalAlignment="Left" Width="432" Orientation="Horizontal">
<TextBlock TextWrapping="Wrap" Margin="20,0,7,0" Foreground="#DEFFFFFF"><Run Text="Nationality"/><Run Text=":"/></TextBlock>
<TextBlock x:Name="country" TextWrapping="Wrap" Text="{Binding Country}" Foreground="#DEFFFFFF"/>
</StackPanel>
<StackPanel HorizontalAlignment="Left" Width="432" Orientation="Horizontal">
<TextBlock TextWrapping="Wrap" Margin="20,0,7,0" Foreground="#DEFFFFFF"><Run Text="Country of Birth"/><Run Text=":"/></TextBlock>
<TextBlock x:Name="cobirth" TextWrapping="Wrap" Text="{Binding Cobirth}" Foreground="#DEFFFFFF"/>
</StackPanel>
<StackPanel HorizontalAlignment="Left" Width="432" Orientation="Horizontal">
<TextBlock TextWrapping="Wrap" Margin="20,0,7,0" Foreground="#DEFFFFFF"><Run Text="Place of Birth"/><Run Text=":"/></TextBlock>
<TextBlock x:Name="fobirth" TextWrapping="Wrap" Text="{Binding Pobirth}" Foreground="#DEFFFFFF"/>
</StackPanel>
</StackPanel>
</ScrollViewer>
</controls:PanoramaItem>
DetailsPage.cs
using TombstoneHelper;
public User()
{
InitializeComponent();
SupportedOrientations = SupportedPageOrientation.Portrait;
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
this.SaveState(); // <- first line
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
this.RestoreState(); // <- second line
}
Mainpage.Cs
private void UserListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));
FrameworkElement root = Application.Current.RootVisual as FrameworkElement;
root.DataContext = (RosterItem)e.AddedItems[0];
((ListBox)sender).SelectedIndex = -1;
}
}
All things being equal Tombstone helper should just work. Remember that you need to have named your controls (with an x:Name attribute) for Tombstone helper to access them. Also make sure you are calling SaveState() in your NavigatedFrom() method and RestoreState() in NavigatedTo() (and not the other way round).
If that doesn't something must be wrong elsewhere in your code. We might be able to help if you post the relevant parts of your code.
Related
I know there should be a simple solution to this question but I just cant seem to figure it out here is what my code looks like:
<ListBox HorizontalAlignment="Left"
x:Name="locationsNB"
VerticalAlignment="Top"
Height="563"
Width="455"
SelectionChanged="locationsNB_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
Margin="18,0,0,0"
x:Name="placeDetails">
<Image Source="{Binding icon}"
Height="40"
Width="40"
VerticalAlignment="Top"
Margin="0,10,8,0" />
<StackPanel Width="350">
<TextBlock Text="{Binding name}"
FontSize="35"
Foreground="#399B81"
TextWrapping="Wrap" />
<TextBlock Text="{Binding vicinity}"
FontSize="20"
Foreground="#888888"
TextWrapping="Wrap" />
<TextBlock x:Name="reference"
Text="{Binding reference}"
Visibility="Collapsed" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want to get the stackpanel->reference text (Text="{Binding reference}") of the selected item I dont know what my C# should look like but any help will be greatly appreciated.
If the ItemsSource of your ListBox is bound to a collection of items then you can use the SelectedItem property of the ListBox
private void locationsNB_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listbox = (ListBox)sender;
var myObject = listbox.SelectedItem as MyCustomObject;
if (myObject == null) return;
// perform your custom logic with this item
}
I have an xaml code about listbox object:
<ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="FirstListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<TextBlock Text="{Binding LineOne}" TextWrapping="NoWrap" Margin="50,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="NoWrap" Margin="12,60,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
<CheckBox VerticalAlignment="Top" Margin="0,-5,0,0"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
i was get my listboxitem by the code :
ListBoxItem item = this.list.ItemContainerGenerator.ContainerFromIndex(2) as ListBoxItem;
but i don't know how to get all items in this listbox item (including textblock and checkbox option).
please help me. thanks all.
Ideally, you'd want to have your checkbox bound to a property of your item data model, so for example, you may have...
public string LineOne { get; set; }
public string LineTwo { get; set; }
public bool MyBooleanValue { get; set; }
and then
<ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="FirstListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<TextBlock Text="{Binding LineOne}" TextWrapping="NoWrap" Margin="50,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="NoWrap" Margin="12,60,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
<CheckBox Checked="{Binding MyBoolValue, Mode=TwoWay}" VerticalAlignment="Top" Margin="0,-5,0,0"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Then you can pull back the DataContext for the item you are currently looking at (on a tap method or similar), or when you parse through your "Items" collection, all the checkbox states will be in the child objects for you already.
I'm using ListBox with custom DataTemplate, in this DataTemplate I have two thumbnails, when user clicks on one of this images I need to display a popup with a full-sized image(something like lightbox in JavaScript). I tried to use the Popup control in the DataTemplate, but the popup is positioned to current element on ListBox, not centered in the screen, and I'm not able to make it modal. I also tried to use the Coding4Fun toolkit, but I can't find any documentation or do it without any help.
Here is code of listbox:
<ListBox MaxHeight="600" ItemsSource="{Binding Items}" x:Name="LooksList" u:ScrollViewerMonitor.AtEndCommand="{Binding FetchMoreDataCommand}" d:LayoutOverrides="GridBox" BorderThickness="0" Margin="0,0,0,62">
<ListBox.ItemTemplate>
<DataTemplate>
<views:LookListItem />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And views:LookListItem:
<Grid x:Name="LayoutRoot">
<StackPanel x:Name="MainPanel" Margin="0,53,0,0" Orientation="Horizontal">
<StackPanel x:Name="PhotosPanel" Margin="20,11,0,0" Width="198" Height="126" HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Horizontal">
<Border BorderThickness="3" BorderBrush="White" Margin="0" HorizontalAlignment="Left" Width="93" Height="126">
<Image Source="{Binding Photo1.Thumb}" VerticalAlignment="Center" Tap="Image_Tap" />
</Border>
<Border BorderThickness="3" BorderBrush="White" Margin="12,0,0,0" HorizontalAlignment="Right" Width="93" Height="126">
<Image Source="{Binding Photo2.Thumb}" VerticalAlignment="Center" />
</Border>
</StackPanel>
</StackPanel>
</Grid>
Photo1 and Photo2 should be clickable and after click it should be a popup.
Thanks in advance!
There are a few ways you can go about doing this. I'll show how you can do this with a little code behind.
In your xaml:
<Grid>
<ListBox ItemsSource="{Binding MyItems}" ItemTemplate="{Binding MyTemplate}"
SelectionChanged="ListBox_SelectionChanged"/>
<Popup x:Name="Popup">
<Grid>
<ToggleButton Content="X"
IsChecked="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"
HorizontalAlignment="Right" VerticalAlignment="Top"/>
<Image x:Name="PopupImage"/>
</Grid>
</Popup>
</Grid>
In your code behind:
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs args)
{
ListBox listBox = (ListBox)sender;
MyImageObject obj = (MyImageObject)listBox.SelectedItem;
ImagePopup.Source = MyImageObjct.LargeImageSource;
Popup.IsOpen = true;
// Unselect item so user can "reselect" it -- If you need item later, save it somewhere
listBox.SelectedItem = null;
}
// Handle the back key button to close the popup
protected override void OnBackKeyPress(CancelEventArgs e)
{
if(Popup.IsOpen)
{
Popup.IsOpen = false;
e.Cancel = true;
}
}
UPDATE BASED ON LATEST INFO
If you do not need your view in a separate UserControl (no logic, only placement of controls) you can still use the example, but instead of listening to the SelectionChanged event, listen to the Tap event of each Image.
<ListBox MaxHeight="600" ItemsSource="{Binding Items}" x:Name="LooksList"
BorderThickness="0" Margin="0,0,0,62">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="MainPanel" Margin="0,53,0,0" Orientation="Horizontal">
<StackPanel x:Name="PhotosPanel" Margin="20,11,0,0" Width="198" Height="126" HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Horizontal">
<Border BorderThickness="3" BorderBrush="White" Margin="0" HorizontalAlignment="Left" Width="93" Height="126">
<Image Source="{Binding Photo1.Thumb}" VerticalAlignment="Center" Tap="Image1_Tap" />
</Border>
<Border BorderThickness="3" BorderBrush="White" Margin="12,0,0,0" HorizontalAlignment="Right" Width="93" Height="126">
<Image Source="{Binding Photo2.Thumb}" VerticalAlignment="Center"
Tap="Image2_Tap" />
</Border>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
The event of for Tap events would look something like
private void Image1_Tap(object sender, GestureEventArgs gestureEventArgs)
{
MyImageObject obj = ((FrameworkElement)sender).DataContext as MyImageObject;
// This is the event for Image1 Thumb, so show the Image1 Large
ShowPopup(obj.Photo1.Large);
}
If you do need a separate UserControl
You could create an "ImageOverlay" view much like in my Custom MessageBox Post. In your LookListItem view subscribe to the tap event for both thumbs
<Grid x:Name="LayoutRoot">
<StackPanel x:Name="MainPanel" Margin="0,53,0,0" Orientation="Horizontal">
<StackPanel x:Name="PhotosPanel" Margin="20,11,0,0" Width="198" Height="126" HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Horizontal">
<Border BorderThickness="3" BorderBrush="White" Margin="0" HorizontalAlignment="Left" Width="93" Height="126">
<Image Source="{Binding Photo1.Thumb}" VerticalAlignment="Center" Tap="Thumb1_Tap" />
</Border>
<Border BorderThickness="3" BorderBrush="White" Margin="12,0,0,0" HorizontalAlignment="Right" Width="93" Height="126">
<Image Source="{Binding Photo2.Thumb}" VerticalAlignment="Center" Tap="Thumb2_Tap" />
</Border>
</StackPanel>
</StackPanel>
In the tap events show the ImageOverlay control
private void Thumb1_Tap(object sender, GestureEventArgs gestureEventArgs)
{
ShowOverlay(Photo1.Large);
}
private void Thumb2_Tap(object sender, GestureEventArgs gestureEventArgs)
{
ShowOverlay(Photo2.Large);
}
private void ShowOverlay(ImageSource source)
{
ImageOverlay overlay = new ImageOverlay();
overlay.ImageSource = source;
overlay.Show();
}
I've a LongListSelector with the following item template:
<DataTemplate x:Key="stopItemTemplate">
<Grid Margin="{StaticResource PhoneTouchTargetOverhang}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox VerticalAlignment="Top" HorizontalAlignment="Left" IsChecked="{Binding Checked}" Click="AlarmActivationClicked" />
<StackPanel Grid.Column="1" VerticalAlignment="Top">
<TextBlock Text="{Binding Stop.Name}" Style="{StaticResource PhoneTextLargeStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" TextWrapping="Wrap" Margin="12,-12,12,6"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Distanz:" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" Width="120"/>
<TextBlock Text="{Binding Distance, Converter={StaticResource MyStringFormatConverter}, ConverterParameter=:1000:\{0:0.0\} km}" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Alarm:" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" Width="120"/>
<TextBlock Text="{Binding Alarm, Converter={StaticResource MyBooleanStringConverter}}" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Vibration:" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" Width="120"/>
<TextBlock Text="{Binding Vibration, Converter={StaticResource MyBooleanStringConverter}}" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
And used as followed:
<controls:PivotItem Header="ziele">
<toolkit:LongListSelector x:Name="alarmList" Background="Transparent" IsFlatList="True"
ItemTemplate="{StaticResource stopItemTemplate}" SelectionChanged="AlarmListSelectionChanged" />
</controls:PivotItem>
The SelectionChanged event:
private void AlarmListSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var guid = ((AlarmItem)alarmList.SelectedItem).Id;
NavigationService.Navigate(new Uri(string.Concat("/AlarmDetailPage.xaml?id=", guid), UriKind.Relative));
}
To change details of an item I've subscribed the SelectionChanged event of the LongListSelector. That works as expected.
But if I tap on the checkbox - at first the clicked event of the checkbox is fired, but I don't recognize which checkbox was clicked (the property longlistselector.SelectedItem is old) and just after the SelectionChanged event has fired and try to navigate to the detail page like is happens if I intend to do that.
How can I separate these to events to avoid firing both? And how can I get the corresponding data item?
Thanks a lot...
Kind regards, Danny
You don't need listen to SelectionChanged event. In Click, Checked or Unchecked event handler you can get an item:
private void CheckBox_Checked(object sender, System.Windows.RoutedEventArgs e)
{
var guid = ((sender as CheckBox).DataContext as AlarmItem).Id;
NavigationService.Navigate(new Uri(string.Concat("/AlarmDetailPage.xaml?id=", guid), UriKind.Relative));
}
In your AlarmActivationClicked (event handler on the checkbox) you'll be able to get the dataitem of the item in the list that was click.
private void AlarmActivationClicked(object sender, RoutedEventArgs e)
{
var dataItem = ((FrameworkElement)sender).DataContext;
}
I am not seeing the event AlarmListSelectionChanged method being called after the AlarmActivationClicked method is called. If you click on the checkbox, the checkbox changes to checked, but it doesnt change the selection in the list box.
I am using List to bind a listbox which is as follows:
<ListBox x:Name="ContentPanel" SelectionChanged="onSelectionChanged" Background="LightGray" Grid.Row="2">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Name="{Binding title}" Height="165" Margin="25,5,25,0" Width="430">
<Border BorderThickness="1" Height="165" BorderBrush="Gray">
<toolkit:ContextMenuService.ContextMenu >
<toolkit:ContextMenu IsZoomEnabled="False">
<toolkit:MenuItem Name="Delete" Header="Delete Message" Click="DeleteMessage_Click" >
</toolkit:MenuItem>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<StackPanel Orientation="Vertical">
<StackPanel>
<TextBlock Text="{Binding title}" Margin="5,0,0,0" FontSize="25" Foreground="Black"/>
<TextBlock Text="{Binding msgFrom}" Padding="5" TextWrapping="Wrap" Foreground="Gray" FontSize="20"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,13,0,0" FontSize="24" Foreground="WhiteSmoke" Text="{Binding msgReceivedOn}"/>
<toolkit:ToggleSwitch Margin="170,10,0,0" IsChecked="{Binding msgStatus}" Unchecked="UnChecked" Background="LightBlue" Checked="Checked"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
At first data is successfully loaded. But when I use the Contextmenu to remove the item and reload the listbox.. it fires an exception. Code to handle the context menu click is:
private void DeleteMessage_Click(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
Message message = (Message)item.DataContext;
MessageBoxResult result = MessageBox.Show("Are you sure to delete the message??", "Confirmation", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.Cancel)
return;
else
{
ContentPanel.Items.Remove(message);
lstMessage.Remove(message);
}
ContentPanel.ItemSource = lstMessage;
}
But it this code is not working. So any suggestions?
You don't need each time to bind collection to a list. Also, when you remove an item from your collection, it should disappear also in the list (if binding setup properly). I think you have not ObservableCollection, so you need manage items manually. Please, consider to use ObservableCollection.
Your code should looks like:
lstMessage.Remove(message); //it must raises CollectionChanged event automatically
And this lines is unnecessary:
ContentPanel.Items.Remove(message);
ContentPanel.ItemSource = lstMessage;