UWP MenuFlyout in Application.Resources - how to assign events? - c#

I'm relatively new to UWP, but I have good WPF background.
What I need is a simple context menu for the application. User "right taps" anywhere, menu opens, user taps an item and things happen.
It looks basic and simple. First I add MenuFlyout element to my Application.Resources. Then, in MainPage I just show it with ShowAt method. Works.
To my greatest surprise when I tried to add events to menu items, VS told me it's invalid, events cannot be added in App.xaml.
So here's my assignment (in App.xaml.cs):
MainContextMenu = (MenuFlyout)Resources["MainContextMenu"];
MainContextMenu.Items.First(i => i.Name == "NavToCalibration").Tapped += NavToCalibration_Tapped;
The problem is - the handler is never called. I run my app, open the menu, click on the item and nothing happens. The assigned method is not called. What am I doing wrong? Why the handler is not called?
The assignment IS executed on application launch.
I'm also surprised I haven't been able to find any example or tutorial on doing such a simple and basic thing.
There is a good reason I use app-wide context menu instead of other controls. The app displays test images, it has to be full-screen (or maximized window) without interfering elements.
Now I will try to move my menu to the page resources, my pages will have different context menus anyway. But I'm really curious what's wrong in MenuFlyout defined in App.xaml?
Whoa. I tried to move my MenuFlyout to MainPage. I was able to assign Tapped event in XAML. And it also is not triggered! Now I'm completely lost. Any ideas?

Related

limiting tabbing to a custom in-window message box

I have made a custom MessageBox for my application and it launches as a UserControl. I have two buttons inside it and I would like to allow users to press Tab to switch between Buttons. However, since it's a UserControl overlaying the content, Pressing tab more than twice makes the focus go in the background on elements that aren't supposed to be tabbed at.
I can't figure out a good idea how to prevent this, I've thought of making a method that will select all elements and make their IsTabStop values to false and then restore them later, but I think that would be more of a problem then a solution.
Is there a way around this to limit tabbing only to the UserControl?
I would also appreciate advice on working with the message box.. the whole messagebox is an async function that has an infinitive loop until the answer is given. Is there another way to stop the application until one of the message box options was selected?
Crowcoder's reference has lead to correct MSDN page where I found my solution:
dialog = new UCMessageBox("Are you sure you want to exit the application?", MBType.YesNo);
AppMessageBox.Children.Add(dialog);
KeyboardNavigation.SetTabNavigation(dialog, KeyboardNavigationMode.Cycle);
The key was to call .SetTabNavigation function and direct it to my dialog (custom UserControl for the message box) and setting the KeyboardNavigationMode to Cycle.
After closing the UC rest of the application continued normally regarding navigation.

Accessing SplitView control from a different page than it's host - C# XAML Windows 10 UWP

