JavaFX 8 : Combobox with full screen popup - combobox

I currently develop a javafx application designed for windows 8 tablet. I use the JMetro theme (a little customized) for the whole application.
I would like the combobox to behave like on Android, opening a full screen popup list.
I think the better and simpler solution would be to create a new skin and to plug it with -fx-skin css ? After that I "only" have to create my popup, react to click event, and setValue of the combobox. I looked at the source code of ComboBoxListViewSkin but I don't see what to change if I extend it...
I there a build-in solution to display a fullscreen combobox popup ?
Any help appreciated. Thank for reading.

The solution was quite simple, but not evident for a beginner.
public class TouchComboBoxListViewSkin<T> extends ComboBoxListViewSkin<T> {
private ComboBox<T> comboBox;
public TouchComboBoxListViewSkin(ComboBox<T> comboBox) {
super(comboBox);
this.comboBox = comboBox;
}
#Override
public void show() {
//TODO use the accessible protected popup to display the list of items
}
}
and a little of css to use this skin :
.combo-box {
-fx-skin: "path.to.TouchComboBoxListViewSkin";
}
Feel free to comment is this is not the right method.

Related

How to know UI automation client is listening to my WPF app

I want to make my app to be accessible (make my app exposed for screen readers, which are UI automation client, like "Narrator").
I got some ContentControl that when it got keyboard focus, I'm showing a tooltip (taking it from the Tooltip property of this ContentControl). It's a control that used in many ways, for example it can be used like that:
the Content of this ContentControl is a question mark icon image, and the ToolTip is the help text...
Here is a concept code:
class AutoTooltipOnFocus : ContentControl
{
public AutoTooltipOnFocus()
{
this.GotKeyboardFocus += OnGotKeyboardFocus;
}
private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs keyboardFocusChangedEventArgs)
{
bool automationListens = AutomationPeer.ListenerExists(AutomationEvents.AutomationFocusChanged);
if (automationListens)
{
// don't show tooltip because GetNameCore of MyAutoPeer will represent the ToolTip value
return;
}
// show tooltip (by reading the ToolTip value of this AutoTooltipOnFocus)
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new MyAutoPeer(this);
}
}
class MyAutoPeer : FrameworkElementAutomationPeer
{
private AutoTooltipOnFocus _owner;
public MyAutoPeer(AutoTooltipOnFocus owner)
: base(owner)
{
}
protected override string GetNameCore()
{
return GetToolTipValueFromOwner();
}
private string GetToolTipValueFromOwner()
{
// just for the simplicity of the example, I return this:
return ToolTipService.GetToolTip(_owner).ToString();
}
}
Narrator, for example, reads the textual representation of the Content (let's say the property AutomationProperties.Name of the image is set to "help icon") and then says "Tooltip: some help text".
I don't want to count on the tooltip been read by all the screen readers (correct me if I'm wrong thinking some of them don't read Tooltips), so I made my GetNameCore return the ToolTip content so that I know it would be read necessarily, and I prevented the appearance of the tooltip (at OnGotKeyboardFocus handler) in order to prevent double reading of the same help text.
The problem is that: I thought that asking AutomationPeer.ListenerExists(AutomationEvents.AutomationFocusChanged) tells me that UI automation is listening to my app, but when narrator is not running, this method returns "false" and the rest of the times it returns true, so no tooltip appears when no one using screen reader, so I need to know what is the way to indicate whether UI automation client is running and listening to my app.
Maybe there is a workaround by adding some code to my custom AutomationPeer.
Thanks for giving your time!

Dynamically Change Content by clicking RibbonPane using Prism

I'm using Microsoft Ribbon and Prism to develop my application. I have in my main window 2 regions: one for the ribbon and the other to inject a view depending on the button clicked in my ribbon.
That works pretty good, but I would like to have the same functionality if I click a specific ribbon tab.
Has anyone done anything like this using Prism?
As you wanted, here is the code using a Button. This code is in the VM of the Ribbon...when the button is clicked the event goes to OnShowConfiguration. This method load a new View in my GeneralContentRegion and also a new RibbonTab.
private void OnShowConfiguration()
{
loadView(PrismViewsNames.GeneralContentMainView, PrismRegionsNames.ContentRegion);
loadView(PrismViewsNames.GeneralRibbonTab, PrismRegionsNames.RibbonMenuRegion);
}
private void loadView(string viewToShow, string regionWhereToShow)
{
var regionManager = (RegionManager)ServiceLocator.Current.GetInstance<IRegionManager>();
var uri = new Uri(viewToShow, UriKind.Relative);
regionManager.RequestNavigate(regionWhereToShow, uri);
}
Myabe that helps you, Ayyappan Subramanian ;)

Windows Narrator reads the names of all the controls in the window (even hidden ones)

I need to make my application visually impaired friendly... and I am facing this problem: Windows Narrator reads all the controls names in the window despite that some of them are hidden.
I have another app that I used WinForms to write it, and there it works fine.
After looking in the UI Spy I saw that WinForms app is not exposing hidden controls and WPF is exposing all the controls in the window.
Can it be that it's a bug in WPF?
I was having the same problem.
Based on Alexis's answer, I wrote the code bellow. It works for me.
public class MyAutoComplete : RadAutoCompleteBox
{
public MyAutoComplete ()
{
//init stuff here
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new MyAutomationPeer(this);
}
}
internal class MyAutomationPeer : RadAutoCompleteBoxAutomationPeer
{
public MyAutomationPeer(FrameworkElement owner)
: base(owner)
{
}
protected override List<AutomationPeer> GetChildrenCore()
{
return new List<AutomationPeer>();
}
}
If your controls are already in the visual tree, this behavior is the normal one, because UI Automation tree based on the Visual tree. So if you want to prevent of reading unnecessary elements using screen readers, you have to load them on demand.
You can also override the OnCreateAutomationPeer method in controls that contain visible and hidden elements to return your own AutomationPeer. Then you can override the GetChildrenCore method and return modified children collection. To update automation children tree, you need to call the AutomationPeer.ResetChildrenCache() method and the AutomationPeer.RaiseAutomationEvent(AutomationEvents.StructureChanged) one.

