Yes, i have googled for it, this solution doesn't do the trick:
Disable navigation on FlipView
Because i want to remain changing items with animations, but only programmatically.
I have investigated the FlipView template and found that all interactions/animations etc. are built using the ScrollingHost by name:
<ScrollViewer x:Name="ScrollingHost" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalSnapPointsType="MandatorySingle" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsTabStop="False" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Padding="{TemplateBinding Padding}" TabNavigation="{TemplateBinding TabNavigation}" VerticalSnapPointsType="MandatorySingle" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="Disabled">
<ItemsPresenter/>
</ScrollViewer>
So, i have created a custom class MyFlipView and derivered from FlipView, and overrided MouseWheel ( this gives me the needed behavior on desktop ), and deleted navigation buttons from template ( this also limits user interactions ). But the only thing that remains, user is still able to drag the items by pointer ( tablets, phones, maybe even PC with touch screens ). here is my code:
public class MyFlipView : FlipView
{
ScrollViewer scroll;
public MyFlipView()
{
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
scroll = GetTemplateChild("ScrollingHost") as ScrollViewer;
scroll.HorizontalScrollMode = ScrollMode.Disabled;
scroll.VerticalScrollMode = ScrollMode.Disabled;
scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
scroll.IsHorizontalRailEnabled = false;
scroll.IsVerticalRailEnabled = false;
scroll.IsVerticalScrollChainingEnabled = false;
scroll.IsHorizontalScrollChainingEnabled = false;
scroll.IsHoldingEnabled = false;
}
protected override void OnPointerWheelChanged(PointerRoutedEventArgs e)
{
e.Handled = true;
//base.OnPointerWheelChanged(e);
}
}
As you can see i tried do disable all the scrolling in the ScrollingHost, but still it is possible to switch items on touchscreens. How can i disable them also?
Set the FlipView's IsHitTestVisible property to false.
Then set KeyboardNavigation.DirectionalNavigation to none
Which is basically saying "You can't touch me or tab to me"
Thomas Schneiter's answer would still allow it to be reached via tabbing / other buggy methods of navigation.
If you don't need any interaction with the FlipView, an easy but... well kinda ugly solution is to put a (almost) transparent rectangle on top of your FlipView.
<Grid>
<FlipView ... />
<Rectangle Fill="White" Opacity="0.01" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
Over a year later and still no good solution for disabling FlipView's. Here's what I ended up doing which seems to do the trick without having to create a new FlipView control.
Edit the ControlTemplate and remove all the navigation buttons. Add a transparent background to you DataTemplate container. Add a PointerWheelChanged event handler to the DataTemplate container and have it set e.Handled = true;. Finally, add a SelectionChanged event handler to the FlipView and have it reset the selected item back to the original.
XAML
<FlipView x:Name="MyFlipView" ItemsSource="{x:Bind Items,Mode=OneWay}" SelectionChanged="FlipView_SelectionChanged">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent" PointerWheelChanged="Item_PointerWheelChanged">
<!--You Item XAML-->
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
<FlipView.Template>
<ControlTemplate TargetType="FlipView">
<Grid>
<!--Default ScrollViewer settings omitted, but no changes needed-->
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</Grid>
</ControlTemplate>
</FlipView.Template>
</FlipView>
Code Behind
private bool _isDisabled;
private object _selectedItem;
public ObservableCollection<object> Items { get; } = new ObservableCollection<object>();
//methods for setting Items, _isDisabled, and _selectedItem omitted
private void Item_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
//this prevents the wheel from changing the items
e.Handled = _isDisabled;
}
private void FlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Can't find a way to disable keyboard from changing items so we'll monitor the change and flip it back
if (_isDisabled)
{
this.SetupSelectedItem();
}
}
private void SetupSelectedItem()
{
//do a check here to prevent SelectionChanged events from firing.
if (this.MyFlipView.SelectedItem != _selectedItem)
{
this.MyFlipView.SelectedItem = _selectedItem;
}
}
UPDATE
Ok, TouchScreen was still having some problems so I took another stab at it. There are two levels we need to work on, the FlipViewItem and the FlipView. Unfortunately we have to sub-class these because there aren't any overrides we can do to interrupt the default behavior. I also wanted to use binding to be able to turn the flipping on or off. This only supports Horizontal orientation but can easily be adjusted to support Vertical.
Custom FlipViewItem is needed to control the mouse and keyboard.
public sealed class GalleryFlipViewItem : FlipViewItem
{
public bool IsFlipEnabled { get; set; }
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
e.Handled = !this.IsFlipEnabled;
base.OnKeyDown(e);
}
protected override void OnPointerWheelChanged(PointerRoutedEventArgs e)
{
e.Handled = !this.IsFlipEnabled;
base.OnPointerWheelChanged(e);
}
}
Custom FlipView is needed to control the touch and trickle the setting to the custom FlipViewItem.
public sealed class GalleryFlipView : FlipView
{
public static readonly DependencyProperty IsFlipEnabledProperty =
DependencyProperty.Register("IsFlipEnabled", typeof(bool), typeof(GalleryFlipView), new PropertyMetadata(true, IsFlipEnabledChanged));
private static void IsFlipEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is GalleryFlipView control)
{
if (control.GetTemplateChild("ScrollingHost") is ScrollViewer scrollViewer)
{
scrollViewer.HorizontalScrollMode = control.IsFlipEnabled ? ScrollMode.Auto : ScrollMode.Disabled;
}
if (control.ContainerFromItem(control.SelectedItem) is GalleryFlipViewItem flipViewItem)
{
flipViewItem.IsFlipEnabled = control.IsFlipEnabled;
}
}
}
public bool IsFlipEnabled
{
get { return (bool)GetValue(IsFlipEnabledProperty); }
set { SetValue(IsFlipEnabledProperty, value); }
}
protected override DependencyObject GetContainerForItemOverride()
{
return new GalleryFlipViewItem
{
IsFlipEnabled = this.IsFlipEnabled
};
}
}
Now we need to add the styles for each of these controls. I just copied the default styles for FlipViewItem and FlipView. I made a small adjustment to the FlipView by removing the up/down buttons and added binding to control the left/right button's visibility. To do this, wrap the original button in a grid and then use a converter to convert the bool to a visibility enum.
<Grid HorizontalAlignment="Left" VerticalAlignment="Center" Visibility="{Binding IsFlipEnabled,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibleConverter}}">
<Button x:Name="PreviousButtonHorizontal" Height="36" IsTabStop="False" Template="{StaticResource HorizontalPreviousTemplate}" UseSystemFocusVisuals="False" Width="20" />
</Grid>
<Grid HorizontalAlignment="Right" VerticalAlignment="Center" Visibility="{Binding IsFlipEnabled,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibleConverter}}">
<Button x:Name="NextButtonHorizontal" Height="36" IsTabStop="False" Template="{StaticResource HorizontalNextTemplate}" UseSystemFocusVisuals="False" Width="20" />
</Grid>
Since IsFlipEnabled is a DependencyProperty you can use binding, xaml, or code behind to control it.
<controls:GalleryFlipView IsFlipEnabled="False">
Finally, this seems like the right solution. So frustrating we have to do so much work to simply turn this feature on and off.
Related
I have a Popup which will fill the whole page when opened.
<Grid x:Name="gridRoot" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Open" HorizontalAlignment="Center" Click="{x:Bind viewModel.OpenPopup}" />
<Popup x:Name="popupCorrect" VerticalAlignment="Top" IsOpen="{Binding IsOpen}" IsLightDismissEnabled="False">
<Popup.ChildTransitions>
<TransitionCollection>
<PaneThemeTransition Edge="Left" />
</TransitionCollection>
</Popup.ChildTransitions>
<uc:MyPopup Width="{Binding ElementName=gridRoot, Path=ActualWidth}" Height="{Binding ElementName=gridRoot, Path=ActualHeight}"/>
</Popup>
</Grid>
The Popup is a UserControl
<Grid Background="Red">
<Button Content="Close" HorizontalAlignment="Center" Click="{x:Bind viewModel.ClosePopup}" />
</Grid>
The page
When popup is shown
Close the popup, resize the page, then reopen the popup. Notice that it does not match the new size of container page even though its Width and Height is bound to gridRoot . Do I have to manually set a new Width and Height for the popup? Why can't I achieve this with binding? This issue also appears on mobile during 'OrientationChanged'
Based on Decade Moon comment, this is how to resize the popup to match the parent container as its size changed.
Create a dependency property in the code behind
public double PageWidth
{
get { return (double)GetValue(PageWidthProperty); }
set { SetValue(PageWidthProperty, value); }
}
public static readonly DependencyProperty PageWidthProperty =
DependencyProperty.Register("PageWidth", typeof(double), typeof(GamePage), new PropertyMetadata(0d));
public double PageHeight
{
get { return (double)GetValue(PageHeightProperty); }
set { SetValue(PageHeightProperty, value); }
}
public static readonly DependencyProperty PageHeightProperty =
DependencyProperty.Register("PageHeight", typeof(double), typeof(GamePage), new PropertyMetadata(0d));
Update the value on SizeChanged event
private void GamePage_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.NewSize.Width > 0d && e.NewSize.Height > 0d)
{
PageWidth = e.NewSize.Width;
PageHeight = e.NewSize.Height;
}
}
Then in XAML, just use x:Bind to bind the popup width and height
<Popup x:Name="popupCorrect" VerticalAlignment="Top" IsOpen="{Binding IsPopupCorrectOpen, Mode=TwoWay}" IsLightDismissEnabled="False">
<Popup.ChildTransitions>
<TransitionCollection>
<PaneThemeTransition Edge="Left" />
</TransitionCollection>
</Popup.ChildTransitions>
<uc:PopupCorrect Width="{x:Bind PageWidth, Mode=TwoWay}" Height="{x:Bind PageHeight, Mode=TwoWay}"/>
</Popup>
Pretty straight forward. Just remember not to use the ActualWidth or ActualHeight properties for binding source as they do not raise the PropertyChanged event.
Although it has an ActualWidthProperty backing field, ActualWidth does not raise property change notifications and it should be thought of as a regular CLR property and not a dependency property.
For purposes of ElementName binding, ActualWidth does not post updates when it changes (due to its asynchronous and run-time calculated nature). Do not attempt to use ActualWidth as a binding source for an ElementName binding. If you have a scenario that requires updates based on ActualWidth, use a SizeChanged handler.
#PutraKg have a great way.
But I have two way to solve it.
The first is set the VerticalAlignment="Center" HorizontalAlignment="Center" that can make the popup in the center.
But I think youare not content to put it in the center.
The great way is use the screen position.
You can get the Grid's screen postion and make it to popup.
In open button
private void Button_OnClick(object sender, RoutedEventArgs e)
{
var grid = (UIElement)popupCorrect.Parent; //get grid
var p = grid.TransformToVisual (Window.Current.Content).TransformPoint(new Point(0, 0)); //get point
popupCorrect.HorizontalOffset = p.X;
popupCorrect.VerticalOffset = p.Y;
popupCorrect.IsOpen = !popupCorrect.IsOpen;
}
I wanted to change the color of an item of ListView according the data value.
It would be easy doing:
<ListView.ItemContainerStyle>
<Style TargetType = "ListViewItem" >
< Setter Property="Background" Value="{Binding EventType, Converter={StaticResource EventTypeToBackColorConverter}}" />
</ListView.ItemContainerStyle>
But the thing is that UWP does not support binding in Setter Properties.
My second attempt was overriding PrepareContainerForItemOverride of the ListView:
public class EventListView : ListView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var listViewItem = element as ListViewItem;
var ev = item as EventType;
if(ev.Warning)
listViewItem.Background = new SolidColorBrush(Color.Red);
}
}
The above code works fine running in a PC with Windows 10 and UWP. It colors in red some items according the underlying data. When I run the same app in Windows Mobile, at beginning it works fine, but when I scroll up and then I scroll down, returning to the original view that was ok at beginning, now other items are also in red color.
What I am missing?
I am not sure the reason, but the following code works for me:
public class EventListView : ListView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var listViewItem = element as ListViewItem;
var ev = item as EventType;
if(ev.Warning)
listViewItem.Background = new SolidColorBrush(Color.Red);
else
listViewItem.Background = null;
}
}
I have added listViewItem.Background = null
This is because when there are a large number of Items, by default ListView has implement the function of data virtualization. It's not a good idea to disable this function since it can achieve a better performance.
But for your scenario, there is a much easier method to solve your problem. Since you're trying to modify the style of ListViewItem in the code behind, and we can't modify the existed one, we can set a new style of ListViewItem to ListView for example like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
var dynamicStyle = new Style();
dynamicStyle.TargetType = typeof(ListViewItem);
dynamicStyle.Setters.Add(new Setter(BackgroundProperty, Colors.Red));
listView.ItemContainerStyle = dynamicStyle;
}
Only one problem is, if you are setting the Background property to all the ListViewItem, it makes no difference than binding data to the Background property of ListView or setting the Background to ListView like this:
listView.Background = new SolidColorBrush(Colors.Red);
So I just assume that you want to modify the root control in the DataTemplate for example like the Grid in the following xaml:
<ListView x:Name="listView" ItemsSource="{x:Bind collection}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem" x:Name="myListItemStyle">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="{Binding Testtext}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then in this scenario, you can use data binding probably like this:
<DataTemplate>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{Binding EventType, Converter={StaticResource EventTypeToBackColorConverter}}">
<TextBlock Text="{Binding Testtext}" />
</Grid>
</DataTemplate>
Any way, if you insist to change some property of all ListViewItem in the ListView, you can use the first method I provided.
I'm building a Windows Phone 8.1 Hub Application. One of the hub section contains a ListView that displays a list of articles. I'd like to add a Textblock to this hubsection which displays a message when the articles failed to download. The XAML Code is below:
<HubSection
x:Uid="ArticlesSection"
Header="ARTICLES"
DataContext="{Binding Articles}"
HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}">
<DataTemplate>
<Grid>
<ListView
AutomationProperties.AutomationId="ItemListViewSection3"
AutomationProperties.Name="Items In Group"
SelectionMode="None"
IsItemClickEnabled="True"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource BannerBackgroundArticleTemplate}"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
</ListView>
<TextBlock
x:Name="NoArticlesTextBlock"
HorizontalAlignment="Center"
VerticalAlignment="center"
Style="{StaticResource HeaderTextBlockStyle}"
TextWrapping="WrapWholeWords"
TextAlignment="Center"/>
</Grid>
</DataTemplate>
</HubSection>
The problem I'm having is that I can't access the TextBlock from the C# code. Is there an easier way to do this?
The problem I'm having is that I can't access the TextBlock from the C# code.
Yes, since the TextBlock is defined inside a DataTemplate, the TextBlock won't be available until the DataTemplate has been applied. Thus, the x:Name attribute won't automatically generate a variable reference in the InitializeComponent method in your *.g.i.cs file. (Read up on XAML Namescopes for more information).
If you want to access it from your code-behind, there are two ways:
The first way is the simplest: you can get a reference to the TextBlock in the sender argument of the Loaded event handler for that TextBlock.
<TextBlock Loaded="NoArticlesTextBlock_Loaded" />
Then in your code-behind:
private TextBlock NoArticlesTextBlock;
private void NoArticlesTextBlock_Loaded(object sender, RoutedEventArgs e)
{
NoArticlesTextBlock = (TextBlock)sender;
}
The second way is to traverse the visual tree manually to locate the element with the required name. This is more suitable for dynamic layouts, or when you have a lot of controls you want to reference that doing the previous way would be too messy. You can achieve it like this:
<Page Loaded="Page_Loaded" ... />
Then in your code-behind:
static DependencyObject FindChildByName(DependencyObject from, string name)
{
int count = VisualTreeHelper.GetChildrenCount(from);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(from, i);
if (child is FrameworkElement && ((FrameworkElement)child).Name == name)
return child;
var result = FindChildByName(child, name);
if (result != null)
return result;
}
return null;
}
private TextBlock NoArticlesTextBlock;
private void Page_Loaded(object sender, RoutedEventArgs e)
{
// Note: No need to start searching from the root (this), we can just start
// from the relevant HubSection or whatever. Make sure your TextBlock has
// x:Name="NoArticlesTextBlock" attribute in the XAML.
NoArticlesTextBlock = (TextBlock)FindChildByName(this, "NoArticlesTextBlock");
}
Jerry Nixon has a good page on his blog about this.
Using Caliburn.Micro for a WinRT application, I would like to control the ZIndex of items displays in an ItemsControl.
When a user taps on an item, it should become the topmost element.
<ItemsControl Background="White" Height="auto" Width="auto" x:Name="Parts"
HorizontalAlignment="Left"
VerticalAlignment="Top"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
The viewmodel bound to the view above contains a property Parts:
private BindableCollection<IPartViewModel> _parts = new BindableCollection<IPartViewModel>();
public BindableCollection<IPartViewModel> Parts
{
get { return _parts; }
set { _parts = value; NotifyOfPropertyChange(() => Parts); }
}
IPartViewModel has different implementations, each with their own View (= custom user controls).
Every implementation of IPartViewModel has a ZIndex property, ready to be bound.
All other bindings (labels, the tapped event, ...) work perfectly, but I cannot figure out what the binding should look like to control the ZIndex.
Many other questions on SO deal with this issue, but none for WinRT.
I ended up achieving this with a custom ItemsControl and overriding the method GetContainerForItemOverride where I return a ContentPresenter with a binding added to the ZIndex property
protected override DependencyObject GetContainerForItemOverride()
{
var cp = new ContentPresenter();
cp.SetBinding(Canvas.ZIndexProperty, new Binding { Path = new PropertyPath("ZIndex") });
return cp;
}
I want to implement auto-complete on a textbox in a Windows 8 UI / Metro UI app using C#/XAML.
At the moment, when the soft / touch keyboard shows, it obscures the auto-complete box. However, on the text box focus, Windows 8 automatically scrolls the entire view up and ensures the text box is in focus.
In reality, all I want is the view to scroll up a little more (in fact, by the height of the auto-complete box).
I realise I can intercept the Showing event of InputPane.GetForCurrentView()
I can set InputPaneVisibilityEventArgs.EnsuredFocusedElementInView to true inside the Showing event fine (so Windows won't try to do anything).... however, how can I invoke the same scrolling functionality that Windows 8 would do, but ask it to scroll a little more!?
Here's the code for the main page:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,200,0,0">
<TextBlock HorizontalAlignment="Center" FontSize="60">App 1</TextBlock>
<TextBlock HorizontalAlignment="Center">Enter text below</TextBlock>
<TextBox HorizontalAlignment="Center" Margin="-10,0,10,0" Width="400" Height="30"/>
<ListBox HorizontalAlignment="Center" Width="400">
<ListBoxItem>Auto complete item 1</ListBoxItem>
<ListBoxItem>Auto complete item 2</ListBoxItem>
<ListBoxItem>Auto complete item 3</ListBoxItem>
<ListBoxItem>Auto complete item 4</ListBoxItem>
<ListBoxItem>Auto complete item 5</ListBoxItem>
</ListBox>
</StackPanel>
</Grid>
If you start up the simulator with the lowest resolution, use the hand to "touch" the textbox, this will bring up the soft keyboard. In the real app, the auto complete list will appear with items as the user enters text.
So in a nutshell, how can I move the screen up a bit more so the user can see the entire autocomplete list?
Bear in mind, in the real app, it'll be worse, as the user may not even notice the autocomplete list appearing "underneath" the keyboard.
I really would appreciate some advice, many thanks!
I have created an AutoCompleteBox for Windows Store apps, the nuget package is available at https://nuget.org/packages/AutoCompleteBoxWinRT
Ok, here is how I would tackle this since I cannot seem to find any way to control the scrolling of the app based on the appearance of the keyboard. I would create a user control that would form the basis for the auto-complete textbox.
<UserControl
x:Class="App6.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App6"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<TextBox x:Name="textBox" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" GotFocus="textBox_GotFocus" LostFocus="textBox_LostFocus" />
<ListBox x:Name="listBox" Height="150" Margin="0,-150,0,0" VerticalAlignment="Top" Visibility="Collapsed"/>
</Grid>
This is an incredibly basic implementation, so you will have to tweak to meet your needs.
Then, I would add the following code-behind to the user control
public sealed partial class MyUserControl1 : UserControl
{
// Rect occludedRect;
bool hasFocus = false;
public MyUserControl1()
{
this.InitializeComponent();
InputPane.GetForCurrentView().Showing += MyUserControl1_Showing;
}
void MyUserControl1_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
if (hasFocus)
{
var occludedRect = args.OccludedRect;
var element = textBox.TransformToVisual(null);
var point = element.TransformPoint(new Point(0, 0));
if (occludedRect.Top < point.Y + textBox.ActualHeight + listBox.ActualHeight)
{
listBox.Margin = new Thickness(0, -listBox.ActualHeight, 0, 0); // Draw above
}
else
{
listBox.Margin = new Thickness(0, textBox.ActualHeight, 0, 0); // draw below
}
}
}
private void textBox_GotFocus(object sender, RoutedEventArgs e)
{
listBox.Visibility = Windows.UI.Xaml.Visibility.Visible;
hasFocus = true;
}
private void textBox_LostFocus(object sender, RoutedEventArgs e)
{
listBox.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
hasFocus = false;
}
}
Next steps would be to expose properties to pass data to be bound to the ListBox. Hard core would be ListBoxItem templating and more, depending on how reusable you wanted it to be.