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.
Related
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);
}
}
I have WPF UserControl within ElementHost in a Windows Form. I had to use the interop because I needed easy zooming and panning functionality. And everything is perfect except I can't play slideshow.
Funny thing is that each image can be display with selection in ListBox without any problem. But when I loop through the list to play movie, it only shows the last image. I put Thread.Sleep(1000), this.Refresh(), or anything else in each loop in vain. Any clue will be appreciated.
Solved the problem by creating following code in the UserControl and calling its Refresh method whenever needed.
public delegate void MyDelegate();
public void Refresh()
{
//this.Refresh();
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, (MyDelegate) delegate() { });
}
I am new to WPF and C# and i need some help - sorry about the newbie question!
Anyway I have a control panel 'window' as the file thats loaded when i run my project, and i then have a button on this control panel, that when clicked triggers an event. Inside this 'event function' I am trying to load a new window that has its own XAML code behind, how do i go about doing this? I have googled but to no avail.
Please explain in laymens terms, I am still getting the hang of this all.
Thanks!
private void btnCustomers_clicked(object sender, RoutedEventArgs e)
{
//load in Customers.xaml file here - in a new window
}
You need to declare an instance of the class that is your other window then call Show() on it. So if your other window is call MySecondWindow you write the following in your event handler.
MySecondWindow otherWindow = new MySecondWindow();
otherWindow.Show();
A basic explination of how windows work can be found on the MSDN Site.
I'm attempting to use the ScintillaNET control in an application I am working on. I drag and drop the control into my form and run form. The control appears on the form. This is good. In addition, if I set any of the properties in the control's properties editor (ConfigurationManager.Language, for example), I am able to type in that language and see syntax highlighting occur.
Where I run into problems is when I attempt to change properties programmatically. For example, I attempt to load text from a file into the form (I'm doing this in the form's Load). The text doesn't display. I also can't seem to show the line numbers or do any other number of tasks (including programmatically change the Language).
Any idea what I may be doing wrong? Even something as simple as the code below doesn't seem to work:
private void scintilla1_Load(object sender, EventArgs e)
{
scintilla1.ConfigurationManager.Language = "xml";
}
Simply add scintilla1.ConfigurationManager.Configure();
private void scintilla1_Load(object sender, EventArgs e)
{
scintilla1.ConfigurationManager.Language = "xml";
scintilla1.ConfigurationManager.Configure();
}
After spending some time playing around with the different events, it appears that I cannot affect the Scintilla control until after it is already visible. Hence, the "Load" event does not let me make any programmatic changes to the control until I've set it visible.
It's a little strange, and seems sort of pointless to me to have the Load event at all, but I just wanted to let everybody know what is happening in case someone else ran into the same problem.
I am trying to load a preferences window for my application and I would like the apply button to initially be disabled, then when a preference is updated, the apply button gets enabled again. I have some controls data bound to a preferences object and what happens is that after the window loads, the combobox events get triggered. Is there any event that is guaranteed to happen dead last after everything is stable?
Here is what my code looks like (the apply button is always enabled after the window loads):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_preferencesData = new PreferencesDataContext();
LayoutRoot.DataContext = _preferencesData;
ButtonApply.IsEnabled = false;
}
private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ButtonApply.IsEnabled = true;
}
Is it also interesting to note that this only happens with textboxes and comboboxes, not checkboxes or radiobuttons.
Best solution for simple need
Joseph's answer is the best solution by far for your simple need: Just use data binding and let the data model handle it.
Answer to question as posed
There are more complex scenarios when you really do need control after absolutely everything has finished loading and all events have fired. There is no single event that occurs "dead last", but it is easy to effectively roll your own using the Dispatcher queue.
This is how to do it:
Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(() =>
{
var x = ComputeSomething(1, 2, 3);
DoSomething(x, "Test");
}));
Everything inside the { } will be executed when WPF finishes everything at a higher priority than ContextIdle, which includes all event handlers, loaded events, input events, rendering, etc.
Sequence of events when a Window is created and shown
As requested, here is the sequence of major events in WPF when a window is created and shown:
Constructors and getters/setters are called as objects are created, including PropertyChangedCallback, ValidationCallback, etc on the objects being updated and any objects that inherit from them
As each element gets added to a visual or logical tree its Intialized event is fired, which causes Styles and Triggers to be found applied in addition to any element-specific initialization you may define [note: Initialized event not fired for leaves in a logical tree if there is no PresentationSource (eg Window) at its root]
The window and all non-collapsed Visuals on it are Measured, which causes an ApplyTemplate at each Control, which causes additional object tree construction including more constructors and getters/setters
The window and all non-collapsed Visuals on it are Arranged
The window and its descendants (both logical and visual) receive a Loaded event
Any data bindings that failed when they were first set are retried
The window and its descendants are given an opportunity to render their content visually
Steps 1-2 are done when the Window is created, whether or not it is shown. The other steps generally don't happen until a Window is shown, but they can happen earlier if triggered manually.
The Window.ContentRendered event fulfilled my requirements.
I just did kind of the same thing behaviorly in a systray WPF app.
However, I didn't do it using event handling. I simply bound the Enabled property of my button to a property in my ViewModel, and had the property updated whenever I needed the behavior.
You can use ManagedSpy to figure this out on your own.
http://msdn.microsoft.com/en-us/magazine/cc163617.aspx
Setting the DataContext will likely fire the SelectionChanged event, and you can't rely on when exactly it's fired. Some logic checking on what exactly is selected would be more reliable:
private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (myComboBox.SelectedItem == null)
{
buttonApply.IsEnabled = false;
}
else
{
buttonApply.IsEnabled = true;
}
}
The reason it's happening afterwards with your code as-is is because the event gets queued on the thread for the UI, so it's up to Windows if it will execute the next line of code in Load, or to handle the other events on the queue.
Not to throw a whole lot of stuff at you that you may or may not be familiar with, but if this is a relatively new codebase, you may want to consider using the MVVM pattern and use Commands instead of the archaic (emphasis mine) eventing model.
Order of Events in Windows Forms
Control.HandleCreated
Control.BindingContextChanged
Form.Load
Control.VisibleChanged
Form.Activated
Form.Shown