Why isn't the TextBox inside ContentDialog automatically scroll above keyboard - windows

I notice that if the TextBox is in a Page, then everything working perfectly. Whenever the TextBox is focused, it will scroll to the right position above the keyboard so that the user will be able to see the text as he is typing along. Thing is a little bit different for ContentDialog for whatever reason. TextBox is easily covered by the keyboard. Is there any obvious setting that I am missing?
I create a default ContentDialog and copied the code to a page. And get the following screenshots. Everything else is the same except that the upper level XAML elements is <ContentDialog> for the left column, <Page> for the right column.
Left Image - ContentDialog before keyboard pop up
Right Image - Page before keyboard pop up
Left Image - ContentDialog after keyboard pop up
Right Image - Page after keyboard pop up
Here is the related code:
<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBox Name="email" Header="Email address"/>
<PasswordBox Name="password" Header="Password"/>
<CheckBox Name="showPassword" Content="Show password"/>
<!-- Content body -->
<TextBlock Name="body" Style="{StaticResource MessageDialogContentStyle}" TextWrapping="Wrap">
<TextBlock.Text>
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</TextBlock.Text>
</TextBlock>
</StackPanel>
Why isn't the TextBox inside ContentDialog scrolled above the keyboard as it is like the in the Page?

Once I've faced similar problem with the TextBox and have found answer here. Basically, once the keyboard is shown, the focused element is not moved up, you can correct this behaviour by making additional transform:
// add this code somewhere to your constructor of your page or content dialog - where the problematic TextBox is located
Windows.UI.ViewManagement.InputPane.GetForCurrentView().Showing += (s, args) =>
{
const double extraHeightBuffer = 20.0;
UIElement focused = FocusManager.GetFocusedElement() as UIElement;
if (null != focused)
{
GeneralTransform gt = focused.TransformToVisual(this);
Point focusedPoint = gt.TransformPoint(new Point(0, focused.RenderSize.Height - 1));
double bottomOfFocused = focusedPoint.Y + extraHeightBuffer;
if (bottomOfFocused > args.OccludedRect.Top)
{
var trans = new TranslateTransform();
trans.Y = -(bottomOfFocused - args.OccludedRect.Top);
this.RenderTransform = trans;
}
args.EnsuredFocusedElementInView = true;
}
};
Windows.UI.ViewManagement.InputPane.GetForCurrentView().Hiding += (s, args) =>
{
var trans = new TranslateTransform();
trans.Y = 0;
this.RenderTransform = trans;
args.EnsuredFocusedElementInView = false;
};

Related

How to know which indicator you are on with CarouselView in Xamarin Forms?

I a using the CarouselView and I can successfully load in items! Yey, so far so good. But now when i reach the 2nd item, I try to do a specific function that will only happen in the 2nd index.
Right now i seem to have figured out when im on the 2nd page al though the log is writing a lot of things in the log, but when i transition to the 3rd page, or back to the 1st page, i have lost count (programmatically) of where I am.
<CarouselView BackgroundColor="Transparent"
HorizontalScrollBarVisibility="Never"
IndicatorView="indicatorView"
VerticalOptions="CenterAndExpand"
Margin="25,0"
Scrolled="CarouselView_Scrolled"
ItemsSource="{Binding BindingContext.Intro, Source={x:Reference ParentView}}">
<CarouselView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal"
SnapPointsAlignment="Center"
SnapPointsType="MandatorySingle"/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Text}"
FontSize="Large"
HorizontalTextAlignment="Start"
FontFamily="Helvetica Neue"
TextColor="DimGray"
FontAttributes="None" />
</AbsoluteLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
Code behind:
async void CarouselView_Scrolled(System.Object sender, Xamarin.Forms.ItemsViewScrolledEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.CenterItemIndex);
if (e.CenterItemIndex == 1)
{
if (Transitioning == false)
{
Transitioning = true;
await ParentView.ColorTo(Color.White, Color.FromHex("#161825"), c =>
{
ParentView.BackgroundColor = c;
Transitioning = false;
}, 500);
}
}
else
{
Transitioning = true;
await ParentView.ColorTo(Color.FromHex("#161825"), Color.White, c => ParentView.BackgroundColor = c, 500);
Transitioning = false;
}
}
What logic do i need to add in my frontend to successfully monitor if im on page 2?
ItemsViewScrolledEventArgs has a CenterItemIndex property that tells you which item is in the center view
or you could use the CurrentItemChanged event

