ListBox ScrollIntoView not working OnNavigatedTo - c#

I'm making a timer with adjustable time. For that reason I want to set the time using listboxes (one for minutes and one for seconds). The filling of the listboxes is accomplished using the following code.
public EditTime()
{
this.InitializeComponent();
List<Numbers> numbers = new List<Numbers>();
for (int i = 0; i < 61; i++)
{
numbers.Add(new Numbers() { Number = i });
}
listBoxobjM.ItemsSource = numbers;
listBoxobjS.ItemsSource = numbers;
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
this.navigationHelper.SaveState += this.NavigationHelper_SaveState;
}
public class Numbers
{
public int Number { get; set; }
}
In XAML I have the following code for the ListBoxes:
<Grid Grid.Row="1" x:Name="ContentRootM" Margin="65,0,0,0" Width="130">
<ListBox Background="Transparent" Margin="10,10,10,10" BorderThickness="2" MaxHeight="580" Grid.Row="2" x:Name="listBoxobjM" VerticalContentAlignment="Top" HorizontalContentAlignment="Center">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Margin="5" BorderBrush="{ThemeResource ApplicationHeaderForegroundThemeBrush}" BorderThickness="1" Background="{ThemeResource ButtonBackgroundThemeBrush}">
<TextBlock TextAlignment="Left" HorizontalAlignment="Left" Width="70" Height="80" x:Name="LbM" Text="{Binding Number}" FontSize="48" Foreground="{ThemeResource ButtonForegroundThemeBrush}" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<Grid Grid.Row="1" x:Name="ContentRootS" Margin="10,0,0,0" Width="130">
<ListBox Background="Transparent" Margin="10,10,10,10" Height="auto" BorderThickness="2" MaxHeight="580" Grid.Row="2" x:Name="listBoxobjS" VerticalContentAlignment="Top" HorizontalContentAlignment="Center">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Margin="5" BorderBrush="{ThemeResource ApplicationHeaderForegroundThemeBrush}" BorderThickness="1" Background="{ThemeResource ButtonBackgroundThemeBrush}">
<StackPanel Width="125" Orientation="Horizontal" Grid.Row="1">
<TextBlock TextAlignment="Left" HorizontalAlignment="Left" Width="70" Height="80" x:Name="LbS" Text="{Binding Number}" TextWrapping="Wrap" FontSize="48" Foreground="{ThemeResource ButtonForegroundThemeBrush}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
When I navigate to this page I can select the preselected time (minutes and seconds) using listBoxobjM.SelectedIndex = i; in the following code. I can scroll manually to this Item and see it is selected.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.navigationHelper.OnNavigatedTo(e);
string parameter = e.Parameter as string;
string[] parts = parameter.Split(';');
id = int.Parse(parts[0]);
....
DatabaseHelper fetch = new DatabaseHelper();
TeamType team = fetch.GetTeamType(id);
for (int i = 0; i < 60; i++)
{
if (i == team.PlayTime.Minutes)
{
listBoxobjM.SelectedIndex = i;
listBoxobjM.ScrollIntoView(listBoxobjM.SelectedIndex);
}
if (i == team.PlayTime.Seconds)
{
listBoxobjS.SelectedIndex = i;
listBoxobjS.ScrollIntoView(listBoxobjS.SelectedIndex);
}
}
}
I want the Listbox automatically to scroll to the SelectedIndex, but instead the Listbox shows the first Items on top. How can I take care theListBox scrolls to the SelectedIndex?

ListBox.ScrollIntoView() takes an item that's in the ListBox, not an index. (MSDN documentation) So instead of
listBoxobjM.ScrollIntoView(listBoxobjM.SelectedIndex);
try
listBoxobjM.ScrollIntoView(listBoxobjM.SelectedItem);
instead.

Eventually I found the solution myself via an other Stack Overflow question. Here they also had problems with the ListView because it was filled with a delay. Using a await Task.Delay (see code) the problem is solved. I thank everybody for his contribution.
for (int i = 0; i < 60; i++)
{
if (i == team.PlayTime.Minutes)
{
listBoxobjM.SelectedIndex = i;
await Task.Delay(1000);
listBoxobjM.ScrollIntoView(listBoxobjM.SelectedItem);
}
if (i == team.PlayTime.Seconds)
{
listBoxobjS.SelectedIndex = i;
await Task.Delay(1000);
listBoxobjS.ScrollIntoView(listBoxobjS.SelectedItem);
}
}

