Bring button to front on Windows Phone UI - c#

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();
}
}

Related

How to make the CommandBar open towards the bottom of the screen?

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.

Issue designing code to manage objects

I have a C# winform which displays snapshots from a camera. The form has four PictureBox controls and When an image is taken it is placed into pictureBox1 and the previous images are bumped along to 2,3 and 4. Under each picture box is also a label which displays the time stamp and the order number (each image is given a number 1-4, that stays with it until it is bumped off in which the newest image takes that number). Currently I am doing it like below. However I feel this is very inefficient and will cause me problems later on if I decide to add key down events to change the backcolors of some of the labels (to indicate status).
Does anyone know of a better way to do this?
if (count > 4)
{
count = 0
}
count ++;
pictureBox4.image = pictureBox3.image;
pictureBox3.image = pictureBox2.image;
pictureBox2.image = pictureBox1.image;
pictureBox1.imagelocation = (#"http://192.168.X.X/image.cgi")
label4.Text =label3.text;
label3.text = label2.text;
label2.text = label1.text;
label1.text = count.ToString()+ " " + datetime.now();
I could create a new Control, most likely a Panel that contains all of these UI elements in it (PictureBox, Label, anything else). Have a constructor for your Control that takes a URL of the image. Load the image into your PictureBox, and set your label.
Have all of that logic encapsulated in your Control. So when a new one is added, you just create the new Control, and remove the last one in your row, and move the .Left properties of the 3 remaining to their new locations.
Don't forget to implement IDisposable, and Dispose of the Controls when they're removed to free up the resources of displaying the images.
EDIT
If it's not there already, you can provide references back to the top Control in each of your inner Controls (PictureBox and Label), and even to your main form in your top Control by passing this as a parameter in the constructor as well and setting a private member variable inside those controls. That way, when someone clicks on the PictureBox, you can go up the line to this.Parent and get your outer Control. You could even have that reference to your Main Form (hopefully a Panel in there that holds your 4 of these objects). That could be this.Parent.Parent to call a method on there. (I think there's already a public property of Parent on all Controls, so that's fine.)
A little bit of quick coding:
You have your main Form (mainForm). In there is a Panel (picturePanel). picturePanel holds your 4 new Panels, which we'll call customPanel. Each customPanel has a PictureBox (imageBox), and Label (fileNameLabel).
Your customPanel constructor would look like this:
public partial class CustomPanel : Panel {
private PictureBox _imageBox;
private Label _fileNameLabel;
public CustomPanel() {} // This is most likely tied into the code behind file. Sorry, It's been a while since I've done WinForms
public CustomPanel(string imageFileName, Panel parent) {
// Set the source for the PictureBox.
// Set the Text of the label.
_parent = parent;
}
}
Continue with this down the line through the PictureBox and Label. Then in your events, you have your PictureBox work up the chain. To find picturePanel. If you want to get really fancy, you could have that derive from Panel as well and just add a public property that handles all of the switching around of which customPanel sent the message.
So down in your PictureBox event, you could have a line of code like this:
if (this.Parent.Parent is PicturePanel) {
((PicturePanel)this.Parent.Parent).RemovePicture(this.Parent);
}

c# Close a form opened from and instance class from the main form that created the class

I'm having a difficulty in sizing my form!
I dynamically create buttons on a form and need to know if they are all fully visible or if I need to grow the form and in what direction to make all the buttons fully visible.
I don't want to use the autosize property as I need to control the layout.
So how do I tell if a dynamically created controls bounds are within that of the form?
thanks
This a .Net 4 classic forms app.
When you add the button to the controls collection, to see if it is visible check the contains on the forms bounds - Form.Bounds.Contains(button.Bounds));. If that returns false then you need grow your form. Here is some basic code to do the form growing, it will not necessarily produce the prettiest output and is not necessarily the best way, just written to give you a quick idea of how it could be accomplished.
// Add the control
form.Controls.Add(button);
var formBounds = form.Bounds;
var controlBounds = button.Bounds;
if (!formBounds.Contains(controlBounds))
{
formBounds.Left = Math.Min(controlBounds.Left, formBounds.Left);
formBounds.Right = Math.Max(controlBounds.Right, formBounds.Right);
// Do similar for top and bottom this will ensure your button is visible
form.Bounds = formBounds;
}
Can you add the button, can't you compare the Width of the container vs the Left + Width properties of the newly added button?

Scroll a ListBox's VirtualizingStackPanel with buttons

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.

Bring Winforms control to front

Are there any other methods of bringing a control to the front other than control.BringToFront()?
I have series of labels on a user control and when I try to bring one of them to front it is not working. I have even looped through all the controls and sent them all the back except for the one I am interested in and it doesn't change a thing.
Here is the method where a label is added to the user control
private void AddUserLabel()
{
var field = new UserLabel();
userContainer.Controls.Add(field);
SendLabelsToBack(); // Send All labels to back
userContainer.Controls[field.FieldName].BringToFront();
}
Here is the method that sends all of them to the back.
private void SendLabelsToBack()
{
foreach (var label in userContainer.Controls);
label.SendToBack();
}
Yeah, there's another way. The Controls.SetChildIndex() also changes Z-order. The one with index 0 is the one on top. Doesn't buy you anything though, BringToFront() uses this method.
Your SendLabelsToBack() method as given cannot work, it will also send the label to added to the back. But your next statement fixes that again.
Okay, that doesn't work, which means the BringToFront() method doesn't get executed. Look in the Output window for a "first chance exception" notification. As written, your SendLabelsToBack() will cause an exception if the user control contains any control other than a UserLabel. Also, set a breakpoint after the BringToFront() call and check the value of userContainer.Controls[0].Name when it breaks.
Controls' z-index is per-container.
If you call BringToFront on a control that is inside a container (such as a Panel), it will not bring the container to the front.
Therefore, the control will only go in front of other controls in that container.
To see what containers your controls are in, you can use the Document Outline pane in the View menu.
EDIT: Your userContainer control is probably behind a different control.
Have you tried Invalidate() after BringToFront()? BringToFront does not raise the Paint event
try this:
private void SendLabelsToBack()
{
foreach (var label in userContainer.Controls)
{
label.SendToBack();
label.Invalidate();
}
}
I think you just need to change your last line:
userContainer.Controls[field.FieldName].BringToFront();
to this:
userContainer.Controls[field.Name].BringToFront();
When you use a string as the indexer for the Controls collection, it goes by the Name property of the control (not the FieldName property).
Since you're just trying to bring the most recently-added control to the top, this would also work:
userContainer.Controls[userContainer.Controls.Count - 1].BringToFront();
From my experience looks like windows puts all controls belonging to one graphic container(pane, group box...etc) in a software collection. The collection is ordered by child index which is a property of every control in that container.
The trick is that children with the same index can and do exists. In this case windows will paint those children ordered relative to others but between them it will paint them in the reverse order they had been added to the container.
Long story short: for one container-you need to make sure controls have different indexes by changing ALL NOT just SOME of the indexes when you want to change the z-order. For example:
foreach (Control newControl in TopControl.Controls)
{
TopControl.Controls.SetChildIndex(newControl,indexlogic(newControl));
}
where indexLogic(newControl ) is your method of calculation of the index of particular control.

Categories