ListPicker windows phone 7 giving error

I have list picker in my windows phone 7 app & it works fine but whenever i try to add more options in it... it crashes i can add upto 4 or 5 options only in this list picker is there anything i can do aboout it
My working code is
xaml code
<toolkit:ListPicker x:Name="ListPicker" Margin="12,3,12,12" Foreground="#FF00C000" >
<toolkit:ListPicker.Items>
<toolkit:ListPickerItem Content="Item1"/>
<toolkit:ListPickerItem Content="Item2"/>
</toolkit:ListPicker.Items>
</toolkit:ListPicker>
& .cs code
string ListPickerOperator = (this.ListPicker.SelectedItem as ListPickerItem).Content as string;
switch (ListPickerOperator )
{
case "Item1":
break;
case "Item2":
break;
}
but whenever i try to make this list bigger it crashes after 4 5 items
I think you should use item template. You couldn't show more than 4 or 5 items because you have to use "Full Mode template".
to use item template you should do something like this.
<toolkit:ListPicker x:Name="ListPicker" Margin="12,3,12,12" Foreground="#FF00C000" SelectionChanged="ListPicker_SelectionChanged" >
<!--Normal Item template-->
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
<!--Full Mode template-->
<toolkit:ListPicker.FullModeItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</toolkit:ListPicker.FullModeItemTemplate>
</toolkit:ListPicker>
To populate the listpicker you only have to use itemSource propetary
//list string
List<String> itemsList = new List<String>();
// create 100 items
for (int j = 0; j < 100; j++)
{
itemsList.Add("item" + j);
}
//itemsource
this.ListPicker.ItemsSource = itemsList;
to get the selectedItem you could do something like this
String ListPickerOperator= ((String)this.ListPicker.SelectedItem);
switch (ListPickerOperator)
{
case "item1":
MessageBox.Show("item 1 was selected");
break;
case "item2":
MessageBox.Show("item 2 was selected");
break;
/*
.
* .
* .
* .
* .
*/
}

Passing the value of a bound list

I had this code working before, but have somehow deleted it as I was trying to get something else fixed.
So I have a list which is bound as a View model, and the list has three lines on it.
I want to be able to click on the list, get the value of the third line on another page and use that value.
Here is the code for the selection of the list
private void List_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If selected index is -1 (no selection) do nothing
if (List.SelectedIndex == -1)
return;
// Navigate to the new page
NavigationService.Navigate(new Uri("/Route.xaml?selectedItem=" + List.SelectedIndex, UriKind.Relative));
string urlWIthData = string.Format("/Route.xaml?name={0}", " ");
this.NavigationService.Navigate(new Uri(urlWIthData, UriKind.Relative));
// Reset selected index to -1 (no selection)
List.SelectedIndex = -1;
}
Then, on the route page I want to be able to get the value and use the value line three....
How do I do this?
EDIT:
so this one part of the list:
this.Items.Add(new ItemViewModel() { LineOne = "Images/1.png", LineTwo = "Whitehawk - County
Hospital - City Centre - Hove - Portslade - Mile Oak", LineThree = "1 Whitehawk - Mile Oak",
LineFour = "1 Mile Oak - Whitehawk", LineFive = "1149" });
I Display the list on one page :
<ListBox Margin="6,6,7,6" ItemsSource="{Binding Items}" Name="List" OpacityMask="#FFD38648" FontSize="26" SelectionChanged="List_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17" DataContext="{Binding}">
<Image Name="Images" Source="{Binding LineOne}">
</Image>
<TextBlock Text="{Binding LineTwo}" Style="{StaticResource PhoneTextSubtleStyle}" Name="textblock3"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can cast the list's SelectedItem to type Item and get the value from there:
private void List_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If selected index is -1 (no selection) do nothing
if (List.SelectedIndex == -1)
return;
// Here's the codes -----------------------
var item = Items.SelectedItem as Item;
if(item == null) //cast didn't work
return;
var lineThree = item.LIneThree;
// end of the codes -----------------------
// Navigate to the new page
NavigationService.Navigate(new Uri("/Route.xaml?selectedItem=" + List.SelectedIndex, UriKind.Relative));
string urlWIthData = string.Format("/Route.xaml?name={0}", " ");
this.NavigationService.Navigate(new Uri(urlWIthData, UriKind.Relative));
// Reset selected index to -1 (no selection)
List.SelectedIndex = -1;
}

