I'm having what's probabily a stupid doubt, but I really don't know how to fix this thing.
I have a complex UI with many items inside it (a SplitView with other stuff inside it, then a Frame which holds a Page, where I have a Grid and finally my CommandBar).
When I tap on the "..." button, the CommandBar opens towards the top of the window, and it also actually covers part of the UI outside of the Frame where its parent Page is located (I don't event know how's that possible).
I tried setting the VerticalAlignment property of both the CommandBar, the parent Grid, the Page etc... to Top, but the CommandBar still opens towards the top of the screen.
Is there a way to have it open towards the bottom, just like the CommandBar in the built in Weather or Photo app? Am I missing a setting/property here?
Thank you for your help!
Sergio
Edit: just to be clear, the basic structure for my page is something like this:
RootContent > ... > Frame > Page > Grid > CommandBar
I can't put the CommandBar inside the Page.TopAppBar as if I do that the CommandBar gets placed outside of my Page and covers the top of my UI. I need the CommandBar to be place inside the Page.
The CommandBar relies on VisualStates to control this part of its dimensions and animations this makes it easy to use a custom visual state manager to intercept the state change calls and replace all OpenUp calls with OpenDown ones.
public class OpenDownCommandBarVisualStateManager : VisualStateManager
{
protected override bool GoToStateCore(Control control, FrameworkElement templateRoot, string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
{
//replace OpenUp state change with OpenDown one and continue as normal
if(!string.IsNullOrWhiteSpace(stateName) && stateName.EndsWith("OpenUp"))
{
stateName = stateName.Substring(0, stateName.Length - 6) + "OpenDown";
}
return base.GoToStateCore(control, templateRoot, stateName, group, state, useTransitions);
}
}
public class OpenDownCommandBar : CommandBar
{
public OpenDownCommandBar()
{
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var layoutRoot = GetTemplateChild("LayoutRoot") as Grid;
if(layoutRoot != null)
{
VisualStateManager.SetCustomVisualStateManager(layoutRoot, new OpenDownCommandBarVisualStateManager());
}
}
}
Then just use the new OpenDownCommandBar instead of the normal one.
<myControls:OpenDownCommandBar>...</myControls:OpenDownCommandBar>
How are you defining your command bar? There are two ways to do so:
<Page.BottomAppBar>
<CommandBar>
....
</CommandBar>
</Page.BottomAppBar>
Or on the contrary..
<Page.TopAppBar>
<CommandBar>
....
</CommandBar>
</Page.TopAppBar>
In your case you would want to use the former and make sure your appbar is not inside any other containers.
You're using the commandbar for something it wasn't intended for. It's supposed to cover page content when displayed.
If you can't change the way something behaves (as in this case) then the alternative would be a different control (there isn't anything I'm aware of which would give you exactly what you want) or make your own.
Related
Current Situation
I have made a xamarin forms cross-platform app which has a tabbed Page with an infinite scroll listView.
The listView is populated in increments of 10 items whenever the last item appears.
The normal behaviour
Usually when we tap the top bar of the tabbed page (the bar containing the tabbed page's Title) for the first time (if we are not viewing the tab at that moment), the app will switch to view that page. Which is fine.
When we tap the top bar for the second time (when tapping the top bar of current viewing tabbed page), nothing happens (unlike twitter, u can tap to scroll to the top )
My Problem
I want to be able to make the listView to scroll back to the top (to the first Item on the list) when the top bar is tapped (something like how twitter does in its android app) while still maintaining all the already loaded items in my listView.
Any idea on how to make that top bar react to the tap to scroll the listView back to the top?
The TabbedPage exposes a CurrentPageChanged event (or you can override OnCurrentPageChanged) that fires only when the selected tab changes, so you'll need to subscribe to that if you want to scroll when the user changes tabs. It doesn't seem like this is needed, but just in case...
Xamarin.Forms doesn't have a built-in event that fires when the already-selected tab is selected a second time. You can make that happen with custom renderers though, by subclassing Xamarin's TabbedPage renderers. I wrote it up here and have a working Xamarin.Forms solution for iOS, Android, and UWP here.
You don't mention the platforms, so assuming you want iOS and Android, the core bits are below.
iOS custom renderer
public class MainTabPageRenderer : TabbedRenderer
{
private UIKit.UITabBarItem _prevItem;
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if (SelectedIndex < TabBar.Items.Length)
_prevItem = TabBar.Items[SelectedIndex];
}
public override void ItemSelected(UIKit.UITabBar tabbar,
UIKit.UITabBarItem item)
{
if (_prevItem == item && Element is MainPage)
{
// the same tab was selected a second time, so do something
}
_prevItem = item;
}
}
Android custom renderer
public class MainTabPageRenderer : TabbedPageRenderer, TabLayout.IOnTabSelectedListener
{
void TabLayout.IOnTabSelectedListener.OnTabReselected(TabLayout.Tab tab)
{
if (Element is MainPage)
{
// the same tab was selected a second time, so do something
}
}
}
Once you have captured that event, use the ListView.ScrollTo method to scroll to the top.
You should try something like this for scrolling up
ListViewName.ScrollTo(yourobject,ScrollToPosition.Start, true);
// true means boolean for animated.
I hope this help you
I'm trying to create an application that would use multiple windows. For starters I'd like it to have a splash screen window and a "main window". I came along this article: http://southworks.com/blog/2010/01/26/creating-a-multi-shell-application-in-prism-v2/ however it doesn't seem to suit my needs. Author is creating 2 windows at the same time, also showing both right from the start. What I want to do is to create this splash screen window (with some nice loading indicators) and only when it's underlying logic will complete its tasks, I want to show another window
protected override DependencyObject CreateShell() {
//return Container.Resolve<MainShell>();
return Container.Resolve<SplashScreenShell>();
}
protected override void InitializeShell() {
base.InitializeShell();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
}
Another issue is that when I use this code, all my modules (so even those used only by MainShell) are getting loaded and initialized, and that's totally not what I want. Mainly because Prism looks for RegionName that is not present on SplashScreenShell (but is present on the second shell).
I'm using Prism 6.1.0 and .NET 4.6.
Why not just show your splash screen before you call MainWindow.Show? Just show it as ShowDialog to stop the bootstrapper form continuing to process until you close your splash screen.
protected override void InitializeShell()
{
var sc = new SplashScreen();
sc.ShowDialog();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
}
The good patern is to stick to one window for the whole application. My proposal is to create splash screen as UserControl and then kind of mess around with visibility.
Your MainView may be looking as follows
<Grid>
<ContentControl Content="{Binding CurrentViewModel}"/>
<userControl:SplashScreen/>
</Grid>
At this point your splash screen covers view and once the view is loaded you make the SplashScreen invisible. In order to do so create another class which will expose boolean property like IsVisible, and method Show/Hide for making splash screen visible and invisible respectively. Subsequently, you set SplashScreen's DataContext to that class, bind Visibility property to IsVisible and make use of BooleanToVisibilityConverter, provided by WPF by default. For appearance sake, you can set splash sreen opacity to, for instance 0.75, so that it would show through splash screen displaying some destination view simultaneously.
Whenever you want to show splash screen you invoke Show method, within method you set IsVisible to true, PropertyChanged event is raised and changes are reflected at view. As a result Visibility is set to true and Splash screen shows up on the top covering everything else.
If you follow these steps you should acquire similar outcome. Message being displayed can be explicitly adjusted as well, as a replacement for hardcoded "Loading".
On the main page of my app I have a grid with 6 x 4 columns and rows of buttons.
I want to move one of these buttons to the middle and then scale it larger using RadControls by Telerik.
I can do this easily however when I do the button is shown behind all the other buttons on the grid and I can't seem to make it come to the front.
Any help would be much appreciated.
The order that items were added to a panel/grid determines what control is above another. Looking around it looks like you have two options:
Change the Canvas.ZIndex for the button you want to be on top.
Yes it seems odd as there is no canvas, but it works for any panel or grid.
Remove and re-add the child from the parent grid so that it was last. I found a nice snippet of code here posted by "CleverCoder" : http://forums.silverlight.net/post/63607.aspx
//Originally posted by CleverCode - http://forums.silverlight.net/post/63607.aspx
public static void PushToTop(this FrameworkElement element)
{
if (element == null) throw new ArgumentNullException("element");
var parentPanel = element.Parent as Panel;
if (parentPanel != null)
{
// relocate the framework element to be the last in the list (which makes it "above" everything else)
parentPanel.Children.Remove(element);
parentPanel.Children.Add(element);
parentPanel.UpdateLayout();
}
}
When I add krypton items to my form, they appear over the top of the others, how can I make it so that I can put something behind the other items?
Assuming you're using the Winform designer, you can right click a control and select 'Bring to Front' or 'Send to Back' from the context menu to change the control's 'z-order.'
The order of control appearing inside their parrent container is controlled by Z-Index.
Right click control in the designer. Select "Bring ro front" from the context menu.
If you doing it programmtiacly. All control in winforms environment have two methods : BringToFront() and SendToBack(). You can call it to setup z-index of controls.
If you want to specify Z-Index explicitly you may use this workaround:
public static class ControlExtension
{
public static void SetControlZIndex(this Control ctrl, int z)
{
ctrl.Parent.Controls.SetChildIndex(ctrl, z);
}
}
Usage:
button1.SetControlZIndex(10);
I have a Listbox displaying 5 items at a time, horizontally. I want to implement a 'Previous' and 'Next' button that when clicked, will display the previous set of 5, or next set of 5 items. I am not displaying the horizontal scroll bar, as I don't want a user to navigate with that.
Is there already some functionality implemented so I can do this, or do I need to write code to calculate what items I'm displaying, etc, in the button's click events?
Thanks in advance!
You can use the built-in ScrollViewer.PageUp() and ScrollViewer.PageDown() commands, like this:
public void ShowNextPage()
{
InvokeOnScrollViewer(listBox, viewer => viewer.PageDown());
}
public void ShowPriorPage()
{
InvokeOnScrollViewer(listBox, viewer => viewer.PageUp());
}
public void InvokeOnScrollViewer(ItemsControl control, Action<ScrollViewer> action)
{
for(Visual vis = control as Visual; VisualTreeHelper.GetChildCount(vis)!=0; vis = VisualTreeHelper.GetChild(vis, 0))
if(vis is ScrollViewer)
{
Action((ScrollViewer)vis);
break;
}
}
How it works: InvokeOnScrollViewer scans down the visual tree until it finds the ScrollViewer, then invokes the given action on it, which is either PageUp() or PageDown().
When your ItemsPanel is a StackPanel (of either orientation, virtualizing or not), ScrollViewer.PageUp() moves back by one viewport and ScrollViewer.PageDown() moves forward by one viewport. In other words, if your ListBox shows five items then these commands move it by five items.
Look at ListBox.ScrollIntoView() method.