Pre-warning, I'm new to C# and XAML, but I'm really enjoying Windows 10 UWP apps. I've got a question on how to appropriately handle a SplitView.
I've got a Main Page, in which I have a SplitView control. In the SplitView Content, I've added a Frame for navigation to other pages. I want to add the Hamburger button on the child page to open the SplitView on the Main Page, but I can't access the SplitView control from the child page. How can I make the SplitView control accessible so that the hamburger button within the sub-page can open the SplitView pane?
The alternative is to add a header in the Main Page and have a static hamburger button there, but I don't like this option as it makes handling the text header content more difficult. Another is to copy the SplitView to each page. I don't want to do this either.
Any advice would be fantastic! Thank you.
I would highly recommend you take your alternative option of including the hamburger button in the main page. Users always expect it to be in the same location every time and changing this approach will probably result in a bad user experience.
You also don't want to be repeating code and thus you don't want to recreate the button on every page as well as any additional functionality like the open/close commands.
Rather than referencing elements from one page to another, a better practice is to keep things loosely coupled. This can be done with a messenger plugin which sends an event from one page to the other which can give it instructions on what you want to do. That way the other page only has to listen for the event instead of holding strong references. To streamline some of this process you could inherit from a base class which implements the messenger functionality.
That would provide a solution to your button and your header text situations but setting them up is out of the scope of this question. Depending on the size of you app and your goals, you might like to look into existing frameworks which helps in designing maintainable apps. A good Mvvm framework I would recommend checking out is MvvmCross which also cross platform and contains a messenger plugin.
Good luck with your app.
I found that solution :
In the MainPage, in your SplitView pane button method, add a SplitView reference as parameter in Navigate() :
private void SlitViewPaneButton_Tapped(object sender, TappedRoutedEventArgs e)
{
var frame = contentFrame;
Page page = frame?.Content as Page;
if (page?.GetType() != typeof(ChildPage))
{
frame.Navigate(typeof(ChildPage), SplitViewName);
}
}
In your ChildPage.xaml.cs :
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SplitView sv = new SplitView();
sv = e.Parameter as NavigateControls;
}
You can now do sv.IsPaneOpen = false, in your ChildFrame code.
Note : if you want to pass several Controls, create a Class with these Controls as variables, and use an instance as parameter.
As stated above, it is better to keep your hamburger button in your main page for a couple of reasons. One is the consistency mentioned above. Second, you would have to recreate the hamburger button in each of your content pages instead of just once in the MainPage.xaml. Additionally, keep in mind, there are different kinds of interactions with the SplitView menu in terms of how it pops in and out and how it is displayed, all listed below.
Inline – When the menu pane is opened, it pushes the content over. When it’s closed, the content goes back to its original location
Overlay – When the menu pane is opened, it lays on top of the content. When it’s closed, it is invisible.
Compact Overlay – When the menu pane is opened, it lays on top of the content. When it’s closed, the pane is still visible in Compact Mode.
Compact Inline – When the menu pane is opened, it pushes the content over. When it’s closed, the content goes back to its original position but the pane is still visible in Compact Mode.
You can also see a quick intro into the SplitView here.
http://jamesqquick.com/windows-10-splitview-intro/

Registering for UIAutomation structure change events

I am working on an application that is monitoring a given application for automation events. Currently, I am working specifically with structure change events on a WPF application that I developed.
public void MonitorStructureChangedEvents(AutomationElement element)
{
Automation.AddStructureChangedEventHandler(element, TreeScope.Subtree, OnStructureChanged);
}
where in this case, element is the root AutomationElement of the Application (its main window). The WPF application in question is just a Window with a grid view and various controls (text boxes, checkboxes, buttons, etc). It is a test app I have developed specifically for testing UIAutomation events.
I am using a Unit Test project to test these events, and I am launching the application in the ClassInitialize decorated method. I do not register for StructureChanged events until the application is launched and I have located it via WMI in my TestMethod. The application is spawned as a new process.
However, upon registering for structure changed events, I receive structure changed events for all the elements in the main window of my application, even though the WPF application is effectively idling. I have buttons in the main window that add and remove controls to test StructureChanged events, and it does work, however I am unsure why when I initially register, all of the elements fire a structure changed event.
Edit: After further testing, I notice that these events are fired as soon as I either click on the application window, or hover over a button. It then fires a structure changed event for every element in the app one time. After it is done, it no longer fires a structure changed event if I hover over a button, or click on the application (even after clicking on another application or the desktop)
Edit2: After further testing, I believe I figured out the cause of the issue, but no solution yet. When I try to TreeWalker.RawViewWalker.GetFirstChild(rootApplicationElement) I receive a null. It appears that the AutomationElement that I am acquiring has no children cached. Once I add the StructureChanged event handler on the element, the TreeWalker method works, and I get a valid element. It seems when I activate the window after this, that's when it realizes that it now has all these new child elements. Is there a way to cache all the descendants of the rootApplicationElement so that before I add the event handler, I can walk the entire subtree?
I was able to solve the problem by using the following method
CacheRequest request = new CacheRequest();
request.TreeScope = TreeScope.Element | TreeScope.Descendants;
using (request.Activate())
{
rootApplicationElement = AutomationElement.RootElement.FindAll(TreeScope.Children,
new PropertyCondition(AutomationElementIdentifiers.ProcessIdProperty, ApplicationInstance.ProcessId))[0];
}
I do not advise that people acquire a root element in this fashion, since if an application has more than one window you will get more than one result, but this was tailored to a specific testing need.

How to create a custom .NET ComboBox with the textbox active during edit