stop the stackpanel items inside scroll viewer to be at the display left side when scroll

I have added 10 images in a stackpanel horizontally which is inside a scrollviewer. When user swipe the page ,the scrollviewer stops at certain position, if the scroll stops in the middle of 2 images like the first image shown below i want to set the image with number 3 to be automatically scroll and fit with the left side of the screen like in the second image
for (int i = 0; i <= 9; i++)
{
Uri uri = new Uri("http://d1mu9ule1cy7bp.cloudfront.net//catalogues/47/pages/p_" + i + "/thump.jpg");
ImageSource img1 = new BitmapImage(uri);
Image rect = new Image { RenderTransform = new TranslateTransform() };
rect.Source = img1;
stack.Children.Add(rect);
}
XAML:
<Grid x:Name="LayoutRoot" Width="480" Background="Transparent" Margin="0,-33,0,0" Height="800">
<ScrollViewer HorizontalContentAlignment="Left" HorizontalAlignment="Left" Name="scroll" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
<StackPanel Name="stack" Width="Auto" Orientation="Horizontal" HorizontalAlignment="Left" >
</StackPanel>
</ScrollViewer>
</Grid>
The first thing you need to do is detect which item is overlapping the side of the screen. To do this, iterate over each item within the StackPanel and determine their location relative to some other element that has a fixed location on screen.
To do this, I use the following extension method:
/// <summary>
/// Gets the relative position of the given UIElement to this.
/// </summary>
public static Point GetRelativePosition(this UIElement element, UIElement other)
{
return element.TransformToVisual(other)
.Transform(new Point(0, 0));
}
i.e. for each item call the following;
Point position = stackPanelItem.GetRelativePosition(someFixedElement);
Using the location of each item, you should be able to work out which one overlaps the screen.
You then need to calculate by how much you need to scroll in order to ensure that your item is fully visible, then use ScrollViewer.ScrollToVerticalOffset to scroll to that location.
This probably isn't the nicest solution and I am sure there is a better way to achieve this but you could use the following :-
XAML :-
<ListBox x:Name="MyListBox"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
C# :-
DispatcherTimer myTimer = new DispatcherTimer();
// Constructor
public MainPage()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
{
MyListBox.Items.Add(new Button()
{
Content = i.ToString(),
Width = 200,
Height = 100,
});
MyListBox.MouseMove += new MouseEventHandler(MyListBox_MouseMove);
}
myTimer.Interval = TimeSpan.FromSeconds(1);
myTimer.Tick += new EventHandler(myTimer_Tick);
}
private void myTimer_Tick(object sender, EventArgs e)
{
myTimer.Stop();
SnapFirstItem();
}
private void MyListBox_MouseMove(object sender, MouseEventArgs e)
{
myTimer.Stop();
myTimer.Start();
}
private void SnapFirstItem()
{
foreach (Button currentButton in MyListBox.Items)
{
bool visible = MyListBox.TestVisibility(currentButton, System.Windows.Controls.Orientation.Horizontal, true);
if (visible)
{
MyListBox.ScrollIntoView(currentButton);
break;
}
}
}
The TestVisibility extension method is from the following :-
http://blogs.msdn.com/b/ptorr/archive/2010/10/12/procrastination-ftw-lazylistbox-should-improve-your-scrolling-performance-and-responsiveness.aspx

