C# Excessive Repainting of WebView2 Control after Applying NativeWinAPI Styles - c#

Having experiences various forms of flickering and graphical glitches, I searched online for possible solution. The only thing that worked straight away was accepted solution using NativeWinAPI from post just below:
Avoid Flickering in Windows Forms?
Inserting this code in the main form of the application and keeping handle for 'this' practically eliminated every issue I had with graphics.
At least until I included a web browser (WebView2 Control). This control along side with the code from the post causes the control itself to constantly repaint itself. This in turn causes graphical issues within entire User Control that is parent to the WebView2. Other controls flicker in and out, which is super annoying and unpleasant.
Having spent hours(days really) trying to figure out what is wrong and practically rewriting entire project, the issue was located and it disappears straight after disabling function that sets the window style.
I am fairly certain that WebView2 Control is the only control having issues as I created OnPaint functions that write to console every time that the control was repainted, and disabling webview2 stops other controls from being repainted, while when enabled I get 100's of repaints within few seconds.
The problem is that disabling those changes makes the application look even worse with all the flickering and graphical glitches that it was fixing before.
I do not understand what the code from the link exactly does (too advanced/complex for my current knowledge). If anyone could help me figure out how to solve the issue I would really appreciate it.
Update:
I created a small demo project for anyone interested in addressing this.
It is a 7zip of the project placed on google drive:
FlickeringDemo.7z
Microsoft Edge Canary Browser is required for WebView2 to work correctly:
Download Edge Canary Here
Main form has bool flag that control graphical improvements and flickering. Simply set it to true/false to observe the difference.
Debug.WriteLine(); - will output Paint Event counter into console in Visual Studio.
bool FlickerEnabled = false;
public MainForm()
{
InitializeComponent();
if (FlickerEnabled)
{
InitialiseGraphicalFixes();
}
}

I was having the same problem in my project and I've managed to solve it.
In the provided FickeringDemo.zip sample, to stop flickering with that version of WebView2 (1.0.664.37) you should set to true the DoubleBuffered property in all of your .Net Controls; see code below for an example on how to do it.
Another thing that I've found is that this fix stops to working in WebView2 1.0.774.44; in that version the rest of your controls will not flick, but the WebView2 will flick a lot. I didn't find a way to solve it...
public partial class WebViewControl : UserControl
{
...
public WebViewControl()
{
...
//the fix to solve flicker if the WS_EX_COMPOSiTED is set on the top window
SetDoubleBuffered(this, true);
}
private void SetDoubleBuffered(Control control, bool value)
{
try
{
control.GetType().GetProperty("DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(control, value, null);
}
catch
{
}
foreach (Control child in control.Controls)
{
SetDoubleBuffered(child, value);
}
}

Related

Xamarin Forms ScrollView click always sets Focus on first item of child Grid

I have a scrollView with a Grid inside which contains several Entrys.
When I click anywhere on the screen that isn't one of the Entry controls the focus automatically goes to the first Entry I have on the grid. I.e. This happens whether any Entry already has Focus or not, it will always set the focus of the first one again.
If I remove the Scrollview and have the Grid on screen on it's own I don't get this issue.
I am developing an application for a Windows 10 device but using the Xamarin forms cross platform code as we may move the code to Android at some stage.
Thanks in advance.
I was able to reproduce the described behavior on UWP Windows 10, but not on Android or iOS, so this is a bug in the Forms code for UWP.
I have filed a bug report for this issue which you can track here: https://bugzilla.xamarin.com/show_bug.cgi?id=52613
Xamarin engineers will now discuss this issue on the bug report. If you would like to receive a notification when the bug is updated, you can add yourself to the CC list for the bug. Please note that you will need to create an account on that system if you have not already done so.
I don't know if you solved your problem because it was more than a year ago and the issue #jgoldberger has opened on Xamarin's Bugzilla did not progress since last October.
Nevertheless I just noticed the same behaviour on my UWP app and after looking around the internet I found a solution.
If you look at this thread : Why does my TextBox get focused when clicking inside of ScrollViewer?
Then it is easy to imagine a solution for a Xamarin.Forms app by creating a custom renderer inside your UWP project.
You can use the following code which is working perfect for me :)
using {your_project_namespace}.UWP;
using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;
[assembly: ExportRenderer(typeof(ScrollView), typeof(ScrollViewCustomRenderer))]
namespace {your_project_namespace}.UWP
{
public class ScrollViewCustomRenderer : ScrollViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<ScrollView> e)
{
base.OnElementChanged(e);
if (Control == null)
return;
Control.IsTabStop = true;
}
}
}
Hope this helps.
Cheers

