Word: SyncScrollingSideBySide and ScrollIntoView - c#

One feature of our Word add-in shows two document windows side-by-side. The user can double-click a paragraph in the left-hand document to scroll an associated paragraph in the right-hand document into view. When we do this, we want to re-enable Synchronous Scrolling if it was enabled before the double-click. We're doing something like this:
private void LineUpParagraphs()
{
// Unlock the views so we can scroll them independently.
bool wasSyncEnabled = this.originalDocument.Document.Windows.SyncScrollingSideBySide;
this.originalDocument.Document.Windows.SyncScrollingSideBySide = false;
// Scroll corresponding original paragraph into view.
this.originalDocument.Document.Windows[1].ScrollIntoView(
this.CurrentOriginalParagraph.Range);
// Re-enable synchronous scrolling if it was enabled before.
if (wasSyncEnabled)
{
this.originalDocument.Document.Windows.SyncScrollingSideBySide = true;
}
}
After doing this, the desired range is in view in the original (right-hand for our app) document, but as soon as you scroll either window, the right-hand window jumps back to its original position.
Things we've tried that didn't work:
Set the SyncScrollingSideBySide property on all of the Application windows rather than just one of the two compare documents.
Toggle the property an additional time.
We've resorted to SendKeys to simulate a click on the Synchronous Scrolling button. (If you don't re-enable the sync programatically, then click the button yourself, the right-hand document doesn't jump back to its original position when you scroll). This isn't really an acceptable solution, though--it is inconsistent for example depending on whether our add-in's tab is active. Sometimes it works, sometimes it toggles the sync scrolling an additional time which will annoy the customer. Is there a better way?
Note: The issue occurs when the left-hand document is longer than the right-hand document (the one being scrolled).

Related

Custom OSK: Listen to TextBox Focus

I have written a custom OnScreen Keyboard as an UserControl to have a better control over what the user can type (Alphanumeric/Numpad/Navigation Keys - stuff like that) and to have a better control over the screen layout at design time.
The OSK works by manipulating the text- and selection-properties/functions of a textbox-control.
My main Problem is how to find the right TextBox to inject text into.
My first, naive approach was to register every TextBox I want to use with the OSK Control manually and use the GotFocus/LostFocus of those registered TextBoxes to determine the active control:
public void RegisterInput(TextBox text) {
if (!_listeners.ContainsKey(text)) {
_listeners.Add(text, modes);
text.GotFocus += Input_OnGotFocus;
text.LostFocus += Input_OnLostFocus;
}
}
private void Input_OnLostFocus(object sender, RoutedEventArgs routedEventArgs) {
if (_focused == sender) {
_focused = null;
IsEnabled = false;
UpdateKeyboardMode(); // << Updates Keyboard layout (Alphanumerical vs Numpad) based on focused control
}
}
private void Input_OnGotFocus(object sender, RoutedEventArgs routedEventArgs) {
_focused = (TextBox) sender;
IsEnabled = true;
UpdateKeyboardMode();
Bindings.Update();
}
I work with Focus here, because I need to determine which kind of keyboard (full-size alphanumerical vs. short numpad) to display for each TextBox. The _focused TextBox is then used to directly inject the pressed keys into it. In the constructor of my Page which also contains the OSK-control I would call RegisterInput() with a reference of each and every TextBox I defined on the page. This works just fine — if I have those references.
But now I am working with UserControls. That also removes the TextBoxes out of reach for direct referencing, but I could write some kind of VisualTree-Scan after InitializeComponent() to find all references and call RegisterInput() on each reference I found. If I only need to do this once, it isn't a problem (altough it is still ugly).
One step further - ListBoxes with dynamicly changing contents and DataTemplates. Now I'd need to rescan the whole VisualTree explicitly everytime something changes. But how to detect those changes?
The question is: Can I get an event as soon as $any element in my VisualTree gets/looses focus, without knowing all those elements beforehand (thus replacing RegisterInput() completely)? Or can I listen to changes to the VisualTree to rescan all controls and then call RegisterInput() manually for every TextBox I found?
The goal is to get a handler called everytime a GetFocus/LostFocus event on any TextBox/Control in the UI is raised so that I can update the keyboard to either display a full-sized alphanumerical keyboard (for default textboxes) or a shortened numpad (e.g. for textboxes bound to numerical backing fields).
Alternatively: Is there any other way to inject text and call UpdateKeyboardMode() to update the keyboard layout as soon as the selected textbox changes?
Other options I thought about include:
Build a custom control which derives from a TextBox and let it register itself to the OSK. I'll probably resort to this method, if I don't find any better way. But this will destroy support for 3rd party libraries in which my control is not present and thus does not use the "special magical textbox with osk support".
Don't use events at all. Get the currently focused TextBox with the FocusManager as soon as the user presses a key on my OSK and inject text into the focused instance. Problem with this approach is, that it completely destroys the capability to adapt the OSK to different input types (alphanumerical vs only Numpad), because I cannot determine the keyboard type I need before pressing a key.
Rescan the VisualTree with a timer. Won't do that, thats simply too much of a hack.
Use the OnScreen-Keyboard supplied by Win10 IoT. Two problems: It has no designtime support and is displayed above elements, even if the focused element is directly underneath the keyboard (acceptable if neccessary), but I don't know of a way to change the keyboard "layout" between a full-sized alphanumeric keyboard and a shortened Numpad which only contains numbers and some keys. Also it does not allow to use custom keys (e.g. arrow keys for navigation, custom return key handling).
After a discussion in the chat forum, the actual problem isn't to create a Custom OSK control and use that to interact with the TextBoxs but instead, it's "being bound to use custom control" wrapping a textbox everywhere a OSK needs to be shown.
The Solution would be to listen to the OS-OSK events and when they are triggered, pop up the Custom OSK this ways you won't have to wrap a Textbox in a user control and use that throughout your project.
Link to the Documentation: - respond to the presence of the touch keyboard