Related

WPF UniformGrid dynamic content

I have a uniformgrid which i want to dyanmically show contents/view.
It can show either 1, 2, 4, or 6 contents. I set my uniformgrid row, col binding, and the content visibility binding.
This does NOT work in the case of views/contents,
but it DOES WORK in the case for rectangles. Why is that?
How do i modify it to work with views/contents.
Sample MainWindow.xaml code.....
<StackPanel>
<ComboBox HorizontalAlignment="Left" Width="50" SelectedIndex="{Binding SelectedIndex}">
<ComboBoxItem IsSelected="True" Content="1" />
<ComboBoxItem Content="2" />
<ComboBoxItem Content="4" />
<ComboBoxItem Content="6" />
</ComboBox>
<!-- NOT CORRECT, SHOWS 6 ITEMS ALWAYS -->
<UniformGrid Rows="{Binding ScreenRows}" Columns="{Binding ScreenCols}">
<local:ScreenView Grid.Row="0" Grid.Column="0" Visibility="{Binding VisibleScreen[0]}" />
<local:ScreenView Grid.Row="0" Grid.Column="1" Visibility="{Binding VisibleScreen[1]}" />
<local:ScreenView Grid.Row="0" Grid.Column="2" Visibility="{Binding VisibleScreen[2]}" />
<local:ScreenView Grid.Row="1" Grid.Column="0" Visibility="{Binding VisibleScreen[3]}" />
<local:ScreenView Grid.Row="1" Grid.Column="1" Visibility="{Binding VisibleScreen[4]}" />
<local:ScreenView Grid.Row="1" Grid.Column="2" Visibility="{Binding VisibleScreen[5]}" />
</UniformGrid>
<!-- OK, SHOWS 1,2,4, or 6 RECT DEPENDING ON SelectedIndex -->
<UniformGrid Rows="{Binding ScreenRows}" Columns="{Binding ScreenCols}">
<Rectangle Width="20" Height="20" Grid.Row="0" Grid.Column="0" Fill="Red" Visibility="{Binding VisibleScreen[0]}" />
<Rectangle Width="20" Height="20" Grid.Row="0" Grid.Column="1" Fill="Orange" Visibility="{Binding VisibleScreen[1]}" />
<Rectangle Width="20" Height="20" Grid.Row="0" Grid.Column="2" Fill="Yellow" Visibility="{Binding VisibleScreen[2]}" />
<Rectangle Width="20" Height="20" Grid.Row="1" Grid.Column="0" Fill="Green" Visibility="{Binding VisibleScreen[3]}" />
<Rectangle Width="20" Height="20" Grid.Row="1" Grid.Column="1" Fill="Blue" Visibility="{Binding VisibleScreen[4]}" />
<Rectangle Width="20" Height="20" Grid.Row="1" Grid.Column="2" Fill="Violet" Visibility="{Binding VisibleScreen[5]}" />
</UniformGrid>
</StackPanel>
Basically, i have a combobox. If I select 1, my ViewModel will dynamically change rows=1, cols=1, with 1st content Visible, and others collapse. It works in the case for Rectangles, but NOT views. Why is that? How to fix it so that it works for views?
Anyone curious, here is the code (Prism MVVM) in MainWindowViewModel
class MainWindowViewModel : BindableBase
{
private const int SCREEN_MAX = 6;
private int screenRows = 1;
public int ScreenRows
{
get { return screenRows; }
set { SetProperty(ref screenRows, value); }
}
private int screenCols = 1;
public int ScreenCols
{
get { return screenCols; }
set { SetProperty(ref screenCols, value); }
}
private Visibility[] visibleScreen = new Visibility[SCREEN_MAX];
public Visibility[] VisibleScreen
{
get { return visibleScreen; }
set { SetProperty(ref visibleScreen, value); }
}
private int selectedIndex;
public int SelectedIndex
{
get { return selectedIndex; }
set
{
SetProperty(ref selectedIndex, value);
ChangeScreen(selectedIndex);
}
}
private void ShowScreens(int num_screens)
{
// make all collapse
for (int i = 0; i < SCREEN_MAX; i++)
VisibleScreen[i] = Visibility.Collapsed;
// show only X num screens
for (int i = 0; i < num_screens; i++)
VisibleScreen[i] = Visibility.Visible;
RaisePropertyChanged("VisibleScreen");
}
public void ChangeScreen(int idx)
{
switch (idx)
{
case 0: ScreenRows = 1; ScreenCols = 1; ShowScreens(1); break;
case 1: ScreenRows = 1; ScreenCols = 2; ShowScreens(2); break;
case 2: ScreenRows = 2; ScreenCols = 2; ShowScreens(4); break;
case 3: ScreenRows = 2; ScreenCols = 3; ShowScreens(6); break;
}
}
}
The ScreenView.xaml
<UserControl...>
<!-- SOME HOW IT IS THIS DATACONTEXT CODE MESS UP THE UI -->
<UserControl.DataContext>
<local:ScreenViewModel x:Name="vm"/>
</UserControl.DataContext>
<StackPanel>
<TextBlock>TEST</TextBlock>
</StackPanel>
</UserControl>
Sample Output
As you can see from sample output, my combo selection is 1, so it should display 1 TEST, while 1 square is showing which is correct. But why should it show me 6 TEST? How to make it display 1 TEST?
Here's a corect output
Thanks!
Initial value of selectedIndex is 0 (default value of int field). But content of VisibleScreen array is not matching selectedIndex - you need to call ChangeScreen during initialization, e.g. like this:
public MainWindowViewModel()
{
SelectedIndex = 0;
}
Btw,Grid.Row and Grid.Column have no effect in UniformGrid. UniformGrid arranges items in the order they are added
Don't set DataContext inside UserControls.
instead of Visibility[] create collection of ScreenViewModel of in MainWindowViewModel (ObservableCollection<ScreenViewModel>).
Add bool IsVisible property in ScreenViewModel.
Change ShowScreens method like this:
private void ShowScreens(int num_screens)
{
for (int i = 0; i < SCREEN_MAX; i++)
VisibleScreen[i].IsVisible = i < num_screens ? Visibility.Visible : Visibility.Collapsed;
}
Change the view:
<ItemsControl ItemsSource="{Binding VisibleScreen}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding ScreenRows}" Columns="{Binding ScreenCols}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<local:ScreenView Visibility="{Binding IsVisible}"/>
</ItemsControl.ItemTemplate>
</ItemsControl>
ItemTemplate will create a local:ScreenView for each item in VisibleScreen collection AND assign it to DataContext of local:ScreenView

