I'm trying to implemented infinite scrolling in my listview.
The approach is to get the scroll bar within the listview and hook an event handler to it's scroll event.
<CollectionViewSource x:Key="PaginatedData"
IsSourceGrouped="True"
ItemsPath="CommentaryList"
Source="{Binding paginatedCommentary}"/>
<ListView x:Name="commentaryListView"
Loaded="commentaryListView_Loaded"
ItemTemplate="{StaticResource CommentaryListTemplate}"
ItemsSource="{Binding Source={StaticResource PaginatedData}}"/>
private void commentaryListView_Loaded(object sender, RoutedEventArgs e)
{
var scrollViewer = commentaryListView.GetFirstDescendantOfType<ScrollViewer>();
var scrollbars = new List<ScrollBar>(scrollViewer.GetDescendantsOfType<ScrollBar>());
var verticalBar = scrollbars.FirstOrDefault(x => x.Orientation == Orientation.Vertical);
if (verticalBar != null)
verticalBar.Scroll += BarScroll;
}
private void BarScroll(object sender, ScrollEventArgs e)
{
if (e.ScrollEventType != ScrollEventType.EndScroll) return;
var bar = sender as ScrollBar;
if (bar == null) return;
if (e.NewValue >= bar.Maximum)
{
datacontext.pageCommentaryItems();
}
}
Can't seem to figure out what I'm doing here, but it's never hitting the BarScroll event handler.
Appreciate your help. Thank you :)
I recommend you use the ListView's ViewChanged event directly:
private void OnListViewLoaded(object sender, RoutedEventArgs e)
{
var listview = sender as ListViewBase;
if (listview != null)
{
// Attach to the view changed event
_scrollViewer = listview.GetFirstDescendantOfType<ScrollViewer>();
if (_scrollViewer != null)
{
_scrollViewer.ViewChanged += OnViewChanged;
}
}
}
private void OnViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
// If scrollviewer is scrolled down at least 90%
if (_scrollViewer.VerticalOffset > Math.Max(_scrollViewer.ScrollableHeight * 0.9, _scrollViewer.ScrollableHeight - 150))
{
// Execute whatever you want
}
}
A much simpler solution would be to create an observable collection that implements the ISupportIncrementalLoading interface and bind it to your ListView. This will make the ListView do incremental scrolling without any need to implement it yourself. See https://marcominerva.wordpress.com/2013/05/22/implementing-the-isupportincrementalloading-interface-in-a-window-store-app/
Related
I am trying to make a small music player for windows phone. I have added a slider functionality in the player. The slider works fine as the music plays. But I want to change the media according to how much i drag the slider, but cannot find any relevant event for it. I have tried value changed but it does not help. Also I tried Thumb.Dragstarted event but my visual studio gives an error.. this is the code so far:
XAML:
<Slider AllowDrop="True" x:Name="sld1" Thumb.DragStarted="sld1_DragStarted" HorizontalAlignment="Left" Margin="58,213,0,0" VerticalAlignment="Top" Width="351" ValueChanged="sld1_ValueChanged"/>
<MediaElement x:Name="bleep" Source="abcd.wav" AutoPlay="False" Visibility="Collapsed" MediaEnded="bleep_MediaEnded"/>
C#:
public Page1()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += timer_Tick;
timer.Start();
}
private bool userIsDraggingSlider = false;
private void timer_Tick(object sender, EventArgs e)
{
if ((bleep.Source != null) && (bleep.NaturalDuration.HasTimeSpan) && (!userIsDraggingSlider))
{
sld1.Minimum = 0;
sld1.Maximum = bleep.NaturalDuration.TimeSpan.TotalSeconds;
sld1.Value = bleep.Position.TotalSeconds;
}
}
private void sld1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
tm_passed.Text = TimeSpan.FromSeconds(sld1.Value).ToString(#"mm\:ss");
}
private void sld1_DragStarted(object sender, DragStartedEventArgs e)
{
userIsDraggingSlider = true;
}
private void sld1_DragCompleted(object sender, DragCompletedEventArgs e)
{
userIsDraggingSlider = false;
bleep.Position = TimeSpan.FromSeconds(sld1.Value);
}
But since the DragCompleted and DragStarted events are not working I cannot provide the drag functionality to the slider.
What I identified from the Thumb class is that, you can't simply add Thumb.DragStarted="sld1_DragStarted within your Slider. You'll be able to add that kind of event only for Thumb control. Refer the bottom of the article for sample code.
what would be the steps to add timer to change selected item's image in listpicker. Any suggestions? FYI, have never used ListPicker before. So i am finding it kind of hard to understand where to start and what to do.
You will need an ObservableCollection of your ImageSources and a DispatcherTimer to fire the events every TimeSpan of your choosing.
Here's some code to help you get started. You can modify it to do exactly what you want. It basically contains a ListPicker that has a collection of images as its ItemTemplate. Every one second the DispatchTimer fires and switches the selectedItem's Image between the 2 default images that are created in about every single WP8.0 application.
Make it a habit to use ObervableCollection when you want to display something to the user instead of a List, it will make your WP8 development life a lot easier.
XAML
<toolkit:ListPicker x:Name="my_listpicker" SelectionChanged="my_listpicker_SelectionChanged_1" Background="Black">
<toolkit:ListPicker.HeaderTemplate>
<DataTemplate/>
</toolkit:ListPicker.HeaderTemplate>
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel Background="Black">
<Image Source="{Binding ImageSource}" Height="200"></Image>
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
</toolkit:ListPicker>
C# Namespaces
using System.ComponentModel; // ObservableCollection
using System.Collections.ObjectModel; // INotifyPropertyChanged
using System.Windows.Threading; // Dispatch Timer
C# Model of your Images (pretty basic, but pay attention to the INotifyPropertyChanged
public class MyBindingImage : INotifyPropertyChanged
{
public MyBindingImage() { }
public MyBindingImage(string source)
{
this.ImageSource = source;
}
// Create the OnPropertyChanged method to raise the event
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
string image_source;
public String ImageSource {
get { return image_source; }
set
{
image_source = value;
OnPropertyChanged("ImageSource");
}
}
}
C# (Create the Timer and ObservableCollection and Set the ItemSource)
DispatcherTimer timer;
// Constructor
public MainPage()
{
// create our dispatch timer
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(2000);
timer.Tick += OnTimerTick;
InitializeComponent();
// create our list picker elements
ObservableCollection<MyBindingImage> my_image_list = new ObservableCollection<MyBindingImage>();
my_image_list.Add(new MyBindingImage("Assets/ApplicationIcon.png"));
my_image_list.Add(new MyBindingImage("Assets/AlignmentGrid.png"));
my_listpicker.ItemsSource = my_image_list;
}
C# Events (For the Timer & ListPicker SelectionChange)
// each time the selection has changd: stop the timer, then start it again
private void my_listpicker_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
if (timer != null)
{
timer.Stop();
timer.Start();
}
}
// if the timer is on, cycle the images of the selected item
private void OnTimerTick(object sender, EventArgs e)
{
try
{
MyBindingImage item = (MyBindingImage) my_listpicker.SelectedItem;
// cycle the selected image between to different images
if (item.ImageSource == "Assets/AlignmentGrid.png")
{
item.ImageSource = "Assets/ApplicationIcon.png";
}
else
{
item.ImageSource = "Assets/AlignmentGrid.png";
}
}
catch (Exception ex)
{
string error_message = ex.Message;
}
}
[APPLICATION SCREENSHOT]
As described i input a datepicker in my xaml file
when i run the page ,datepicker just show like this:
then I have to tap the datepicker to enter the select page like this :
Now
I need to directly open the fullscreen datepicker select page when I click a button
the address give a way that I can just Navigate to the select page,
but I don't know how ?
I'm the poster.
i find a solution myself
Override DatePicker class with our custom DatePickerCustom class. Create new class "DatePickerCustom.cs"
public class DatePickerCustom : DatePicker
{
public void ClickTemplateButton()
{
Button btn = (GetTemplateChild("DateTimeButton") as Button);
ButtonAutomationPeer peer = new ButtonAutomationPeer(btn);
IInvokeProvider provider = (peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider);
provider.Invoke();
}
}
then in the mainpage.xaml.cs
private DatePickerCustom datePicker;
// Constructor
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
// create datePicker programmatically
if (this.datePicker == null)
{
this.datePicker = new DatePickerCustom();
this.datePicker.IsTabStop = false;
this.datePicker.MaxHeight = 0;
this.datePicker.ValueChanged += new EventHandler<DateTimeValueChangedEventArgs>(datePicker_ValueChanged);
LayoutRoot.Children.Add(this.datePicker);
}
}
void datePicker_ValueChanged(object sender, DateTimeValueChangedEventArgs e)
{
// now we may use got value from datePicker
TextBlock1.Text = this.datePicker.ValueString;
}
so that when do an action like tap or click, the fullscreen datepicker page will be shown
private void button1_Click(object sender, RoutedEventArgs e)
{
this.datePicker.ClickTemplateButton();
}
ps: timepicker can also do the same thing
ps2:here is the details
#Mario Galván
hope it help u
How I can get behavior of form in windows Phone like Contacts >> New contacts >> Name. In this page it have many textboxes in scrollviewer. When user taps on any textbox and its get focus then the page scrolls up and header remains constant and SIP keyboard shown.
This is a my example but not it works
https://app.box.com/s/lxxcmxp8ckuottrweg52
Why?
thank you
I have modified the above code that works fine for as below.
public double OldHeight;
private TranslateTransform _translateTransform;
#region TranslateY dependency property
public static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register(
"TranslateYProperty", typeof(double), typeof(Chat), new PropertyMetadata(default(double), PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var chat = o as Chat;
#if DEBUG
Debug.WriteLine("New value:" + e.NewValue);
Debug.WriteLine("Old value:" + e.OldValue);
#endif
if (chat != null)
{
chat.UpdateTopMargin((double)e.NewValue);
}
}
public double TranslateY
{
get { return (double)GetValue(TranslateYProperty); }
set { SetValue(TranslateYProperty, value); }
}
#endregion
private void ChatPage_OnLoaded(object sender, RoutedEventArgs e)
{
var transform = ((Application.Current).RootVisual).RenderTransform as TransformGroup;
if (transform != null)
{
_translateTransform = transform.Children.OfType<TranslateTransform>().FirstOrDefault();
if (_translateTransform != null)
{
var binding = new Binding("Y")
{
Source = _translateTransform
};
BindingOperations.SetBinding(this, TranslateYProperty, binding);
}
}
}
private void UpdateTopMargin(double translateY)
{
LayoutRoot.Margin = new Thickness(0, -translateY, 0, 0);
}
Thanks
First, name your scroll viewer ScrollViewer. After that add the GotFocus and LostFocus event handlers for each text box control on the page and write the following code inside:
private void txt_LostFocus(object sender, RoutedEventArgs routedEventArgs)
{
ScrollViewer.Height = _oldHeight;
}
void txt_GotFocus(object sender, RoutedEventArgs e)
{
var transform = ((Application.Current).RootVisual).RenderTransform as TransformGroup;
if (transform != null)
{
_translateTransform = transform.Children.OfType<TranslateTransform>().FirstOrDefault();
if (_translateTransform != null)
{
var binding = new Binding("Y")
{
Source = _translateTransform
};
BindingOperations.SetBinding(this, TranslateYProperty, binding);
}
}
var clipboardVisible = false;
try
{
clipboardVisible = Clipboard.ContainsText();
}
// ReSharper disable once EmptyGeneralCatchClause
catch
{
}
ScrollViewer.Height = _oldHeight - (clipboardVisible ? 407 : 338);
}
You will need to add the following dependency property to the page:
#region TranslateY dependency property
public static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register(
"TranslateYProperty", typeof(double), typeof(OrderContactPage), new PropertyMetadata(default(double), PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((OrderContactPage)o)._translateTransform.Y = 0;
}
public double TranslateY
{
get { return (double)GetValue(TranslateYProperty); }
set { SetValue(TranslateYProperty, value); }
}
#endregion
And also helper fields:
private double _oldHeight;
private TranslateTransform _translateTransform;
You also need to handle some events for your scroll viewer, add this to the page's constructor:
ScrollViewer.Loaded += ScrollViewerOnLoaded;
ScrollViewer.SizeChanged += ScrollViewer_OnSizeChanged;
Implement those event handlers:
private void ScrollViewerOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
ScrollViewer.Loaded -= ScrollViewerOnLoaded;
_oldHeight = ScrollViewer.ActualHeight;
}
private async void ScrollViewer_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
await ScrollToFocusedElement();
}
private async Task ScrollToFocusedElement()
{
await Task.Yield();
var focusedElement = FocusManager.GetFocusedElement() as PhoneTextBox;
if (focusedElement != null)
{
// http://stackoverflow.com/questions/1225318/how-can-i-make-the-silverlight-scrollviewer-scroll-to-show-a-child-control-with
var focusedVisualTransform = focusedElement.TransformToVisual(ScrollViewer);
var rectangle =
focusedVisualTransform.TransformBounds(
new Rect(new Point(focusedElement.Margin.Left, focusedElement.Margin.Top), focusedElement.RenderSize));
var offset = ScrollViewer.VerticalOffset + (rectangle.Bottom - ScrollViewer.ViewportHeight);
ScrollViewer.ScrollToVerticalOffset(offset);
}
}
Wow, there is a lot of code there. I am working on creating something reusable, but I am not there yet. Once I do it, I will publish it on NuGet.
Note that this only works in Portrait mode and will not work perfectly if you have the auto suggestion bar open. I didn't need to handle that in my app so I skipped it :)
Enjoy.
you can try this sample sample project
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0"
Background="#002080">
<TextBlock Text="PAGE HEADER" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<Grid Grid.Row="1" />
<TextBox Grid.Row="2"
Text=""
x:Name="messageBox"
Background="White" LostFocus="MessageBox_OnLostFocus" />
</Grid>
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private static double _newValue;
private static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register("TranslateY", typeof(double), typeof(MainPage), new PropertyMetadata(0d, OnRenderXPropertyChanged));
private double TranslateY
{
get { return (double)GetValue(TranslateYProperty); }
}
private static void OnRenderXPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((double)e.NewValue <= _newValue)
((MainPage)d).UpdateTopMargin((double)e.NewValue);
_newValue = (double)e.NewValue;
}
private void BindToKeyboardFocus()
{
var frame = Application.Current.RootVisual as PhoneApplicationFrame;
if (frame == null) return;
var group = frame.RenderTransform as TransformGroup;
if (#group == null) return;
var translate = #group.Children[0] as TranslateTransform;
var translateYBinding = new Binding("Y") { Source = translate };
SetBinding(TranslateYProperty, translateYBinding);
}
private void UpdateTopMargin(double translateY)
{
double prevTopMargin = LayoutRoot.Margin.Top;
LayoutRoot.Margin = new Thickness(0, -translateY, 0, 0);
}
void b_Hold(object sender, System.Windows.Input.GestureEventArgs e)
{
MessageBoxResult result = MessageBox.Show("A", "MessageBox Example", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
MessageBox.Show(" ....");
}
}
void b_Click(object sender, RoutedEventArgs e)
{
Button btnevent = (Button)sender;
for (int i = 0; i < (Application.Current as App).devices.Length; i++)
if (btnevent.Content.ToString() == (Application.Current as App).devices[i])
{
(Application.Current as App).selectedDevice = i;
NavigationService.Navigate(new Uri("/pages/Buttons.xaml", UriKind.Relative));
}
}
I am working on project and I need to define hold and click events to one button. the problem is click event always fired even i hold on or click the button .
in other words ,, can i disable click event when I hold on the buttons ?
Use tap instead of click in this style
private void Button_OnHold(object sender, GestureEventArgs e)
{
e.Handled = true;
// Your code goes here
}
private void Button_OnTap(object sender, GestureEventArgs e)
{
// Your code goes here
}
After you set Handled property to true click event will not handle your gesture.