Odd behaviour when opening a WPF Window from WinForms

When displaying a WPF window from an Excel addin, I'm encountering odd behaviour whenever I show it with myWindow.Show() rather than myWindow.ShowDialog(). Thus far everything has worked fine when using the latter. However, it would be nice to be able to display a window such that the user can interact with Excel at the same time - i.e. the behaviour I'd expect from Show().
The problem is that controls in my form start acting very oddly quite quickly. ComboBox dropdowns collapse immediately, and textbox input ends up in whatever cell is selected in the Excel worksheet that's active.
I've noticed that with ShowDialog, Snoop is able to attach to my window as well, whereas with Show, I get an error amounting to "Could not find a PresentationSource to attach to". I'm not, however, completely sure if that's related.
Obviously one solution would be to stop directly showing a WPF window from WinForms; I expect the problem to largely go away if I change my window into a UserControl and chuck it into an ElementHost. However, I'd rather avoid that if I can.
Current code (roughly)
public void DoOpenWindow(Office.IRibbonControl button)
{
var myWindow = new myWindow();
// This hasn't addressed the issue, though may be sensible to include:
//ElementHost.EnableModelessKeyboardInterop(myWindow);
// This *also* didn't work, and essentially set my window to
// be always on top of Excel
//var hwSrc = HwndSource.FromVisual(myWindow );
//var ownerHelper = new WindowInteropHelper(myWindow );
//ownerHelper.Owner = (IntPtr)Globals.ThisAddIn.Application.Hwnd;
// with ShowDialog() this works fine...
myWindow .Show();
}
Current thoughts are:
I'm getting window messages from Excel forwarded to myWindow, some of which it isn't expecting.
Excel is intercepting messages meant for my window (keyboard and mouse), which is probably what ElementHost.EnableModelessKeyboardInterop(myWindow) is intended to solve (but either I'm using it wrong, or it's not the whole solution).

Webdriver does not click at the correct coordinate

I am having difficulty with a C# test on a responsive website application. I have four website possibilities. These are two variants of the same code but skinned differently and each variant resizes responsively. My tests use sizes of 1024x768 representing desktop and 420x620 representing mobile. Both desktop tests work flawlessly but one (only one) of the mobile crashes when attempting to click a radio button. I modified my code many times in attempts to find a solution without success; always, three pass but the one mobile crashes. I eventually used the following code to troubleshoot the issue:
public void ClickRadioButton()
{
By element = By.Id("radioButtonID");
IWebElement wait = WaitForElementToAppear(WebDriver, 5000, element);
int x = wait.Location.X;
int y = wait.Location.Y;
wait.Click();
}
With a breakpoint at wait.Click() and examining the coordinate values, wait.Location.X has a value of 52 and wait.Location.Y has a value of 1596. These coordinates are correct for the location of the radio button but wait.click() fails with the message:
Unexpected error. Element is not clickable at point (58, 6). Other element would receive the click:
I don’t understand why wait.Click() is using these coordinates.
Basically, it could select radiobutton because it may be an invisible radiobutton that's no longer visible. If you search for multiple radiobuttons, initiate click events on all radiobuttons found and put an 'error handler' for all the radiobuttons found by system, one of them will click on the radiobutton you are looking for.
Also, if the focus is right, instead of doing a .Click event you should replace with a SendKeys("\n") event.

Implementing Tab-like Navigation model in Windows Phone 8 — How?