How Can I Access to The Controls in DataTemplate in ListBox in WPF

I have a ListBox including an ItemTemplate with a StackPanel. I want to access that stackpanel and change its visibility.
(Change it's visibility to collapsed when I click mouseleftbutton "closeAll")
I can do that with FindDescendantByName Method but it works for only listbox items on screen (Only first 10 items) but when I am scrolling down, I see that this is not working for other listbox items.
I think that errors occurs because of VisualTreeHelper. What can I use instead of VisualTreeHelper?
Thanks..
XAML CODE
<ListBox x:Name="listBoxEditPast" SelectionMode="Single" Margin="0" Background="#272B34" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderThickness="4,0,0,0" Margin="2,0,0,0" Height="29" Background="#2E323B" Width="1050" BorderBrush="#1373A9" MouseLeftButtonDown="Border_MouseLeftButtonDown">
<DockPanel Name="dockPanelPast" Margin="0,4,0,0">
<Image Name="imgArrow" Source="images/down-arrow.png" HorizontalAlignment="Left" Width="20" Height="18"/>
<TextBlock Text="{Binding CreateDate}" Name="txtTarih" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
<TextBlock Text="{Binding SarjNo}" Name="txtSarjNo" Foreground="#FF9CA518" HorizontalAlignment="Stretch" VerticalAlignment="Center" FontSize="16" Margin="50,0,0,0" Width="90"/>
<TextBlock Text="{Binding Adi}" Name="txtReceteAdi" Foreground="#FF26A053" VerticalAlignment="Center" FontSize="16" Margin="40,0,0,0" HorizontalAlignment="Stretch"/>
<Button Content="Detaylar" Style="{StaticResource BlueButton}" HorizontalAlignment="Right" VerticalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" DockPanel.Dock="Right"/>
</DockPanel>
</Border>
<StackPanel Grid.Row="1" Name="stackPanelDetay" Tag="{Binding ID}">
<DockPanel>
<TextBlock Text="Sipariş No" Foreground="#D9480F" VerticalAlignment="Center" />
<TextBlock Text="Parça" Foreground="#AF0FD9" VerticalAlignment="Center" Margin="50,0,0,0" Width="200" />
<TextBlock Text="Malzeme" Foreground="White" VerticalAlignment="Center" Margin="150,0,0,0" Width="90"/>
<TextBlock Text="Müşteri" Foreground="#AF0FD9" VerticalAlignment="Center" Margin="70,0,0,0" />
</DockPanel>
<DockPanel>
<TextBlock Text="{Binding ID}" Foreground="White" VerticalAlignment="Center" Width="100"/>
<TextBlock Text="{Binding ParcaKoduAdi}" Foreground="White" VerticalAlignment="Center" Margin="5,0,0,0" Width="200" />
<TextBlock Text="{Binding Malzeme}" Foreground="White" VerticalAlignment="Center" Margin="152,0,0,0" Width="90" />
<TextBlock Text="{Binding MusteriKoduAdi}" Foreground="White" VerticalAlignment="Center" Margin="70,0,0,0" />
</DockPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C# CODE
public static class FrameworkElementExtensions
{
public static FrameworkElement FindDescendantByName(this FrameworkElement element, string name)
{
if (element == null || string.IsNullOrWhiteSpace(name)) { return null; }
if (name.Equals(element.Name, StringComparison.OrdinalIgnoreCase))
{
return element;
}
var childCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childCount; i++)
{
var result = (VisualTreeHelper.GetChild(element, i) as FrameworkElement).FindDescendantByName(name);
if (result != null) { return result; }
}
return null;
}
}
private void closeAll_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// StackPanel panel = LayoutHelper.FindElement(listBoxEditPast, n => n.GetType() == typeof(StackPanel)) as StackPanel;
for (int i = 0; i < listBoxEditPast.Items.Count; i++)
{
var element = listBoxEditPast.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
if (element != null)
{
var sp = element.FindDescendantByName("stackPanelDetay") as StackPanel;
if (sp != null)
{
sp.Visibility = Visibility.Collapsed;
}
}
}
}
noting to do with the visualtreehelper, this is because the list is virtualized, so only the first ten items are created and then replaced by the ten next....and you loose your modifications
you must not work with the element in the data template by code
iterate through your data to set a boolean to true/false for all and then change the stack and bind the visibility to this boolean
<StackPanel Grid.Row="1" Name="stackPanelDetay" Visibility="{Binding myBoolean, Converter=BoolToVisibility}">

