I have a layout that I want to show as a popup window (used as a custom options menu) while in a fragment of a viewpager. Therefore, when the "Options" button is clicked, I do the following:
public void onOptionsButtonClicked(int buttonHeight)
{
LayoutInflater optionsLayoutInflater = (LayoutInflater)Context.GetSystemService(Context.LayoutInflaterService);
int popupWidth = ViewGroup.LayoutParams.MatchParent;
int popupHeight = ViewGroup.LayoutParams.WrapContent;
View layout = optionsLayoutInflater.Inflate(Resource.Layout.TrackOptions, null);
int popupYOffset = (85 + buttonHeight) * -1;
var popup = new PopupWindow(context);
popup.Focusable = true;
popup.Width = popupWidth;
popup.Height = popupHeight;
popup.ContentView = layout;
popup.SetBackgroundDrawable(new BitmapDrawable());
popup.OutsideTouchable = true;
popup.ShowAsDropDown(view, 0, popupYOffset);
}
And this works as I want, visually that is. Meaning, I click the button and I do see the layout popup as a popup window with all of my options. HOWEVER, none of the buttons work. I put a breakpoint in the class that should be associated the the layout and noticed that onCreateView never gets called, therefore, none of the buttons and associated click event handlers are ever wired up. So, I know why it is not working. However, I don't know how to fix it. I think it is because, while I inflate the view, I am never actually creating the fragment. I have done fragementmanager transactions to replace a fragment in other parts of my project and I know that would probably do it, however, this is a different case as I am trying to do a popup window.
Thanks!
Mike
Fragment is attach in activity so you can try it in onActivityCreated(Bundle) method
Related
I'm having trouble with navigation outside of the typical use cases for navigation controllers and tabbar controllers. Here's a drawing of a simplified version. (real version has a TabBarController that feeds into 9 NavControllers)
In my Home Nav Controller, there's a table view where the user could select a row and that should navigate them to a particular Events Detail View Controller. At that point, the user should be able to navigate back to the Events TableView Controller to see the list of events or use the TabBar to navigate to another section.
So far with my code I can push the correct detail view controller and select the correct index of the tabbar but it only works the first time:
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
tableView.DeselectRow(indexPath, true);
var eventsDetailView = new EventsDetailController(eventPosts[indexPath.Row]);
//loop through ViewControllers array in case the user has set a custom tabbar order via the More Tab
foreach (UIViewController viewC in tbController.ViewControllers)
{
UINavigationController navController = viewC as UINavigationController;
if (navController.TabBarItem.Tag.Equals(9))
{
navController.PushViewController(eventsDetailView, false);
tbController.SelectedIndex = 9;
}
}
}
After the user has navigated to the events detail view controller, if they then:
travel to the Home ViewController via the TabBar
select a new TableRow to navigate to a different Events detail view controller
... then the same previous events detail view shows up. It doesn't matter which row the user selects in the Home View Controller. The initial detail view controller will always be the same one to be presented.
Any help pointing me in the right direction would be greatly appreciated!
Solution:
In my understanding, what you want is :
HomePageController --> EventDetailPage --> EvevtTableViewControll
So in the first step, you could push to EventDetailPage in HomePageController:
this.NavigationController.PushViewController(new HomeDetailUIViewController(), true);
Then, in your EventDetailPage, you can customize a back button, for example:
UIBarButtonItem backBtn = new UIBarButtonItem();
backBtn.Title = "back";
backBtn.Style = UIBarButtonItemStyle.Plain;
this.NavigationItem.LeftBarButtonItem = backBtn;
backBtn.Clicked += (sender, e) =>
{
// 1 here is an example, it should be the index of your EvevtTableViewControll
NavigationController.TabBarController.SelectedIndex = 1;
NavigationController.PopToRootViewController(true);
};
Set the NavigationController.TabBarController.SelectedIndex=1 first to make sure EvevtTableViewControll will show after you back from EvevtDetailViewControll, then your PopToRootViewController to back to the EvevtTableViewControll.
Try it and let me know if you have any problem.
First, a little overview of how my current UI looks like:
Note that other than the stuff in the ToolStripControlHost, everything else is standard WinForms.
In short, I want to have something similar to the ToolStripControlHost but I need it "pinned" to the bottom of the menu, mostly so that when there is a lot of items, it is not scrolled like the rest of the menu items.
After some searching around I came to the conclusion that maybe customizing painting might be the solution, don't know if this is the case though.
Here's some sample code, but I'm not sure how useful it is:
public ToolStripDropDownButtonContainer(ToolStripDropDownButton button)
{
this.UIControl = button.GetCurrentParent();
this.Button = button;
if (this.Button.Tag == null)
{
this.Button.Tag = true;
this.Button.DropDownDirection = ToolStripDropDownDirection.AboveLeft;
ToolStripDropDownMenu menu = (ToolStripDropDownMenu)this.Button.DropDown;
menu.SuspendLayout();
try
{
menu.BackColor = Color.White;
menu.ShowImageMargin = false;
menu.ShowCheckMargin = false;
menu.AutoSize = true;
menu.Margin = Padding.Empty;
menu.Padding = Padding.Empty;
menu.GripMargin = Padding.Empty;
menu.GripStyle = ToolStripGripStyle.Hidden;
menu.MinimumSize = new Size(310, 0);
menu.MaximumSize = menu.MinimumSize;
// TODO pin panel (or some control) to the bottom-side of the menu
}
finally
{
menu.ResumeLayout();
}
}
}
My solution to this problem is to completely avoid using the normal menu control containment system and instead have the menu show one FlowLayoutPanel which instead contains my menu items.
This involved having to add some various trickeries to get the panel to behave nicely with the UI. The added advantage of this approach is more flexibility and control over the system.
On the downside, I noticed a degrade in performance when I have a tonne of sub-items, but I'll investigate this separately.
I have an application that has a nice flyout animation when the users selects an item in the listbox. When the user clicks the back button, a flyin animation is used. You can see the example here:
I am using the same animation code as this sample. everything works fine until the clicked item is partially off the bottom or top of the screen. The flyout animation will happen properly but when the user returns to the list, the listbox auto scrolls the selected item up (or down) to be fully in view. The flyin animation however returns the text to the original (before auto scroll happened) location. You may need to download the working sample to fully see what I am on about.
The question I have is - is there a way to disable this auto-scroll action. The built in apps like messaging and email don't scroll a partially visible item into view when selected.
Thanks
I don't know how to disable auto-scroll action, but I have a quick fix for that code:
In class ItemFlyInAndOutAnimations
add a field
private FrameworkElement _element; //let's consider the line is 266
in public void ItemFlyIn() make changes:
public void ItemFlyIn()
{
if (_popupCanvas.Children.Count != 2)
return;
_popup.IsOpen = true;
_backgroundMask.Opacity = 0.0;
Image animatedImage = _popupCanvas.Children[1] as Image;
var sb = new Storyboard();
var rootFame = Application.Current.RootVisual as FrameworkElement; //new line
var targetElementPosition = _element.GetRelativePosition(rootFame); //new line
// animate the X position
var db = CreateDoubleAnimation(targetElementPosition.X - 100, targetElementPosition.X,
new SineEase(),
_targetElementClone, Canvas.LeftProperty, _flyInSpeed); //reference changed!
sb.Children.Add(db);
// animate the Y position
db = CreateDoubleAnimation(targetElementPosition.Y - 50, targetElementPosition.Y,
new SineEase(),
_targetElementClone, Canvas.TopProperty, _flyInSpeed); //reference changed!
sb.Children.Add(db);
//other code is the same
in public void ItemFlyOut(FrameworkElement element, Action action)
after this line
_targetElementPosition = element.GetRelativePosition(rootElement);
add this one:
_element = element;
What have I done:
In this code I save the reference to animated UI element and update it's position on back animation.
You'd better to test this code, but it seems to be ok.
so I figured I'm making just a stupid mistake here. In the first of what will be many controls, I need to either show a balloon tooltip when a bool is true or not show them when the bool is false. I know that ShowAlways is not what I need to modify and I've tried various solutions already. Does anyone spot the problem? The bool is set by a checked dropdown item in a Help Menu Strip Item.
It will open with the application with the correct display, but as soon as I check that option to show it, it always shows there after.
public void changeBalloonProperties(bool boolSet)
{
ToolTip helpDeskInfoButtonToolTip = new ToolTip();
if (boolSet)
{
helpDeskInfoButtonToolTip.ToolTipTitle = "HelpDesk Information Button";
helpDeskInfoButtonToolTip.UseFading = true;
helpDeskInfoButtonToolTip.UseAnimation = true;
helpDeskInfoButtonToolTip.IsBalloon = true;
helpDeskInfoButtonToolTip.ShowAlways = true;
helpDeskInfoButtonToolTip.AutoPopDelay = 5000;
helpDeskInfoButtonToolTip.InitialDelay = 1000;
helpDeskInfoButtonToolTip.ReshowDelay = 500;
helpDeskInfoButtonToolTip.SetToolTip(helpDeskButton, "Click to launch HelpDesk user info page in default browser.");
}
else
{
helpDeskInfoButtonToolTip.RemoveAll();
}
}
You are creating a new ToolTip instance each time the changeBalloonProperties is called so the code isn't removing the caption associated with the original ToolTip that was used with the helpDeskButton. Try moving the ToolTip declaration outside of your changeBalloonProperties method so the same ToolTip object is used with RemoveAll().
Also note you can use that same ToolTip object to add captions for multiple controls (as shown in the sample here) and it's probably better to set helpDeskInfoButtonToolTip.Active = false to disable them all at once instead of setting and removing the captions (and other properties) each time you toggle.
I am using a ToolStripDropDown control to implement the dropdown portion of a custom ComboBox-like control. In order to be visually appealing, I am imposing a MaximumSize on the dropdown and manually specifying the width of each ToolStripButton within it - the result is a popup which is the same width as the control that activates it, with a cap on the height of the height of the dropdown portion.
Example (simplified):
ToolStripDropDown dropDown = new ToolStripDropDown();
dropDown.MaximumSize = new Size(200, 100);
dropDown.RenderMode = ToolStripRenderMode.System;
dropDown.AutoSize = true;
for (int i = 0; i < 50; i++) {
ToolStripButton dropDownItem = (ToolStripButton)dropDown.Items.Add("Item " + i);
dropDownItem.AutoSize = false;
dropDownItem.Size = new Size(200, 20);
}
dropDown.Show(owningControl, new Point(0, owningControl.Height - 1));
As you can see, the constraints on the popup's size are applied, however the up/down scroll buttons are not displayed and there seems to be no way to make them appear. There do not appear to be any methods or properties within ToolStripDropDown regarding the scrolling offset or a mechanism to scroll a particular item into view (such as EnsureVisible() on ListViewItem).
How, then, can I get the dropdown to scroll? Any method would be sufficient, be it a scroll bar, scroll buttons or even the mouse-wheel.
(Incidentally, I have tried many times to make similar controls using a Form for the dropdown portion - despite trying dozens of solutions to prevent the popup from stealing focus or gaining focus when its controls are clicked, this seems to be a dead end. I have also ruled out using ToolStripControlHost, whose hosted control can still take focus away from the form that opened it.)
Finally cracked this one. It occurred to me that ContextMenuStrip and ToolStripDropDownMenu are capable of the auto-scrolling behaviour which their base class, ToolStripDropDown, cannot provide. Initially, I avoided these alternative controls because they usually add a wide margin. This can be removed via ShowImageMargin and ShowCheckMargin. Even after doing this, a small (approx 5px) margin remains. This can be removed by overriding the DefaultPadding property:
public class MyDropDown : ToolStripDropDownMenu {
protected override Padding DefaultPadding {
get { return Padding.Empty; }
}
public MyDropDown() {
ShowImageMargin = ShowCheckMargin = false;
RenderMode = ToolStripRenderMode.System;
MaximumSize = new Size(200, 150);
}
}
// adding items and calling Show() remains the same as in the question
This results in a popup window which can contain any type of ToolStrip item, enforces MaximumSize, has no margin and, most importantly, does not steal focus and cannot receive focus.
This is your nemesis:
internal virtual bool RequiresScrollButtons
{
get
{
return false;
}
set
{
}
}
It is internal, you cannot override it. You can revive your approach of using a Form by fixing the focus stealing behavior. Paste this into the form class:
protected override bool ShowWithoutActivation
{
get { return true; }
}