I'm trying to implement my own combobox like a lot of folks before me. What I want to accomplish is a combobox that filters and highlights items in the dropdown list while the user is typing in the combo textbox. The behaviour of a regular combobox after you click the arrow button is that the dropdown pops up and the focus stays in the textbox. This way you can start typing right away.
In order to customize the dropdown control you have to implement something from scratch. Most of the implementations that I've come across use either a Form or a ToolStripDropDown to host the custom control. Both are toplevel controls which means that you have to somehow close it yourself if the user clicks somewhere outside the dropdown. ToolStripDropDown does this automatically if AutoClose is true, but also somehow steals the combo textbox the focus on show if it is activated. A Form must be shown using ShowWithoutActivation() in order to prevent it from stealing the focus.
The problem is that the dropdown does never close unless I click somewhere within the dropdown and therefore activate it.
Another twist is that the combobox control is supposted to be hosted in an MFC application instead of a pure WinForms app.
The dropdown never being activated (gaining focus) is the main complication here. Otherwise you could just use the forms Deactivate event to hide it. The way to go here is to add an IMessageFilter to the WinForms application and catch mouse click messages. The message filter then determines whether the click took place outisde of the dropdown and closes it. If you are creating a WinForms application you are done.
Some extra work is necessary if you are for example in a MFC application hosting the control in a MFC window. In that case your IMessageFilter is useless. The reason is that the WinForms Application is never being run and therefore the event pump is never being invoked. Instead the MFC message pump does all the message handling. To solve this issue I've come accross a neat trick to activate the Application message pump in MFC applications.
In MFC applications there is usually an equivalent to the WinForms Application which is CWinApp (or CWinAppEx). The trick is to tap into the PreTranslateMessage method and serve the WinForms Application message pump before (or after) the MFC message pump:
BOOL CWinApp::PreTranslateMessage(MSG* pMsg)
{
if (FilterWindowsFormsMessages(pMsg))
{
return TRUE;
}
return CWinApp::PreTranslateMessage(pMsg);
}
BOOL CWinApp::FilterWindowsFormsMessages(MSG* pMsg)
{
Message message = Message::Create(IntPtr(pMsg->hwnd),
int(pMsg->message),
IntPtr((void*)pMsg->wParam),
IntPtr((void*)pMsg->wParam));
if (Application::FilterMessage(message))
{
return TRUE;
}
return FALSE;
}
This way the registered IMessageFilters are being served and everything works fine.

How to make a touchable notice top bar in windows phone?

How to make a touchable notice top bar in windows phone ?
I am new to C# and windows phone world.So may be my question has a simple
way to solve,but I google a lot ,and didn't work out.
here is my purpose: I have a timer running throughout my app,it request a
service for notice info every one hour, and show a "notice bar" on the top of
screen.
it is easy to get the information ,but when I want to show them to the Page,
here is my problem:
1.
I used system tray to show my info.
It works,but then I found there is no touch or click event for Progress
Indication bar.
I even add an event to Touch.FrameReported in App.xaml.cs , but still ,
when i touch the system tray area, the event doesn't fire.
2.
Then I want to use a Dynamic way to achieve it: add a text block to the
current page
I got the current page handler ,but case I only know the current page
handler's type is PhoneApplicationPage, I can't get my Root UI element
(all my page has a root element named "LayoutRoot")
And when I try to use reflect method to get the "LayoutRoot" property,
the return value is null.
The code looks like this :
Type type = PhoneApplicationPageHandler.getType()<
//I checked,the type is my page's type
type.getProperty("LayoutRoot") or type.getField("LayoutRoot")
//they all return null
BTW: LayoutRoot is a grid, and it is described in my page's .xmal file.
Now My option is to make all my page inherit a defalut page ,in this page ,I will
implement a method to fulfill my second way to simulate a "touchable top bar".
but I think this coding is ugly .
So, can anyone tell me :
1.how to add touch event to a SystemTray
or
2.how to get a handler of an ui element which is described in xaml, while I only have a PhoneApplicationPage type handler of that page.
You may use
1) a toast prompt described here http://windowsphonegeek.com/articles/WP7-Toast-Prompt-in-depth
2)or shell toast described here http://www.c-sharpcorner.com/UploadFile/ae35ca/working-with-toast-notification-in%C2%A0windows-phone-7/ according to what suits your requirement the best. 3)You may also create a custom control which you may place on the top on your mainPage and handle its tap event accordingly.

Categories

Resources