How to make a StackPanel visible only when the DragCompleted + Condition is matched

I am working on a UWP app in which my requirement is to show a StackPanel only when Drag is completed in a grid view and condition is met too.
I am making a drag and re-order like game. I want the StackPanel (Containing Result and Buttons) appear when not only a single drag is completed but all the items are sorted too.
I have got everything else working fine. Only StackPanel is problem. It appears just after on drag completed whether the condition is met or not.
Following are the screenshots, code and more briefing !
ScreenShot
XAML for GridView
<GridView Name="GameDisplay"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="1"
CanDrag="True"
CanDragItems="True"
CanReorderItems="True"
SelectionMode="Single"
AllowDrop="True"
DragItemsCompleted="GameDisplay_DragItemsCompleted">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="60"
Height="60"
Background="Black">
<TextBlock Text="{Binding}"
FontFamily="BriLliant"
FontSize="48"
FontWeight="light"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal"
MaximumRowsOrColumns="10"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
XAML For StackPanel
<StackPanel Grid.Row="1" Grid.Column="1" Name="GameFinished" Background="#9900ff" Width="800" HorizontalAlignment="Center" VerticalAlignment="Center" Height="auto">
<Grid Name="InnerGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Name="BtnsContainer" Grid.Column="1" Width="auto" Height="auto" Margin="0 10 0 0">
<Grid Name="BtnsGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="txtBannerType"
Width="auto"
Height="auto"
Grid.Row="0"
Text="Well Done !"
FontSize="72"
FontWeight="Bold"
FontFamily="BriLliant"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock Name="txtTimeSpent"
Width="200"
Height="auto"
Grid.Row="1"
Text=""
FontSize="48"
FontWeight="Light"
FontFamily="BriLliant"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock Name="txtScore"
Width="200"
Height="auto"
Grid.Row="2"
Text="Score : 0"
FontSize="48"
FontWeight="Light"
FontFamily="BriLliant"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock Name="txtBestScore"
Width="200"
Height="auto"
Grid.Row="3"
Text="Best Score : 0"
FontSize="48"
FontWeight="Light"
FontFamily="BriLliant"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<Button Name="RestartGame"
Width="200"
Height="70"
Grid.Row="4"
Background="Black"
Content="Restart"
FontSize="48"
FontWeight="Bold"
FontFamily="BriLliant"
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0 20 0 0"
Click="RestartGame_Click"/>
<Button Name="MainMenu"
Width="200"
Height="70"
Grid.Row="5"
Background="Black"
Content="Main Menu"
FontSize="48"
FontWeight="Bold"
FontFamily="BriLliant"
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0 20 0 0"
Click="MainMenu_Click"/>
</Grid>
</StackPanel>
</Grid>
</StackPanel>
C# Events
private void Page_Loaded(object sender, RoutedEventArgs e)
{
lib.New(GameDisplay);//For Starting New Game
}
private void GameDisplay_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
lib.completed(GameDisplay);//When the tiles are re-ordered
}
Class that is handling BackEnd
class Library
{
//BackEnd for Math Game
private const int size = 5;
private const int total = size * size;
private DateTime timer;
private ObservableCollection<int> items = new ObservableCollection<int>();
private Random random = new Random((int)DateTime.Now.Ticks);
public void show(string content, string title)
{
IAsyncOperation<IUICommand> command = new MessageDialog(content, title).ShowAsync();
}
private List<int> select(int start, int finish, int total)
{
int number;
List<int> numbers = new List<int>();
while ((numbers.Count < total))
{
number = random.Next(start, finish + 1);
if ((!numbers.Contains(number)) || (numbers.Count < 1))
{
numbers.Add(number);
}
}
return numbers;
}
private bool winner()
{
return items.OrderBy(o => o).ToList().SequenceEqual(items.ToList());
}
private void layout(ref GridView grid)
{
timer = DateTime.UtcNow;
grid.IsEnabled = true;
grid.ItemsSource = null;
items = new ObservableCollection<int>();
List<int> numbers = select(1, total, total);
int index = 0;
while (index < numbers.Count)
{
items.Add(numbers[index]);
index++;
}
grid.ItemsSource = items;
}
public void New(GridView grid)
{
layout(ref grid);
}
public void completed(GridView grid)
{
string congo = "";
if (winner())
{
TimeSpan duration = (DateTime.UtcNow - timer).Duration();
congo = string.Format("Time: {0}:{1}:{2}", duration.Hours, duration.Minutes, duration.Seconds);
grid.IsEnabled = false;
}
}
}
Above is the game screen. When I drag and re-order a tile an event is fired in which a method runs until all the tiles are dragged and reordered according to the index of list that is containing all these numbers.
StackPanel only waits for one Drag. Is there any way to add StackPanel into the condition that checks for list sort?? Something like Data-Binding??
If you find anything missing, wrong or the question is already solved before. Please let me know explicitly !
Thanks...
Since you have already use winner() method to judge whether the game is ended and also invoke this in GameDisplay_DragItemsCompleted method. So actually the condition is already met in your completed method (every drag completed to judge whether game is over ). We just need to set the Visibility property of StackPanel to visible.
Update complete method as follows:
public void completed(GridView grid,StackPanel stackpanel)
{
string congo = "";
if (winner())
{
TimeSpan duration = (DateTime.UtcNow - timer).Duration();
congo = string.Format("Time: {0}:{1}:{2}", duration.Hours, duration.Minutes, duration.Seconds);
grid.IsEnabled = false;
stackpanel.Visibility = Visibility.Visible;
}
}
Update GameDisplay_DragItemsCompleted method as follows:
private void GameDisplay_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
lib.completed(GameDisplay,GameFinished);//When the tiles are re-ordered
}
Pay attention that in default the StackPanel should be collapsed. Update XAML code about StackPanel as follows:
<StackPanel Grid.Row="1" Grid.Column="1" Name="GameFinished" Background="#9900ff" Width="800" HorizontalAlignment="Center" VerticalAlignment="Center" Height="auto" Visibility="Collapsed">
And you can reset the state for StackPanel and GridView when game restart. Code as follows:
private void RestartGame_Click(object sender, RoutedEventArgs e)
{
GameDisplay.IsEnabled = true;
GameFinished.Visibility = Visibility.Collapsed;
}
And the result:
The problem is, by this code in winner function
return items.OrderBy(o => o).ToList().SequenceEqual(items.ToList()); }
You just check if list items is equal to list items. It will always return true.
According to this msdn document orderBy orders the list itself does not return a copy of it.
If you are going to use this method, create another list to compare with curent list and keep that list sorted.
You may create two bool flags and check them in both methods OnDragComplete and OnChangeCondition like this:
private void OnDragComplete()
{
_isDragCompleted = true;
if (_isDragCompleted && _isConditionChanged)
{
CollapseStackPanel();
}
}
private void OnChangeCondition()
{
_isConditionChanged = true;
if (_isDragCompleted && _isConditionChanged)
{
CollapseStackPanel();
}
}
private void CollapseStackPanel()
{
_isDragCompleted = false;
_isConditionChanged = false;
StackPanel.Visibility = Visibility.Collapsed;
}