I am currently trying to implement a navigation scheme that closely resembles that of the Internet Explorer app on Windows Phone 8.
The IE app can have multiple tabs that the user can switch between. Each of these tabs has its own history. Hitting the Back Button on the phone takes you to the previous page in that tab's Navigation history (Not the PhoneApplicationFrame.BackStack). If there are no previous pages, the back button takes you to the previous opened tab or, if none, exits the app.
Why this is troubling me
Application.RootVisual can only be set once. So you can't have two PhoneApplicationFrames, each with its own BackStack, to swap RootVisual between the two.
You cannot traverse the BackStack (it is a Stack, after all). Can only call GoBack(). Calling GoForward() will throw an Exception.
PhoneApplicationFrame.GoBack() removes entries from the BackStack which can only be added again through the PhoneApplicationFrame.Navigate(...) method. So, manipulating the BackStack is a no-go.
Bright Ideas
Keep a Dictionary<enum, List<string>> which is updated with each call to a custom NavigationService.Navigate(tabTypeEnum, uriString, params). This will keep the Navigation history for each tabType, allowing us to possibly Navigate through the current Tab's history when the BackKeyPress event is handled. Bad thing is, calling Navigate(...) to go to previous pages (instead of GoBack) will add to the BackStack. So requires maintenance that hurts my brain right now.
Create a custom NavigationAwareTabPage : PhoneApplicationPage, which keeps track of its own navigation history and fakes navigation by animating a transition when its Content is changed. The only time we call a true Navigate is when we switch from one tab to another. (I think this is what the IE app does.) And the BackKeyPress would have to look like below.
This:
void RootFrame_BackKeyPress(object sender, CancelEventArgs e)
{
var rootFrame = sender as PhoneApplicationFrame;
if (rootFrame.CanGoBack)
{
// Get the NavigationAwarePage
var navAwarePage = rootFrame.Content as NavigationAwareTabPage;
if(navAwarePage.CanGoBack())
{
// This method "navigates" to the next page
// by changing the navAwarePage.Content
navAwarePage.GoBackToPreviousPage();
e.Cancel = true;
}
}
}
Has anyone been down this road?
All the magic of how ReactiveUI overrides the Back button is here:
https://github.com/reactiveui/ReactiveUI/blob/master/ReactiveUI.Mobile/WP8AutoSuspendApplication.cs#L91
The way that this works in ReactiveUI is that there is a content control named RoutedViewHost that is listening to the Back being signaled (you can do whatever you want in response to the hardware Back button and cancel the default action). ReactiveUI maintains its own ViewModel-based back stack and manipulates that instead of using WP8s, and you never call WP8s navigation methods.
This effectively means that, from WP8's perspective, there is only ever one page in the entire application. WP8 really wants to create that page itself, and it's specified in WMAppManifest.xml.
Don't try to participate in WP8's Frame system, it really wants to work its own way and you won't be able to convince it otherwise.
One last important thing, if you're at the bottom of your back stack, you must allow the default Back action to happen (i.e. what WP8 wanted to do, take you out of the app). Otherwise you'll probably fail Certification and you're Doing It Wrong™.

Changing text of a combobox in a different tab

I have a combo box which I need to mirror in another tab page in a C# winforms based application.
I have perfectly working code for when you select a different item from the drop down list. Unfortunately, however, when I change the Text of a tab that has not been clicked on yet nothing actually happens.
If I first click each tab then everything works as expected.
Now I'm putting this down to some form of lack of initialisation happening first. So I've tried to select each tab in my constructor.
tabControlDataSource.SelectedIndex = 0;
tabControlDataSource.SelectedIndex = 1;
// etc
But this doesn't work.
I've also tried calling tabControlDataSource.SelectTab( 1 ) and still it doesn't work.
Does anyone know how I can force the tab to "initialise"?
Ok, typically I post the question after struggling for an hour and shortly afterwards find the solution.
TabPages are lazily initialised. So they don't fully initialise until they are made visible for the first time.
So i added this code to my constructor:
tabControlDataSource.TabPages[0].Show();
tabControlDataSource.TabPages[1].Show();
tabControlDataSource.TabPages[2].Show();
but this didn't work :(
It occurred to me, however, that the constructor might not be the best place. So I created an event handler for Shown as follows:
private void MainForm_Shown( object sender, EventArgs e )
{
tabControlDataSource.TabPages[0].Show();
tabControlDataSource.TabPages[1].Show();
tabControlDataSource.TabPages[2].Show();
}
And now everything is working!
Perhaps you could also use sort of a "lazy" synchronization (initialization) in this case. Quick robust ideas: polling timer to update content (which will update it once you see tab page), no dependses within second tab (no Changed events for combobox to update second tab content, use original combobox from first tab or rather have it's content underlying in accessable for both comboboxes class, etc), "reinitialization" when tab become visible (at which moment you also init your second combobox)...
Can't be a hour, no way =D

Categories