c# & winforms - unable to set Image of ToolStripButton

This seems like a fairly basic thing to do, but for some reason it just fails silently:
/// <summary>
/// Sets the button to show it's busy image
/// </summary>
public void SetBusy()
{
if (Control is Button)
{ ((Button)Control).Image = BusyImage; }
else if (Control is ToolStripButton)
{ ((ToolStripButton)Control).Image = BusyImage; }
}
BusyImage is set using BusyImage = Properties.Resources.Busy;
If I debug this, I can see that the image appears to be setting correctly (if I hover over the Image member when at a breakpoint I can see it change), but it doesn't actually change the image when you look at the button.
I have noticed that this works when all the above code is hosted in the same Project file as the UI, but when it's shipped out to a different project (but within the same Solution), it fails silently.
Any ideas where I'm going wrong?
Thanks
EDIT 1:
Even trying to set the Image to a file from the Resources of the same project as the ToolStripButton doesn't work (still fails silently).
Interestingly, it works absolutely fine when using a normal Button, regardless of which project the images are in.
Why the difference in behaviour between Button and ToolStripButton?
EDIT 2:
It appears that moving the code that sets the image into the same project as the ToolStripButton works. However, I would like to keep it in a separate project if at all possible...
try this instead, tested it and working fine at my end:
public void ChangeImg(Component ctrl)
{
if (ctrl is Button)
{ ((Button)ctrl).Image = Properties.Resources.keylock; }
else if (ctrl is ToolStripButton)
{ ((ToolStripButton)ctrl).Image = Properties.Resources.keylock; }
}
Finally figured this out. To cut a long story short, I had some ToolStripButtons hidden somewhere in my form, only visible in the combobox in the designer's properties window (even when you select it from there, you can't see it on the form anywhere). I was passing the name of one of these to the ImageButton instead of the correct one (which had a default name like toolStripButton3)...
I'd love to know how it happened, I suspect user error on my part...but then again I find it strange that VS will allow a ToolStripButton to exist when it doesn't appear on any ToolStrip on the form.
Either way, my code seems to work quite happily now. The reason it appeared to work when run from the same project was that I was using a different button to test the theory.
Lots of process of elimination got it down to just two buttons that weren't playing ball; on a hunch I decided to compare the properties of the working and non-working buttons, whereupon I discovered the issue...

ToolStrip with custom ToolStripControlHost makes tab order focus act weird