Gidview item not updating

My page having city listing and searching functionality. When page first time loading, it is showing all record.
When user enter search Text and tap on search button. it is not updating gridview list. I check by placing debug point my code is working fine. but gridview list not showing updated list.
Following is my code.
XAML:
<StackPanel VerticalAlignment="Top">
<TextBlock Style="{StaticResource ListTextBlockStyle}" FontWeight="Bold" Text="{Binding Description}" />
<TextBlock Style="{StaticResource ListTextBlockStyle}" Text="{Binding Description}" />
</StackPanel>
<TextBlock Style="{StaticResource DistanceTextBlockStyle}" TextWrapping="Wrap" Text="XXXm" />
<Image Width="10" VerticalAlignment="Center" Source="ms-appx:///Assets/arrowright.png"/>
</StackPanel>
<Rectangle Height="1" Stroke="Black" StrokeThickness="0.5" Margin="0,3,0,0" />
</StackPanel>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
<Border Grid.Row="1" Height="60" VerticalAlignment="Bottom">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox x:Name="txtSearch" Margin="0,0,10,0" TextWrapping="Wrap" PlaceholderText="Search" VerticalAlignment="Center" Width="300" Height="50" />
<Image x:Name="imgSearch" Height="50" Width="50" Source="ms-appx:///Assets/btnSearch.png" Tapped="imgSearch_Tapped"/>
</StackPanel>
</StackPanel>
</Border>
C#:
public List<City> gs_CityList = new List<City>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
fillCityList();
}
private void fillCityList()
{
gs_CityList.Clear();
if (string.IsNullOrEmpty(CityListManagerManager.ms_searchTxt))
{
foreach (City foCity in CityListManagerManager.ms_CityList)
{
City loCity = new City();
loCity.Description = foCity.Description.Replace("\n", "").Substring(0, 15) + "...";
loCity.longtitude = foCity.longtitude;
loCity.latitude = foCity.latitude;
loCity.Location = foCity.Location;
gs_CityList.Add(loCity);
}
}
else
{
foreach (City foCity in CityListManagerManager.ms_CityList.Where(p => p.Description.ToLower().Contains(CityListManagerManager.ms_searchTxt.ToLower())))
{
City loCity = new City();
loCity.Description = foCity.Description.Replace("\n", "").Substring(0, 15) + "...";
loCity.longtitude = foCity.longtitude;
loCity.latitude = foCity.latitude;
loCity.Location = foCity.Location;
gs_CityList.Add(loAEDPin);
}
txtSearch.Text = CityListManagerManager.ms_searchTxt;
}
if (gs_CityList.Count > 0)
{
gvCityList.DataContext = gs_CityList; // --- This binding data to gridview
}
else
MessageBox("City not found...!");
}
private void imgSearch_Tapped(object sender, TappedRoutedEventArgs e)
{
CityListManagerManager.ms_searchTxt = txtSearch.Text.Trim();
fillCityList();
}
You should try changing your List<City> into an ObservableCollection<City>, as this allows the binding to get notified about changes.
You could also think about using a CollectionViewSource as data source for the GridView and modifying its Filter property instead of re-filling the collection.

