WPF 4 keyboard focus: never recieving key events - c#

In WPF 4.0, I can't seem to get any keyboard shortcuts to work if I swap the user control in the window after it's been loaded. A code sample says a thousand words, so here's what I'm doing:
Window window = new Window { Width = 800, Height = 600 };
window.Loaded += delegate
{
editor = new EditorRoot();
window.Content = editor;
};
app.Run(window);
window gets KeyDown events (and routed commands work fine), but editor never gets any keyboard events (nor do any controls within it). I tried:
editor.Loaded += (sender, e) => Keyboard.Focus(editor);
... but that didn't do anything. EditorRoot extends UserControl and has IsFocusable=true Any ideas what's wrong?

And if this does not work - use Dispatcher.BeginInvoke. From my experience - setting focus synchronously doesn't always work. And not only in WPF 4.

Maybe you could try the FocusManager instead of your approach. I use it and it works, you can even use it in XAML:
FocusManager.FocusedElement=editor;

Related

UWP CustomRenderer for Checkbox: Pointer over Checkbox changes style?

I'm working with Xamarin.Forms and I made a CustomRenderer for Checkbox in UWP. When I set all the Checkboxes of my items in the ListView to true by clicking the button "Alle", the Checkboxes are displayed correctly with the check inside the box:
However, if I hover my mouse over the Checkboxes, they immediately change their appearence (the check disappears but it's still selected). In the following screenshot, I moved my cursor over the 3rd - 7th Checkboxes:
This is my overridden OnElementChanged method in the CustomRenderer:
protected override void OnElementChanged(ElementChangedEventArgs<EvaCheckbox> e)
{
base.OnElementChanged(e);
var model = e.NewElement;
if (model == null)
{
return;
}
nativeCheckbox = new CheckBox();
CheckboxPropertyChanged(model, null);
model.PropertyChanged += OnElementPropertyChanged;
nativeCheckbox.Checked += (object sender, Windows.UI.Xaml.RoutedEventArgs eargs) =>
{
model.IsChecked = (bool)nativeCheckbox.IsChecked;
};
nativeCheckbox.Unchecked += (object sender, Windows.UI.Xaml.RoutedEventArgs eargs) =>
{
model.IsChecked = (bool)nativeCheckbox.IsChecked;
};
SetNativeControl(nativeCheckbox);
}
I tried to override the PointerEntered event of nativeCheckbox. It works, for example if I set the model.IsChecked to true on this event, it will be set to true:
nativeCheckbox.PointerEntered += (s, args) =>
{
model.IsChecked = true;
};
But I don't know how to (if even at this place) prevent the checkbox from changing it's appearance when moving the cursor above the Checkbox. Just leaving the triggered event with empty code like this won't change anything about the described behaviour:
nativeCheckbox.PointerEntered += (s, args) => { };
How can I prevent the Checkbox from changing it's appearance when I move my cursor over it?
Update:
I've created a sample project for this issue. You can find the repository here: https://github.com/Zure1/CustomCheckbox
It has the exact same described behavior. In the following screenshot I pressed the button "All" on the bottom of the screen and then the checkboxes look like correct with a check inside of them:
After moving the mouse cursor over the bottom 3 checkboxes, their change their appearance:
Information: I'm debugging on my desktop (Windows 10). I don't know if this issue exists on WinPhone. Just in case you're wondering why my checkboxes are red: My system color in Windows is red.
This is a tricky one as I have been struggling with this issue for a while, I'll try my best to answer this.
TL;DR: It's caused by ViewCell.
The issue comes down to Xamarin Forms ListView and ViewCell.
I haven't been able to track down the cause yet for many months and the way I get around this issue is by refreshing the ListView every time a change happens forcing a redraw of the entire ListView which can really impact performance.
My educated guess on what the cause could be is the rendering code for the ViewCell is missing something.
As for your particular issue, I have created a CheckBoxCell which you can use to display a list of checkboxes with a title. I forked your project and made the changes.
This will display something similar to what you are trying to achieve and doesn't have rendering issues so will be a good starting point. You are able to customize this to display images and the like but you'll have to do that in the platform-specific layout code.
Please note that I have only created the code for UWP and that should be enough to get you going for the other platforms.
I hope this helps somewhat.

Closing a form that was opened by ShowDialog()

I have a winform application where I've written my own little color picker that will only display system colours. It's basically a TableLayoutPanel with a bunch of smaller panels added to it, to which I just set the background color.
Pretty simple:
Now I'm opening this form for with:
using (frmColourWindow colourPicker = new frmColourWindow (Cursor.Position.X, Cursor.Position.Y, findingPriority))
{
colourPicker.ShowDialog();
if (!colourPicker.SelectedColor.IsEmpty)
{
pnlColor.BackColor = colourPicker._SelectedColor;
}
}
and closing it with by setting the DialogResult when the user has clicked on one of the color panels.
This all works pretty good, the only thing I can not manage to get right is by closing the form when it loses focus (E.g. when the user clicks somewhere else or starts typing). I've had a look at the Deactivate, LostFocus, and Leave events. Just can't seem to get those events to fire when I want them to. Maybe I'm missing something obvious?
As I mentioned in the comments, when using the ShowDialog() you can only use the Dialog you have opened and thus it never looses focus, so event like Deactivate, LostFocus and Leave won't work.
You need to use the Show() command to use those event to close the opened Form.
As to addressing the issue you pointed out in the comments about assigning the color to the object. you can do the following:
Declare a public Property
Color SelectedColor {get; private set; }
In your color picker and change your using statement to this:
var colourPicker = new frmColourWindow (Cursor.Position.X, Cursor.Position.Y, findingPriority);
colourPicker.Closed += (o, args) => { pnlColor.BackColor = colourPicker.SelectedColor };
colourPicker.Show();
This is of course just one of many possible solutions for that.
You can achieve this by displaying the form with the Show() method and then using the Form.Deactivate event.

Suppress WaitCursor for WinForms WebBrowser control

Consider the following simple WinForms form with a textbox and a webbrowser control. Whenever the textbox content changes, the text is pushed to the browser:
public class MainForm : Form
{
public MainForm()
{
var browser = new WebBrowser() { Dock = DockStyle.Fill };
var textbox = new TextBox() { Dock = DockStyle.Fill, Multiline = true };
var splitter = new SplitContainer() { Dock = DockStyle.Fill };
splitter.Panel1.Controls.Add(textbox);
splitter.Panel2.Controls.Add(browser);
this.Controls.Add(splitter);
textbox.TextChanged += delegate { browser.DocumentText = textbox.Text; };
textbox.Text = "<b>hello world</b>";
}
}
(I am doing something like this in my DownMarker code to build a Markdown editor with Stackoverflow's MarkdownSharp library.)
This works fine, except that the WebBrowser control insists on showing the wait cursor whenever DocumentText is set - even if updating the browser content takes only a few milliseconds. This results in mouse cursor flicker when typing in the textbox.
Is there any way to supress these mouse cursor changes? I already considered rate-limiting the DocumentText updates, but I find that the occasional flicker during an update is still annoying and I would prefer instant updates.
edit: Hans' answer pointed me in the right direction. Changing the TextChanged event handler to this seems to work without cursor flicker:
textbox.TextChanged +=
delegate
{
if (browser.Document == null)
{
browser.DocumentText = "<html><body></body></html>";
}
while ((browser.Document == null)
|| (browser.Document.Body == null))
{
Application.DoEvents();
}
browser.Document.Body.InnerHtml = textbox.Text;
};
edit2: the above still shows the wait cursor when the page is made heavier, e.g. by adding images. This might be fixable be doing more fine grained updates of just the html elements that change, but that is obviously much more complex.
Assigning the DocumentText property is a Big Deal, WebBrowser treats it like a navigation command. It can't tell the difference. Which normally takes time, hundreds of milliseconds, enough for it to justify displaying the wait cursor.
A very different approach would be to load a dummy document and alter the DOM through the Document property. That's pretty common in web pages, Ajax and javascript and what-not. No wait cursor for those. Not so sure if that will still fit your editing model, I'd guess at you wanting to load a dummy HTML document with a empty <body> and change the body content.
Should work. Back-up plan is an Update! button. Which would also avoid trying to render half-finished and thus broken HTML.

How to show non-interactive, auto-hiding notification popup message with Windows Forms in c#?

Using Windows Forms, .NET 3.5 framework, language: c#
I would like to show a popup window for 1 second to notify users of actions that are performed. For example, when I copy a file X I want to show a notification like "Copied file X to File X-copy". Should be shown for a second, then autohide.
You can use a timer. Something along the lines of the following where ShowFloating does the initial display and HideFloating does, you know.
public void ShowFloatingForXMilliSeconds(int milliSeconds) {
ShowFloating();
if (_autoOffTimer == null) {
_autoOffTimer = new System.Timers.Timer();
_autoOffTimer.Elapsed += OnAutoOffTimerElapsed;
_autoOffTimer.SynchronizingObject = this;
}
_autoOffTimer.Interval = milliSeconds;
_autoOffTimer.Enabled = true;
}
void OnAutoOffTimerElapsed(Object sender, System.Timers.ElapsedEventArgs ea) {
if ((_autoOffTimer != null) && _autoOffTimer.Enabled) {
_autoOffTimer.Enabled = false;
HideFloating();
}
}
Also detach the timer handler and dispose the timer in Dispose.
This topic will help you to make topmost window without stealing focus from currently active window.
To complete your solution, in simple case you need to add a timer on your form to make sure the form auto-closes after 1 second and locate your notification window properly (you probably want it in the bottom right part of the screen? - that's a simple arithmetic exercise).
For more advanced solution, you should create NotificationManager class and manage lifetime of your notification message forms there.
Dispite the answers given. I think a message that pops up is somewhat not user friendly. What about using a statusbar link? It's not that evasive (and you can show the progress)

Paragraph.BringIntoView() works only when focused

I am working on a text editor that is based on RichEditBox. I have implemented functionality "Go to line" which eventually resolves to
TextPointer.Paragraph.BringIntoView();
Along with this I also set the caret position.
What I found out is that BringIntoView only works when I click on the RichEditBox first (focus it). Otherwise it seems to get ignored. I can see that the caret position has been adjusted by the code around BringIntoView though.
Does anybody know what is the reason/nature of that problem? How can I overcome it?
Found a workaround for this, not sure if it will work in a pure WPF environment, in my case I'm running WPF inside a mainly Windows Forms solution using WPF UserControls where needed.
Instead of invoking BringIntoFocus() immediately, defer it to a later moment by adding it to a queue that gets handled by a timer. For example:
System.Windows.Forms.Timer DeferredActionTimer = new System.Windows.Forms.Timer() { Interval = 200 };
Queue<Action> DeferredActions = new Queue<Action>();
void DeferredActionTimer_Tick(object sender, EventArgs e) {
while(DeferredActions.Count > 0) {
Action act = DeferredActions.Dequeue();
act();
}
}
In your forms constructor, or in the OnLoad event add:
DeferredActionTimer.Tick += new EventHandler(DeferredActionTimer_Tick);
DeferredActionTimer.Enabled = true;
Finally, instead of calling TextPointer.Paragraph.BringIntoView(); directly, call it like this:
DeferredActions.Enqueue(() => TextPointer.Paragraph.BringIntoView());
Note that the Windows Forms timer kicks events off in the main thread (via the message pump loop). If you have to use another timer you need a bit of extra code. I'd recommend you to use System.Timers.Timer rather than the System.Threading.Timer (it's a little more thread-safe). You would also have to wrap the action in a Dispatcher.Invoke structure. In my case, the WinForms timer works like a charm.
Can't you just give the RichTextBox(?) focus first then, using Keyboard.Focus(richTextBox) or richTextBox.Focus()?

Categories