I'm experiencing some strange behavior. Let me try to explain, I stripped my code down to the bare minimum and I'm still having the problem. So first of all, I'm using VS2013 with .NET 4.0 and I'm on Windows 8.1.
So I have a custom UserControl with a TextBox that's being used through a ToolStripControlHost, if I focus on this textbox and hit TAB, it only cycles through the controls to the LEFT of this textbox. If I have it focused and hit SHIFT+TAB, it cycles through the buttons to the right of it.
So this is an example of my form. The textbox in the middle is a custom control. My code (as simplified as possible) looks like:
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)]
public class ToolStripTestControl : ToolStripControlHost
{
public ToolStripTestControl() : this(new TestControl()) { }
public ToolStripTestControl(Control c) : base(c) { }
}
public class TestControl : UserControl
{
private TextBox _textBox = new TextBox();
public TestControl()
{
_textBox.Dock = DockStyle.Fill;
this.Controls.Add(_textBox);
}
protected override Size DefaultMinimumSize { get { return new Size(100, 22); } }
}
Simply creating a new WinForms (.NET4) project and following these steps will allow you to replicate the problem:
Add new class file and paste the code above.
Build
Add a ToolStrip to your form
On the ToolStrip add a Button, my custom control, and another Button (through the designer is how I've been doing it)
Run
Once running...
Focus in the custom control
Hit TAB a few times, it should only focus on controls to the left.
Hit SHIFT+TAB a few times and it will only focus to the right.
Does anyone know what the problem is - or how I can fix this? I've been tearing my hair out all day trying to fix this. I finally stripped my code down and I can't seem to get it to work. I even tried overriding much of the OnEnter/OnGotFocus functionality and doing it myself, but that became a nightmare.
Thanks!
Update1: So a few extra tid-bits.
If I change the custom control to inherit from TextBox instead of UserControl, tabbing/focus works as expected.
If I change it to be a Control instead of a UserControl the tabbing works fine, as well, however the focus never gets inside my inner TextBox - the focus seems to be lost (or presumably on the outer parent control but not being passed down to the inner TextBox).
I do see a MS Connect item added that describes this problem from 2009, but this link only seems to work if I'm NOT logged in to Microsoft Connect. Which means, I can't vote on it or comment... http://connect.microsoft.com/VisualStudio/feedback/details/472592/tab-cycling-through-controls-with-usercontrol-on-toolstrip-doesnt-perform-as-expected
The .NET 2.0 ToolStripItem classes have been a major bug factory. They are window-less controls, but reproducing the exact behavior of a Windows window isn't that easy. There is an enormous amount of code underneath, most of it internal so you can't tinker with it. And with quirks when they don't emulate the behavior of a window perfectly. You could call them "airspace" issues, pretty similar to the kind of problems that WPF has.
The airspace issue here is focus, entirely unambiguous for a true window but it needs to be faked for a ToolStripItem. It is actually the item's parent that has the focus, it needs to be emulated for the item. It is the transition that bytes, ToolStrip expects a window-based control to have a reliable Focus property.
Trouble is, your custom host doesn't. It is the inner control that has the focus. This could arguably be blamed on an omission in the ToolStripControlHost class. Probably. The trouble with emulating a window, there's never enough code :)
Anyhoo, fix your problem by adding this sliver of code to your host:
public override bool Focused {
get { return _textBox.Focused; }
}

C# WPF Frame->UserControl->Usercontrol Loaded event doesn't fire

I'm new into WPF and have a problem I can't seem to find a solution for.
I'm writing a G19 (Keyboard) applet. This Keyboard has a 320x240 display attached, which you can access with C#.
I'm using WPF for this, because I don't need to do any GDI drawing anymore and use the normal controls instead.
So. It works as I wish. Everything draws properly except one UserControl. I have downloaded this control -> http://marqueedriproll.codeplex.com/
In the designer, the control works, the Loaded event get's fired and the animation is good.
When I run my application, I just see the label and the text. The animation does not work, and the Loaded event does not fire anymore.
Any help is appreciated.
The main function is my wrapper. The wrapper is already a Usercontrol and displays plugins which are switchable. This wrapper has the Frame Control(Wrapper1). I replace the content of this frame every time I switch the plugin.
public void SetPlugin(IPlugin plugin)
{
if (this.MainPlugin != null)
{
this.MainPlugin.OnHide();
((UserControl)this.MainPlugin).Visibility = System.Windows.Visibility.Hidden;
}
this.MainPlugin = plugin;
((UserControl)this.MainPlugin).Visibility = System.Windows.Visibility.Visible;
this.MainPlugin.OnShow();
this.Wrapper1.Content = this.MainPlugin;
}
I think it's the right approach to handle a plugin system that way. The plugin get's drawed on my keyboard.
What I don't understand is why the usercontrol only works in the designer view and not in the running application.
The basic code of the scrolling label is so:
public MarqueeText()
{
this.Loaded += new RoutedEventHandler(MarqueeText_Loaded);
InitializeComponent();
canMain.Height = this.Height;
canMain.Width = this.Width;
}
void MarqueeText_Loaded(object sender, RoutedEventArgs e)
{
StartMarqueeing(_marqueeType);
}
I don't see a reason why it doesn't work. Actually Ive always found a way to fix a problem but this time I see nothing.
Thanks in advance. Your help is really required today.
Have a great saturday! :)
I am guessing you are rendering to a bitmap target, rather than onscreen. If you are using RenderTargetBitmap, you have a couple of responsibilities. You need to set both a presentation source, and make sure you run events on the dispatcher.
Normally, App.xaml or Application.Run does this for you, but if you are not using a Window, you are on your own.
See this related question for details.