Windows phone 8 ListBox becomes empty after loading a lot of data

In my WP8 application I have a listbox which performs Lazy load. All is working fine except one thing. Sometimes after scrolling up or down, even when data is the same, my listbox becomes empty. I analized the used memory using "Windows phone application analyses" and got the maximum used memory 100MB. So there is no problem with memory. Also aplication does not crash after becoming listbox empty. Do you have any ideas why these happen?
Here is my XAML:
<ListBox Name="lbCollections" LayoutUpdated="lbCollectins_LayoutUpdated">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="White" Margin="20">
<Grid Margin="15,5,15,5">
<Grid.RowDefinitions>
<RowDefinition Height="45"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Text="{Binding CategoryName}" Foreground="Black" Style="{StaticResource EmptyListHeaderStyle}"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding CreatedOn, StringFormat='{}{0:MM dd, yyyy}'}" Foreground="Gray" Style="{StaticResource PhoneTextSmallStyle}"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding PhotosCountTxt}" Foreground="Gray" Style="{StaticResource PhoneTextSmallStyle}"></TextBlock>
</Grid>
<Grid Height="150">
<Grid.Resources>
<conv:ImageConverter x:Key="ImageConverter" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Name="img1" Source="{Binding Photos, Converter={StaticResource ImageConverter}, ConverterParameter=0}" Width="150" Height="150" Margin="5"/>
<Image Grid.Column="1" Name="img2" Source="{Binding Photos, Converter={StaticResource ImageConverter}, ConverterParameter=1}" Width="150" Height="150" Margin="5"></Image>
<Image Grid.Column="2" Name="img3" Source="{Binding Photos, Converter={StaticResource ImageConverter}, ConverterParameter=2}" Width="150" Height="150" Margin="5"></Image>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is the code behind:
private async void LoadContent()
{
if (loadingProgress)
{
return;
}
else
{
try
{
loadingProgress = true;
CollectionResponse collectionResp = await CollectionService.IterateAsync(MapPoint, "", dtStart, dtEnd, filterCategoryId, loadedCollectionsCount, collectionsCountToLoadAtOnce, 4, (int)TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes, AppSettings.Invisible, AppSettings.Token);
if (collectionResp.Collections.Count == 0)
{
endOfList = true;
}
else
{
loadedCollectionsCount += collectionResp.Collections.Count;
if (!(lbCollections.ItemsSource is List<CollectionModel>))
{
lbCollections.ItemsSource = new List<CollectionModel>();
}
(lbCollections.ItemsSource as List<CollectionModel>).AddRange(collectionResp.Collections);
//lbCollections.ItemsSource = collectionResp.Collections;
}
}
catch
{
}
finally
{
loadingProgress = false;
}
}
}
private void lbCollectins_LayoutUpdated(object sender, EventArgs e)
{
ScrollBar scrollBar = FindChildOfType<ScrollBar>(lbCollections).Where(sb=>sb.Orientation == System.Windows.Controls.Orientation.Vertical).FirstOrDefault();
if (scrollBar != null)
{
bool endOfScroll = scrollBar.Maximum > 0 && scrollBar.Value > 0 && scrollBar.Maximum - scrollBar.Value < 10;
if (!endOfList && endOfScroll)
{
LoadContent();
}
}
}
static List<T> FindChildOfType<T>(DependencyObject root) where T : class
{
List<T> foundObjects = new List<T>();
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);
while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; i >= 0; i--)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
foundObjects.Add(typedChild);
}
queue.Enqueue(child);
}
}
return foundObjects;
}
Two things to do.
Take a look at this blog about why the ListBox goes blank. Most likely the problem is the images you are showing. You can easily fix by doing the following
Start using the LongListSelector for WP8 (not the WP Toolkit version!) It is designed for fast scrolling even with images

Categories

Resources