Sorry if this is a dumb question. I am maintaining this crazy Windows Phone 8.1 RT dynamic app that I didn't write. It loads up a whole bunch of stuff to the DataContext. Things that aren't visible on the screen don't seem to get their DataContext. When I navigate away from the form the event fires. What do I need to do to fix that? Even when it scrolls into view it doesn't load. If I scoll up and click the back button I see the field populate before it goes to the previous page.
Edit - Here is some code:
<DataTemplate x:Key="com.somecompany.BarcodeboxRenderer">
<Grid HorizontalAlignment="Stretch" DataContext="{Binding Item1}">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Label}" HorizontalAlignment="Stretch" Style="{StaticResource labelstyle}" Grid.Row="0" />
<somecompany:BarcodeBox IsReadOnly="{Binding DisplayOnly}" somecompany:DynamicDataBindingPath.BindingPath="{Binding FieldId}" Grid.Row="1" />
</Grid>
</DataTemplate>
That calls this but only if it's visible:
public sealed class DynamicDataBindingPath:FrameworkElement
{
public static readonly DependencyProperty BindingPathProperty = DependencyProperty.RegisterAttached("BindingPath", typeof(string), typeof(DynamicDataBindingPath), new PropertyMetadata("", OnBindingPathPropertyChanged));
public static string GetBindingPath(FrameworkElement target)
{
try
{
return (string)target.GetValue(BindingPathProperty);
}
catch (Exception)
{
return string.Empty;
}
}
public static void SetBindingPath(FrameworkElement target, string value)
{
target.SetValue(BindingPathProperty, value);
target.Loaded += Target_Loaded;
}
private static void Target_Loaded(object sender, RoutedEventArgs e) {
var target = (FrameworkElement)sender;
if (target is ...) { ... }
else if (target is DatePicker)
{
int startingletterindex = value.IndexOf('.') + 1;
string pathtobindto = "obj." + Char.ToUpper(value[startingletterindex]) + value.Substring((startingletterindex + 1));
Binding newbind = new Binding();
newbind.Path = new PropertyPath(pathtobindto);
var contextsrc = findRealDataContext(target);
newbind.Source = contextsrc.DataContext;
newbind.Mode = BindingMode.TwoWay;
(target as DatePicker).SetBinding(DatePicker.DateProperty, newbind);
}
else if (...)
}
I turned of ListView Virtualization and it works now. I don't need it because there will never be more than a handful of rows.
Related
i'm currently creating a Metro Style Application and want to use the FlipView control to work like the tab control in WPF and winforms, please can any one help me ?
You would put FlipViewItems in the FlipView the same way you'd put TabItems in a TabControl. To add tabs - you could have a StackPanel with TextRadioButtonStyled RadioButtons that have their check states synchronized with the FlipView selection state. Alternatively you could have a heavily styled ListView for the headers bar.
i solved it by editing the flipviewitem template and making its view like the wanted tab page view. Then i added a button on the top of every item to activate it.
We don't have Tab Control in WP8.1 but we can customize using FlipView. Flip View has a property selected index so we can set which view we want.
Create a xaml page, for example MainPage.xaml
For Tab Header
<Border BorderThickness="0,0,0,1" BorderBrush="White" >
<Grid Grid.Row="0" Background="Black" x:Name="navigateHead" >
<TextBlock x:Name="appbarSports" Text="Sports" Tapped="appbarSports_Tapped" TextAlignment="Center" Width="80" Margin="0,34,320,7" />
<TextBlock x:Name="appbarCars" Text="Cars" Tapped="appbarCars_Tapped" Margin="160,34,160,7" TextAlignment="Center" />
<TextBlock x:Name="appbarHomes" Text="Homes" Tapped="appbarHomes_Tapped" Margin="80,34,240,7" TextAlignment="Center" />
<Image x:Name="imgLine0" Source="ms-appx:///Images/white.png" Width="80" Height="3" Stretch="Fill" Margin="0,55,320,1" ></Image>
<Image x:Name="imgLine1" Source="ms-appx:///Images/white.png" Width="80" Height="3" Stretch="Fill" Margin="81,55,239,1" Visibility="Collapsed" />
<Image x:Name="imgLine2" Source="ms-appx:///Images/white.png" Width="80" Height="3" Stretch="Fill" Margin="162,55,158,1" Visibility="Collapsed" />
</Grid>
</Border>
For Flip view XAML code is
<Grid Grid.Row="1" >
<FlipView x:Name="flipControl" SelectionChanged="flipControl_SelectionChanged" >
<FlipViewItem >
<ListView x:Name="listViewForSports" >
<ListView.ItemTemplate>
<DataTemplate>
<Image Stretch="Fill" Source="{Binding SportsImage}"></Image>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</FlipViewItem>
<FlipViewItem >
<ListView x:Name="listViewForHomes">
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding HomesImage}" Stretch="Fill"></Image>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</FlipViewItem>
<FlipViewItem >
<ListView x:Name="listViewForCars">
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding CarsImage}" Stretch="Fill"></Image>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</FlipViewItem>
</FlipView>
</Grid>`
and write in code behind file MainPage.xaml.cs
Just initialize these globally:
public sealed partial class MainPage : Page
{
List<Sports> listOfSports;
List<Cars> listOfCars;
List<Homes> listOfHomes;
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
bind data to the FlipView control when page is initialized
protected override void OnNavigatedTo(NavigationEventArgs e)
{
flipControl.SelectedIndex = 0;
// TODO: Prepare page for display here.
// TODO: If your application contains multiple pages, ensure that you are
// handling the hardware Back button by registering for the
// Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
// If you are using the NavigationHelper provided by some templates,
// this event is handled for you.
GetData();
}
This method will bind
public void GetData()
{
listOfSports = new List<Sports>();
for (int i = 1; i < 9; i++)
{
listOfSports.Add(new Sports() { SportsImage = #"ms-appx:///Images/Sports/image" + i.ToString() + ".jpg" });
}
listViewForSports.ItemsSource = listOfSports;
listOfCars = new List<Cars>();
for (int i = 1; i < 14; i++)
{
listOfCars.Add(new Cars() { CarsImage = #"ms-appx:///Images/Cars/image" + i.ToString() + ".jpg" });
}
listViewForCars.ItemsSource = listOfCars;
listOfHomes = new List<Homes>();
for (int i = 1; i < 9; i++)
{
listOfHomes.Add(new Homes() { HomesImage = #"ms-appx:///Images/Homes/image" + i.ToString() + ".jpg" });
}
listViewForHomes.ItemsSource = listOfHomes;
}
public class Cars
{
public string CarsImage { get; set; }
}
public class Sports
{
public string SportsImage { get; set; }
}
public class Homes
{
public string HomesImage { get; set; }
}`
I did with tap event to navigation withing flip view` private void appbarSports_Tapped(object sender, TappedRoutedEventArgs e)
{
// TextBlock a = sender as TextBlock;
// imgLine0.Margin = new Thickness(a.Margin.Left, 55, a.Margin.Right, 1);
flipControl.SelectedIndex = 0;
method(0);
}
private void appbarCars_Tapped(object sender, TappedRoutedEventArgs e)
{
// TextBlock a = sender as TextBlock;
//imgLine0.Margin = new Thickness(a.Margin.Left, 55, a.Margin.Right, 1);
flipControl.SelectedIndex = 2;
method(2);
}
private void appbarHomes_Tapped(object sender, TappedRoutedEventArgs e)
{
// TextBlock a = sender as TextBlock;
// imgLine0.Margin = new Thickness(a.Margin.Left, 55, a.Margin.Right, 1);
flipControl.SelectedIndex = 1;
method(1);
}
I also used for when the user flips so I used FlipView.SelectionChanged event
private void flipControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
FlipView viewControl = sender as FlipView;
int a = viewControl.SelectedIndex;
method(a);
}
This method() is help full for changing imageLine position
public void method(int a)
{
if (imgLine0 != null)
{
switch (a)
{
case 0:
imgLine0.Visibility = Visibility.Visible;
imgLine1.Visibility = Visibility.Collapsed;
imgLine2.Visibility = Visibility.Collapsed;
break;
case 1:
imgLine0.Visibility = Visibility.Collapsed;
imgLine1.Visibility = Visibility.Visible;
imgLine2.Visibility = Visibility.Collapsed;
break;
case 2:
imgLine0.Visibility = Visibility.Collapsed;
imgLine1.Visibility = Visibility.Collapsed;
imgLine2.Visibility = Visibility.Visible;
break;
}
}
}
My Longlistselector DataTemplate
<DataTemplate x:Key="NotesListBoxItemTemplate">
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<CheckBox
Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"
x:Name="chkDelete"
Visibility="Visible" Tap="chkDelete_Tap" Margin="0,36,0,0" />
<TextBlock
Text="{Binding NoteName}"
FontSize="{StaticResource PhoneFontSizeLarge}"
FontFamily="Segoe WP"
Grid.Row="0" Grid.Column="1" Margin="12,24,0,0" />
</Grid>
</DataTemplate>
and my Longlist selector is
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ScrollViewer>
<phone:LongListSelector
x:Name="MainListBox"
ItemsSource="{Binding AllData}"
Margin="12, 0, 12, 0"
ItemTemplate="{StaticResource ListBoxItemTemplate}" />
</ScrollViewer>
</Grid>
How do I loop through the items and get the Checkbox checked state in each item? Previously I used ListBox and its worked correctly. And I am able to find out the checkbox value of the each item using below code
private T FindFirstElementInVisaulTree<T>(DependencyObject parentElement) where T:DependencyObject
ListBoxItem passed as a DependencyObject. The only problem with ListBox is scrolling. So trying for LongListSelector.
Please how do i loop through the items in LongListSelector.
Thank you
You can also Data Bind the state of the checkbox to your Model. Then you can just loop through the MainListBox.ItemsSource. If you do it this way you need to set the Binding Mode=Two Way or the collection will not change once someone taps the Checkbox. I would also recommend you use a Command to handle the Tap event on the Checkbox so you can handle in your ViewModel rather then Code behind. Here's my quick example modified from previous solutions I have posted:
// Namespaces used
using System.Collections.ObjectModel; // ObservableCollection<T>
using System.ComponentModel; // INotifyPropertyChanged
// sample_data class
public class sample_data : INotifyPropertyChanged
{
// simple constructor
public sample_data(string noteName, Boolean checkboxState)
{
this.NoteName = noteName;
this.CheckboxState = checkboxState;
}
// implement the INotify
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
// {Binding Properties}
Boolean checkbox_state;
public Boolean CheckboxState
{
get { return checkbox_state; }
set { checkbox_state = value; NotifyPropertyChanged("CheckboxState"); }
}
string note_name;
public string NoteName
{
get { return note_name; }
set { note_name = value; NotifyPropertyChanged("NoteName"); }
}
}
// create a sample set of data to show
private ObservableCollection<sample_data> CreateData()
{
ObservableCollection<sample_data> my_list = new ObservableCollection<sample_data>();
my_list.Add(new sample_data("one", false));
my_list.Add(new sample_data("two", true));
my_list.Add(new sample_data("three", false));
my_list.Add(new sample_data("four", true));
my_list.Add(new sample_data("five", false));
my_list.Add(new sample_data("six", true));
my_list.Add(new sample_data("seven", false));
my_list.Add(new sample_data("eight", true));
return my_list;
}
public MainPage()
{
InitializeComponent();
MainListBox.ItemsSource = CreateData(); // set the data bind
}
/// You can loop through the items like this, use any convention you want.
private void LoopThroughItems()
{
foreach (sample_data sd in MainListBox.ItemsSource)
{
Boolean is_check = sd.CheckboxState;
}
}
Your DataTemplate needs to change so it Databinds the checkbox with two-way binding.
<DataTemplate x:Key="NotesListBoxItemTemplate">
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" IsChecked="{Binding CheckboxState, Mode=TwoWay}" Grid.Row="0" Grid.RowSpan="2" x:Name="chkDelete" Visibility="Visible" Margin="0,36,0,0" />
<TextBlock Text="{Binding NoteName}" FontSize="{StaticResource PhoneFontSizeLarge}" FontFamily="Segoe WP" Grid.Row="0" Grid.Column="1" Margin="12,24,0,0" />
</Grid>
</DataTemplate>
I am creating a wp8 application for showing some html files in a browser and the structure is
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Name="PageNavigationMenu">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Height="70" Content="P" Grid.Column="0" VerticalContentAlignment="Center" Click="btnPrevious_Click" x:Name="btnPrevious" ></Button>
<Button Height="70" Content="N" Grid.Column="1" VerticalAlignment="Center" Click="btnNext_Click" x:Name="btnNext"></Button>
</Grid>
<Grid Grid.Row="1" Hold="Grid_Hold">
<phone:WebBrowser IsScriptEnabled="True" x:Name="mainBrowserControl">
</phone:WebBrowser>
</Grid>
</Grid>
Now i am using a previous button and next button to change the content in browser . I want to do it using the Swipe Left / Swipe Right on browser . Like if user Swipe left direction , borswer content should be loaded with previous page and Swipe right results to load next page.
So what are the events i have to listen to implement swipe feature
There are two possibilities (AFAIK):
You can use XNA TouchPanel (more information about it you can find here: Working with TouchInput, Detecting Gestures and this blog) for this:
public MainPage()
{
InitializeComponent();
TouchPanel.EnabledGestures = GestureType.Flick;
myWebbrowser.ManipulationCompleted += myWebbrowser_ManipulationCompleted;
}
private void myWebbrowser_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
{
if (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
switch (gesture.GestureType)
{
case GestureType.Flick:
if (e.FinalVelocities.LinearVelocity.X < 0)
LoadNextPage();
if (e.FinalVelocities.LinearVelocity.X > 0)
LoadPreviousPage();
break;
default:
break;
}
}
}
Or you can use Silverlight Toolkit as described in this answer or other here.
EDIT - small remark
Only watch out, because when you use XNA, you sometimes need to do (for example OnNavigatedTo):
FrameworkDispatcher.Update();
Otherwise your App will sometimes crash.
Hope this helps.
EDIT 2 - code example after comment
In case your ManipulationEvent is handeled first (for example by Pivot or Map), I tried to subscribe to Touch.FrameReported - as I've tested - it should work:
public MainPage()
{
InitializeComponent();
TouchPanel.EnabledGestures = GestureType.Flick;
Touch.FrameReported += Touch_FrameReported;
}
private void Touch_FrameReported(object sender, TouchFrameEventArgs e)
{
if (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
switch (gesture.GestureType)
{
case GestureType.Flick:
if (gesture.Delta.X > 0)
MessageBox.Show("Right");
if (gesture.Delta.X < 0)
MessageBox.Show("Left");
break;
default:
break;
}
}
}
NEXT EDIT (after next comments) - better implementation and example of disabling up, down gestures:
If you don't want to activate for up (little left)/down (little right), you have to describe conditions yourself. Be aware that there is a very little chance (if any) that user will move his finger only left/right/up/down - so you have to include some margin. There are many solutions for that, you have to try and play with it, the simpliest solutions just compare deltaX and deltaY of gesture:
public MainPage()
{
InitializeComponent();
TouchPanel.EnabledGestures = GestureType.Flick | GestureType.HorizontalDrag;
Touch.FrameReported += Touch_FrameReported;
}
TouchPoint firstPoint;
private void Touch_FrameReported(object sender, TouchFrameEventArgs e)
{
TouchPoint mainTouch = e.GetPrimaryTouchPoint(ContentPanel);
if (mainTouch.Action == TouchAction.Down) firstPoint = mainTouch;
else if (mainTouch.Action == TouchAction.Up && TouchPanel.IsGestureAvailable)
{
double deltaX = mainTouch.Position.X - firstPoint.Position.X;
double deltaY = mainTouch.Position.Y - firstPoint.Position.Y;
if (Math.Abs(deltaX) > 2 * Math.Abs(deltaY))
{
if (deltaX < 0) MessageBox.Show("Right.");
if (deltaX > 0) MessageBox.Show("Left.");
}
}
}
I have an app that uses a LongListSelector to display a list of items, at the bottom of the page I have a TextBox. When the TextBox is tapped, the SIP displays itself. At this point, I'm unable to then scroll to the top of the LLS.
Sample code:
XAML:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<phone:LongListSelector x:Name="TheList">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"
Style="{StaticResource PhoneTextLargeStyle}"/>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
<Grid Grid.Row="1">
<TextBox />
</Grid>
</Grid>
C#:
public MainPage()
{
InitializeComponent();
Loaded += (sender, args) =>
{
var list = new List<string>();
for (var i = 0; i < 30; i++)
{
list.Add("This is string number " + i);
}
TheList.ItemsSource = list;
};
}
This is as much as I can see, I can pull down to string number 5, but can't see any higher:
Anyone got any ideas?
The ScrollViewer doesn't take into account the SIP so its scrolling experience is the same as when the SIP is not visible (which is why the top can't be reached). One workaround would be to add a margin to the top of the LongListSelector, (or the bottom if your textbox is at the top), when the SIP is displayed.
As there's no event for the SIP, you can handle the GotFocus and LostFocus events of the TextBox. (The 180 value was obtained via trial and error)
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
TheList.Margin = new Thickness(0,180,0,0);
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
TheList.Margin = new Thickness();
}
I have a Window 8 RT store application (XAML/C#).
I have a form with a grid as the main component. That grid has 50 rows and each row has a TextBox. The grid is wrapped in a scrollviewer:
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
...50 rows
</Grid.RowDefinitions>
<TextBox Grid.Row="0" />
<TextBox Grid.Row="1" />
<TextBox Grid.Row="2" />
...
<TextBox Grid.Row="50" />
</Grid>
</ScrollViewer>
When this form is loaded there is a notable pause while the page is loaded, I guessing this is because the page is being drawn.
What is the best way to speed this load process up? Can I virtualize the loading of the grid/Textboxes?
The slowness is notable once the application is running on a Windows Surface tablet, it's not bad on my design PC but that is obviously much more powerful.
Thanks in advance.
You can use a ListView instead of the Grid in a ScrollViewer since that supports virtualization by default. Other than that - it might be nice to have some nicer user experience than a scary long list of TextBoxes to fill - maybe break up your form in multiple pages or use a FlipView to flip between groups of fields.
*EDIT - example
XAML
<Page
x:Class="App10.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App10"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate
x:Key="TextFieldTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition
Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Text="{Binding Label}" />
<TextBox
Text="{Binding Value, Mode=TwoWay}"
Grid.Row="1" />
</Grid>
</DataTemplate>
<DataTemplate
x:Key="BoolFieldTemplate">
<CheckBox
Content="{Binding Label}"
IsChecked="{Binding Value, Mode=TwoWay}" />
</DataTemplate>
<local:FieldTemplateSelector
x:Key="FieldTemplateSelector"
TextTemplate="{StaticResource TextFieldTemplate}"
BoolTemplate="{StaticResource BoolFieldTemplate}" />
</Page.Resources>
<Grid
Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ListView
x:Name="lv"
ItemTemplateSelector="{StaticResource FieldTemplateSelector}" />
</Grid>
</Page>
C#
using System.Collections.Generic;
using App10.Common;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace App10
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.lv.ItemsSource =
new List<object>(
new object[]
{
new BoolFieldViewModel { Label = "Some bool field" },
new TextFieldViewModel { Label = "Some text field" },
new TextFieldViewModel { Label = "Some text field" },
new BoolFieldViewModel { Label = "Some bool field" },
new BoolFieldViewModel { Label = "Some bool field" },
new TextFieldViewModel { Label = "Some text field" },
});
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
public abstract class FieldViewModel<T> : BindableBase
{
public string Label { get; set; }
#region Value
private T _value;
public T Value
{
get { return _value; }
set { this.SetProperty(ref _value, value); }
}
#endregion
}
public class BoolFieldViewModel : FieldViewModel<bool> { }
public class TextFieldViewModel : FieldViewModel<string> { }
public class FieldTemplateSelector : DataTemplateSelector
{
public DataTemplate BoolTemplate { get; set; }
public DataTemplate TextTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item is BoolFieldViewModel) return BoolTemplate;
if (item is TextFieldViewModel) return TextTemplate;
return base.SelectTemplateCore(item, container);
}
}
}