I want to have tab-like interface where I have multiple buttons (tabs) and when the user press one of the button I show corresponding container and hide other ones.
Something like:
<!-- Buttons -->
<StackPanel VerticalAlignment="Stretch" Grid.Column="0">
<Button
Style="{StaticResource DetailSectionButton}"
Content="info" Click="Button_Click"/>
<Button
Style="{StaticResource DetailSectionButton}"
Content="map" Click="Button_Click2"/>
<Button
Style="{StaticResource DetailSectionButton}"
Content="attachment" Click="Button_Click3"/>
</StackPanel>
<!-- Info -->
<ScrollViewer x:Name="SecInfo" Grid.Column="1" Visibility="Collapsed" ...
<!-- Map -->
<Map:MapControl ZoomLevel="6" x:Name="SecMap" Grid.Column="1" Visibility="Collapsed" ...
<!-- Attachments -->
<StackPanel x:Name="SecAttachments" Grid.Column="1" Visibility="Collapsed">
Code:
private void Button_Click(object sender, RoutedEventArgs e)
{
SecInfo.Visibility = Visibility.Visible;
SecMap.Visibility = Visibility.Collapsed;
SecAttachments.Visibility = Visibility.Collapsed;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
SecInfo.Visibility = Visibility.Collapsed;
SecMap.Visibility = Visibility.Collapsed;
SecAttachments.Visibility = Visibility.Visible;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
SecInfo.Visibility = Visibility.Collapsed;
SecMap.Visibility = Visibility.Visible;
SecAttachments.Visibility = Visibility.Collapsed;
}
Is it a good way to do it or I need to use something different in XAML for this ?
What you have presented should work as you expect it to.
But:
I would strongly recommend that you use some MVVM framework (like mvvmlight and there are other out there) and bindings in you application. If you invest some time to understand the concepts behind your life will become easier later.
Invest some time and understand platform specifics what you already know from desktop development might not apply to this platform (eg: TabControl).
For the specific design that you presented from the top of my head I would consider using HubControl with customization as you presented some buttons to navigate to pages but only if you need rapid access to them and changing page would require a lot of scrolling.
Related
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.
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.
I am developing my first app on windows phone 8. In this app I have a search box.For the search box I need to provide the background text as search city(as a hint text for the user) along with the search symbol/ search button within the box,Can I know the best way to do this as I am pretty new in this field.
Thanks in Advance.
Try this for watermark(hint text) on TextBox and search button at the top.
xaml
<Grid x:Name="ContentPanel" Grid.Row="0" Margin="12,0,12,0" Width="440" Height="100">
<TextBox Width="440" Name="txtSearch" Height="153" LostFocus="TextBox_LostFocus" GotFocus="TextBox_GotFocus" Text="This is whatever search..." TextWrapping="Wrap" Foreground="DarkGray" FontSize="18"></TextBox>
<Button x:Name="btnSearch" Click="btnSearch_Click" HorizontalAlignment="Right" Height="70" Margin="0,0,10,0">
<Button.Content>
<Image Source="Images/yoursearchIcon.png"></Image>
</Button.Content>
</Button>
</Grid>
code behind
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
if (txtSearch.Text.Trim() == "")
{
txtSearch.Foreground = new SolidColorBrush(Colors.DarkGray);
txtSearch.Text = "This is whatever search...";
}
}
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
if (txtSearch.Text == "This is whatever search...")
{
txtSearch.Foreground = new SolidColorBrush(Colors.Black);
txtSearch.Text = "";
}
}
Hope this helps
You could use the AutoCompleteBox where you could implement the search functionality too.
Have a look over here
http://www.geekchamp.com/articles/autocompletebox-for-wp7-in-depth
Hope it helps!
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.
I have a list of customers with various pieces of information. I have a list box with their names. When I select an entry I see more information about the customer on the screen. I want to "Navigate To" another screen when clicking on the user's name with more of their information. I can't figure out how to pass information about the entry to the next screen to accomplish this.
Here is the list box that the user chooses from to begin with.
<ListBox x:Name="scheduleListBox"
ItemTemplate="{DynamicResource ItemTemplate}"
ItemsSource="{Binding Collection}"
Margin="8,8,8,0"
Style="{DynamicResource ListBox-Sketch}"
Height="154"
VerticalAlignment="Top"/>
Here is the TextBlock that could be clicked to go to the other screen. It is changed based on what the user selected from the ListBox.
<TextBlock Text="{Binding Customer}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="150" Margin="104,0,0,0"
Style="{DynamicResource BasicTextBlock-Sketch}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<pi:NavigateToScreenAction TargetScreen="V02Screens.Customer_Status"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
I'm kind of hoping that there is something I can do in Expression Blend 4 or in the XAML.
In Windows 8, you can pass the entire object to the receiving page.
Like this:
// main page
private void ListBox_SelectionChanged_1
(object sender, SelectionChangedEventArgs e)
{
var _Item = (sender as ListBox).SelectedItem;
Frame.Navigate(typeof(MainPage), _Item);
}
// detail page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.DataContext = e.Parameter;
}
In WPF & SL, you can save reference to the SelectedItem in your View Model.
// main page
private void ListBox_SelectionChanged_1
(object sender, SelectionChangedEventArgs e)
{
var _Item = (sender as ListBox).SelectedItem;
MyModel.SelectedItem = _Item;
// TODO: navigate
}
// detail page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.DataContext = MyModel.SelectedItem;
}
I hope this helps.
In WPF you can supply an object to the Navigate command which contains anything you want, including whatever data you might want to show on the next page. Then on the target page (the one you navigate to), you have to handle the load completed event.
In your first page you might navigate with...
this.NavigationService.Navigate( somePage, someContainerObject );
Then you might retrieve it on somePage with...
// Don't forget to subscribe to the event!
this.NavigationService.LoadCompleted += new LoadCompletedEventHandler(container_LoadCompleted);
...
void container_LoadCOmpleted( object sender, NavigationEventArgs e)
{
if( e.ExtraData != null )
// cast e.ExtraData and use it
}