ShowDialog() behind the parent window

I am using ShowDialog() with WindowStyle = WindowStyle.SingleBorderWindow; to open a modal window in my WPF (MVVM) application, but it lets me navigate to parent window using the Windows taskbar (Windows 7).
I've found an answer here: WPF and ShowDialog() but it isn't suitable for me because I don't need an "always on top" tool window.
Thanks in advance
Try setting the Owner property of the dialog. That should work.
Window dialog = new Window();
dialog.Owner = mainWindow;
dialog.ShowDialog();
Edit:
I had a similar problem using this with MVVM. You can solve this by using delegates.
public class MainWindowViewModel
{
public delegate void ShowDialogDelegate(string message);
public ShowDialogDelegate ShowDialogCallback;
public void Action()
{
// here you want to show the dialog
ShowDialogDelegate callback = ShowDialogCallback;
if(callback != null)
{
callback("Message");
}
}
}
public class MainWindow
{
public MainWindow()
{
// initialize the ViewModel
MainWindowViewModel viewModel = new MainWindowViewModel();
viewModel.ShowDialogCallback += ShowDialog;
DataContext = viewModel;
}
private void ShowDialog(string message)
{
// show the dialog
}
}
I had this problem but as the Window was being opened from a view model I didn't have a reference to the current window. To get round it I used this code:
var myWindow = new MyWindowType();
myWindow.Owner = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
You can use: myWindow.Owner = Application.Current.MainWindow;
However, this method causes problems if you have three windows open like this:
MainWindow
|
-----> ChildWindow1
|
-----> ChildWindow2
Then setting ChildWindow2.Owner = Application.Current.MainWindow will set the owner of the window to be its grandparent window, not parent window.
When the parent window makes (and shows) the child window, that is where you need to set the owner.
public partial class MainWindow : Window
{
private void openChild()
{
ChildWindow child = new ChildWindow ();
child.Owner = this; // "this" is the parent
child.ShowDialog();
}
}
Aditionally, if you don't want an extra taskbar for all the children... then
<Window x:Class="ChildWindow"
ShowInTaskbar="False" >
</Window>
Much of the reason for the MVVM pattern is so that your interaction logic can be unit tested. For this reason, you should never directly open a window from the ViewModel, or you'll have dialogs popping up in the middle of your unit tests.
Instead, you should raise an event that the View will handle and open a dialog for you. For example, see this article on Interaction Requests: https://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx#sec12
The problem seems to be related to Window.Owner, and indeed if you judge by previous knowledge that you might have of the Win32 API and WinForms, a missing owner would be the typical cause of such a problem, but as many have pointed out, in the case of WPF that's not it. Microsoft keeps changing things to keep things interesting.
In WPF you can have a dialog with a specific owner and you can still have the dialog appear in the taskbar. Because why not. And that's the default behavior. Because why not. Their rationale is that modal dialogs are not kosher anymore, so you should not be using them; you should be using modeless dialogs, which make sense to show as separate taskbar icons, and in any case the user can then decide whether they want to see different app windows as separate icons, or whether they want to see them grouped.
So, they are trying to enforce this policy with complete disregard to anyone who might want to go against their guidelines and create a modal dialog. So, they force you to explicitly state that you do not want a taskbar icon to appear for your dialog.
To fix this problem, do the following in the constructor of your view class:
ShowInTaskbar = false;
(This may happen right after InitializeComponent();
This is equivalent to Xcalibur37's answer, though the way I figure things, since WPF forces you to have both a .cs file and a .xaml file, you might as well put things that are unlikely to change in the .cs file.
Add "ShowInTaskbar" and set it to false.
Even if this post is a bit old, I hope it is OK that I post my solution.
All the above results are known to me and did not exactly yield the desired result.
I am doing it for the other googlers :)
Lets say f2 is your window that you want to display on top of f1 :
f2.Owner = Window.GetWindow(this);
f2.ShowDialog();
That's it , I promise it will not disappear !
HTH
Guy

RTF with Links in a RichTextBox WPF

I am able to load an rtf document in a RichTextBox, but the links that the document contains to some websites are not working.
Anyone have any idea why? Some solution to make the links work?
Best regards,
Paulo Azevedo
WPF by default doesn't understand where you want the links to be displayed, so what's happening is that the Hyperlink class is firing an event, RequestNavigate, and expecting you, the application designer, to cause the actual navigation to occur.
I assume you just want to launch the system configured web browser, so here's all you need to do:
Hook the Hyperlink::RequestNavigate routed event
Call Process.Start with the URL you receive to have the OS launch the browser.
That might look a little something like this:
public class MyWindow : Window
{
public MyWindow()
{
this.InitializeComponent();
this.myRichTextBox.AddHandler(Hyperlink.RequestNavigate, MyWidow.HandleRequestNavigate);
}
private static void HandleRequestNavigate(object sender, RequestNavigateEventArgs args)
{
Process.Start(args.Uri.ToString());
}
}

Resources