Windows Phone 7 Back Button issue

In my app I have several pages. When I click on the Windows "Back" Button everything goes back as expected.
However I have 2 pages that are causing me grief. Page "A" is doing some binding in the 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}"/>
</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>
The code behind for Page A is fairly simple:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
// Set the data context of the listbox control to the sample data
if (DataContext == null)
DataContext = App.ViewModel;
App.ViewModel.Refresh();
lbPrograms.ItemsSource = App.ViewModel.Items;
}
private void lbPrograms_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
NavigationService.Navigate(new Uri("/DisplayProgram.xaml?selectedItem=" + lbPrograms.SelectedIndex, UriKind.Relative));
}
private void BackBtn_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
Page B has no binding in the XAML as I am taking the data from the ModelView a drawing it out dynamically on the screen. Like so:
private int index;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string selectedIndex = "";
if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
{
//prevents error
if (int.Parse(selectedIndex) == -1)
{
return;
}
if ((DataContext == null))
{
index = int.Parse(selectedIndex);
App.ViewModel.Refresh();
DataContext = App.ViewModel.Items[index].nValDictionary;
int i = 0;
foreach (KeyValuePair<string, string> kvp in (((System.Collections.Generic.Dictionary<string, string>)(DataContext))))
{
StackPanel sp = new StackPanel();
sp.Name = "sp" + i;
sp.Background = new SolidColorBrush(Colors.Black);
sp.Width = 460;
WrapPanel wp = new WrapPanel();
wp.Name = "test" + i;
wp.Width = 300;
wp.Height = 200;
TextBlock txt = new TextBlock();
txt.Text = kvp.Key.ToString();
txt.Foreground = new SolidColorBrush(Colors.White);
sp.Children.Add(txt);
int chkBoxesVal = 0;
if (kvp.Value == "")
{
chkBoxesVal = 0;
}else{
chkBoxesVal = Convert.ToInt32(kvp.Value.ToString());
}
int iCount = 0;
for (iCount = 0; iCount <= chkBoxesVal - 1; iCount++)
{
CheckBox chk = new CheckBox();
chk.Name = i.ToString();
chk.Width = 56;
chk.Height = 70;
chk.Content = "";
//chk.Background = new SolidColorBrush(Colors.Black);
//chk.BorderBrush = new SolidColorBrush(Colors.White);
chk.Style = (Style)Application.Current.Resources["checkBoxNG"];
wp.Children.Add(chk);
}
sp.Children.Add(wp);
lbItems.Items.Add(sp);
i += 1;
}
}
}
}
}
So when I'm going forward everything works fine, but when I hit the Windows "Back" button on Page B I get an error. I stepped through my code and when I hit the "Back" button it does go back to Page A, but then it is also going to Page B, which then throws the error and stops. So can anyone tell me why this behavior is happening? I would expect that it would go back to Page A and just stop there. Not to go back to Page B. is there something in my code that is causing it to reload Page B? Any resources that you can provide that might explain this behavior is also welcome!
Thanks!
It looks like SelectionChanged on Page A is firing as a result of the ItemsSource initialisation you're doing in OnNavigatedTo.
You could verify the SelectedIndex is -1 before taking any action in the SelectionChanged event.
Alternatively you could remove any existing event handler on SelectionChanged while doing this initialisation and restore that event handler on completion.
My assumption is that lbPrograms_SelectionChanged event occurs when you press back button and page A is loaded again.
Change your navigation design. For your DataTemplateStackPanel you could use ManipulationStarted event
and inside add
NavigationService.Navigate(new Uri("/DisplayProgram.xaml?selectedItem=" + lbPrograms.SelectedIndex, UriKind.Relative));

Resources