AxAcroPDF swallowing keys, how to get it to stop?

The AxAcroPDF swallows all key-related events as soon as it gets focus, including shortcuts, key presses, etc. I added a message filter, and it doesn't get any key-related messages either. It's a COM component, could that be relevant?
Is there any way to catch these before the control starts swallowing them?
Hans is correct, the Acrobat Reader spawns two child AcroRd32 processes which you have no direct access to from within your managed code.
I have experimented with this and you have three viable options:
You can create a global system hook, and then look for and filter out / respond to WM_SETFOCUS messages sent to your child AcroRd32 windows. You can accomplish some of this from within C# by using a wrapper library, such as the one here: http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx
You also need to identify the correct processes as there may be more than one instance of your application, or other instances of AcroRd32. This is the most deterministic solution, but because your application will now be filtering messages sent to every single window in existence, I generally don't recommend this approach because then your program could negatively affect system stability.
Find an alternate PDF viewing control. See this answer for a few commercial components: .net PDF Viewer control , or roll your own: http://www.codeproject.com/KB/applications/PDFViewerControl.aspx
Find an acceptable hack. Depending on how robust your application needs to be, code such as the following may be suitable (it was suitable for my case):
DateTime _lastRenav = DateTime.MinValue;
public Form1()
{
InitializeComponent();
listBox1.LostFocus += new EventHandler(listBox1_LostFocus);
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
axAcroPDF1.src = "sample.pdf"; //this will cause adobe to take away the focus
_lastRenav = DateTime.Now;
}
void listBox1_LostFocus(object sender, EventArgs e)
{
//restores focus if it were the result of a listbox navigation
if ((DateTime.Now - _lastRenav).TotalSeconds < 1)
listBox1.Focus();
}
I might finally have a ridiculously simple answer. So far in testing this is working.
Having suffered from this problem for quite some time and having built a complex system of each custom control recording which of them last had focus and using a timer to flip focus back (when acropdf grabbed it) I revisited this problem and read a great number of answers (looking for recent solutions). The information gleaned helped me with the idea.
The idea is to disable the (acropdf) control whilst it is loading as in the following example (code reduced for clarity)
AxAcroPDF_this.Enabled = False
AxAcroPDF_this.src = m_src
Then on a timer, after say 1 second.
AxAcroPDF_this.Enabled = True
Basically the idea is to tell Windows not to let users use the acropdf control until allowed, so asking Windows to prevent it from getting focus (because users are not allowed in there).
So far this is holding up, I will edit this if anything changes. If it doesn't work completely for you then maybe the idea points into a useful direction.
It is an out-of-process COM component, that's the problem. Completely in violation of Windows SDK requirements as laid out in SetParent(). Once its window gets the focus, the message loop in the acroread.exe process gets all the messages, your message filter cannot see any messages anymore.
Technically it is fixable by using SetWindowsHookEx() to inject a DLL into the process and monitor messages with WH_GETMESSAGE. But you can't write such a DLL in the C# language.
Major suck, I know. There never seems to be any lack of it with that program.
For some reason Tim's answer, disabling the AxAcroPDF control directly, didn't work in my case. The Leave event on the previously-selected Textbox would never fire, either.
What is working is nesting the AxAcroPDF control inside of a disabled GroupBox. Since the users of my application need to only see the PDF, not interact with it, the GroupBox's Enabled property is set to False in the designer.

Categories

Resources