keep focus in a WPF combo box in an addin - c#

I have a combobox in a Word addin. The contents of the combobox are often long enough to drape over Word's Zoom slider-bar control. However, selecting an item directly over the zoom control (which is hidden from view) causes the zoom control to get focus, close the combobox, and change your zoom setting! The selection in the combobox is untouched.
How can I make the combo box keep focus and change the selected value to the item (over the zoom bar) selected? Thanks...

I've run into this same issue with WPF, and it looks like it has something to do with the way Word is handling events from child windows. Whenever the dropdown list (or probably any other "popup" control like a context menu) is drawn over one of Word's windows, it gets a bit greedy and assumes you're clicking on the underlying window.
I don't know a whole lot about how messaging/events works in Windows and I haven't had time to figure out the best way to address the problem, but based on a post somewhere about creating borderless windows I tried modifying the window styles of the WinForms user control as follows (windows style constants from http://www.pinvoke.net/default.aspx/Constants/Window%20styles.html):
protected override CreateParams CreateParams
{
get
{
CreateParams p = base.CreateParams;
if (!DesignMode)
{
unchecked
{
p.Style = (int)(WindowStyles.WS_VISIBLE |
WindowStyles.WS_POPUP |
WindowStyles.WS_CLIPSIBLINGS |
WindowStyles.WS_CLIPCHILDREN);
}
}
return p;
}
}
Curiously (or maybe not so curiously for people that are more familiar with Windows messages), the dropdown DOES respond to keyboard events (e.g. click to pop up the list, then use the keyboard to select an item).
Functionally there doesn't seem to be a problem with the above code...but I'm not sure what the ramifications are of saying the user control is a popup instead of a child.
Another post that relates to this is WPF ComboBox doesn't stay open when used in a Task Pane.

Related

Is it possible to focus a control in a form that is unfocusable via WS_CHILD style?

I've created a drop-down control similar to a ComboBox, where on the click of a button a 'dropdown' form will appear below the button and the user will be able to select an option from a ListBox. The dropdown form itself is unfocusable, so the parent form never loses focus. It all works perfectly as intended, but my problem is that I would like to be use any type of control in this dropdown form. Any control that requires focus to function (e.g. a TextBox) won't work because it will be unable to gain focus since the dropdown form is unfocusable.
I am using this code here for the dropdown form:
protected override CreateParams CreateParams
{
get
{
CreateParams ret = base.CreateParams;
ret.Style = (int)Flags.WindowStyles.WS_CHILD;
ret.ExStyle |= (int)Flags.WindowStyles.WS_EX_NOACTIVATE | (int)Flags.WindowStyles.WS_EX_TOOLWINDOW;
ret.X = this.Location.X;
ret.Y = this.Location.Y;
return ret;
}
}
Which I sourced from here:
https://www.codeproject.com/Articles/71808/Creating-a-Form-That-Doesn-t-Take-Focus
I tried manually setting a dropdown control's parent to the root form, but this causes it not to be drawn.
I'd like to know if there's some kind of solution to allow selection of these controls contained in the dropdown despite the form itself being unselectable. Perhaps a windows message that I can process to circumvent focus logic?
I ended up not using the CreateParams override, and instead simply used protected override bool ShowWithoutActivation => true; with a borderless form.
Seems to work well enough. Some of the benefits of not focusing controls such as selection borders and highlights had to be addressed case by case, but otherwise the looks the same with added functionality.

Is it possible to disable a control but still receive events for that control?

In windows forms I have a simple TextBox:
TextBox textBox = new TextBox() { Text = "text" };
textBox.Enabled = false;
textBox.MouseEnter += (object sender, EventArgs e) =>
{
MessageBox.Show("MOUSE ENTERED"); // this never fires if the control is disabled.
};
I want to disable the users ability to interact with the control and I want the control to be styled as a disabled control. But I also want to receive MouseEnter,MouseLeave, and Click events from the control so that I can change the background cover of the control on hover and respond to clicks on the control.
But as I have just discovered if you disable a windows forms control it disabled the events as well. I know with some effort I can accomplish the same thing by checking mouse coordinates globally but it would be a lot nicer if I could just have it disabled but still receive events for it. Is that possible?
Enabled doesn't really do anything in Windows Forms itself. It is a property of windows controls in general that a disabled window doesn't receive input messages (such as mouse events and keyboard events). So no, there is no way for you to disable a control and still receive those messages. Windows just don't work that way on Windows. It's not the TextBox control filtering those messages away - they don't come in the first place.
TextBox is a great wrapper around a windows common control. When you do something like tbx.Text = "Hello";, the TextBox just sends a message to that common control, saying "change the text to Hello". If you want to change that, you need to make the control essentially from scratch. You can make some hack that reverts whatever the common control does as response to a mouse event, but these usually don't work very well and tend to break down in unexpected ways.
In practice, what you really want is probably to tweak either the way ReadOnly behaves (e.g. disabling focus as well as making the control read only, but that's again just a dirty hack), or replace the TextBox with a control that can either be a control or a label - allowing you to switch between the two. If you want the text box to stop behaving as a text box, stop it from being a text box. Problem solved :)
I'd still reconsider using ReadOnly, though. Are you sure the user would not want to select text in the text box and copy it somewhere else? Or change the reading order?

WPF Ribbon collapse and expand programmatically

With the latest (October 2010) WPF Ribbon libraries, there exists a menu item to minimize/maximize (or collapse/expand, if you prefer) the ribbon control.
Does anyone know if there's also a way to hook into the events that control this behaviour so that it could be controlled programmatically from separate UI?
Or, better yet, is there a way to get a collapse/expand button to display in the ribbon like the 2010 Office apps do?
You can use the boolean property IsMinimized on the Ribbon class to show/hide the ribbon itself. It is a dependency property, so you can bind to its value to support the scenarios you describe.
As far as I know, the default template does not have a show/hide button, like Office does, but it shouldn't be too hard to modify the template (using Blend) to add one.
If what you need is know when the bar gets minimized (this happens when you double click a tab header) you could hook to the IsMinimizedChanged event, but er.. it is missing.
Hopefully it is a DependencyProperty so you can successfully hook to any DependencyProperty change this way:
DependencyPropertyDescriptor.FromProperty(Ribbon.IsMinimizedProperty, typeof(Ribbon))
.AddValueChanged(ribbon, (o, args) => /* your code here */);
What I wanted to do (and hence got here) is to prevent it from minimizing when double clicking the header so I ended up using this code:
DependencyPropertyDescriptor.FromProperty(Ribbon.IsMinimizedProperty, typeof(Ribbon))
.AddValueChanged(ribbon, (o, args) => ribbon.IsMinimized = false);
Is not so fancy but gets the job done.
Add a toggle button(simple button and set its content to v or ^ depending upon the operation requested) and then you can use ContentControl in button click to fulfill your requirement:
ContentControl contentControl = FindVisualChildataBankyName<ContentControl>(rbnName, "mainItemsPresenterHost");
contentControl.Visibility = System.Windows.Visibility.Collapsed;
Use contentControl.Visibility = System.Windows.Visibility.Visible; in order to maximize the ribbon

System.Windows.Forms.Trackbar - how to prevent user from dragging the slider?

Is there some way to (temporarily) prevent user from changing the value of TrackBar by dragging the slider? Only way I found is to set Enabled property to false but it also greys out the trackbar.
Edit:
Since I´m getting more answers about why shouldn't I do it rather than how it's possible to do it, I decided to explain why I would like to do it.
I'm not using it to allow user adjust value of some application property, but to display and control progress of some action. Imagine for example your favourite media player - it probably contains some control (I'd call it trackbar but English is not my native language so it's maybe wrong)
that displays what part of movie it's currently playing, but also allows you to control it - move back or forward in time and watch the different part.
I use the trackbar in exactly this way - I don't know any other component that would be better (Progressbar won't allow me changing the "position"). It's working fine,
the only thing I'd like to do is not to allow user to "use the trackbar unless the movie is paused".
For this exact reason I've used trackbar component many times in Delphi 6, but when it was disabled it didn't grey out and in my opinion it worked fine. That's why I asked
here if it's possible to achieve the same effect in C#.
The best way would be to set the Enabled property to false, as you rightly pointed out it greys out the track bar too.
Greying out the controls is a windows standard for saying "You cannot use this control at the moment", just imagine you were presented with some controls that was not grayed out where disabled, it would be a very hit and miss affair trying them all to see which is enabled and which isn't.
If you really want to prevent changes without using the Enabled property one possible alternative is to use the ValueChanged event of the TrackBar
private void trackBar1_ValueChanged(object sender, EventArgs e)
{
// Code here to restore the original value
}
If you wanted to be ambitious (or overzealous), you could create a Transparent Panel control to overlay the TrackBar thereby preventing the user from interacting with it, i.e.
public class TransparentPanel : System.Windows.Forms.Panel
{
private const int WS_EX_TRANSPARENT = 0x00000020;
protected override CreateParams CreateParams
{
get
{
CreateParams transparentParams = base.CreateParams;
transparentParams.ExStyle |= WS_EX_TRANSPARENT;
return transparentParams;
}
}
protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
{
// Do Nothing
}
}
Add this control to your form and then position it over the TrackBar, i.e.
transparentPanel.Location = trackBar1.Location;
transparentPanel.Size = trackBar1.Size;
Then you can hide it when you want to allow user interaction.
As Xander pointed out, having a trackbar that looks perfectly normal but can't actually be used is a good way to drive your users crazy!
If you're worried about the trackbar looking "inactive", you might try another way of displaying the data it represents, like a label. That way when you disable the trackbar, you're only indicating that the editing of the value is unavailable.

Retain focus on a UI element, but click a button on a different dialog. WPF C#

I am developing a touchscreen friendly app that also includes a virtual keyboard. My virtual keyboard is in its own window, allowing it to be moved around. The problem is that when I click on a key on the keyboard the text box on the main application window no longer has focus. The switch from the main application being the active window to the keyboard dialog being the active window means that any field on the main window no longer has focus. How can I get around this?
I tried setting the keyboard window as not focusable. Though this is probably good to set, it did not solve my problem.
You could just return focus to the original window asynchronousely:
public static void BackgroundFocus(this UIElement el)
{
Action a = () => el.Focus();
el.Dispatcher.BeginInvoke(DispatcherPriority.Background, a);
}
But this is not ideal, because the original window caption would flicker when losing focus...
Why don't you use Popup instead?
Check out the function SetForegroundWindow() ,
I have used this long time back some where in my project
May be this may help you
Using a Popup, as already suggested, seems like a good solution. As for your custom window, try setting the Window.ShowActivated to false.

Categories

Resources