I am trying to understand why the DispatcherTimer contained within SingletonWithTimer is not firing in the following WPF application. I've been researching this for a couple of days and cannot seem to get to the bottom it. This application is the reduced essential parts of an existing application that I'm trying to fix. The Startup object of this project is WPFApplication5TimerTest.Program.
The output in the console lists as follows, the problem is evident because the word "TimerTick" is not shown in the output:
Timer is initialized
'WpfApplication5TimerTest.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Sample thread
Sample thread
Sample thread
Sample thread
Sample thread
Sample thread
The thread '<No Name>' (0x10b0) has exited with code 0 (0x0).
Sample thread exiting!
This is Program.cs:
using System;
namespace WpfApplication5TimerTest
{
static class Program
{
[STAThread]
static void Main(string[] args)
{
AppObject = new App();
AppObject.Run();
}
public static App AppObject
{
get;
private set;
}
}
}
This is App.xaml.cs:
using System;
using System.Threading;
using System.Windows;
namespace WpfApplication5TimerTest
{
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
var sampleThread = new Thread(new ThreadStart(SampleThreadEntryPoint));
sampleThread.Start();
new MainWindow().Show();
}
private void SampleThreadEntryPoint()
{
SingletonWithTimer.Initialize();
while (!_shutdownEvent.WaitOne(1000))
Console.WriteLine("Sample thread");
Console.WriteLine("Sample thread exiting!");
}
protected override void OnExit(ExitEventArgs e)
{
_shutdownEvent.Set();
}
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
}
}
This is MainWindow.xaml.cs:
using System;
using System.Windows;
namespace WpfApplication5TimerTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Closed(object sender, EventArgs e)
{
Program.AppObject.Shutdown();
}
}
}
This is SingletonWithTimer.cs:
using System;
using System.Windows.Threading;
namespace WpfApplication5TimerTest
{
public class SingletonWithTimer
{
private static SingletonWithTimer Instance
{
get
{
if (_instance == null)
{
_instance = new SingletonWithTimer();
}
return _instance;
}
}
public static void Initialize()
{
SingletonWithTimer.Instance._timer = new DispatcherTimer();
SingletonWithTimer.Instance._timer.Interval = TimeSpan.FromSeconds(2);
SingletonWithTimer.Instance._timer.Tick += new EventHandler(SingletonWithTimer.Instance.OnTimerTick);
SingletonWithTimer.Instance._timer.Start();
Console.WriteLine("Timer is initialized");
}
private void OnTimerTick(object sender, EventArgs e)
{
Console.WriteLine("TimerTick");
}
private static SingletonWithTimer _instance;
private DispatcherTimer _timer = null;
}
}
It's because you've created the DispatcherTimer on another (non-UI) thread. Hence, it will be tied to the Dispatcher on that thread, not the one on the UI thread. Since nothing is running the Dispatcher on that thread, it will never fire.
Either create the DispatcherTimer on the UI thread, or use a constructor overload that allows you to pass in a specific Dispatcher to use.
Related
I am trying to call WPF client code from WebBrowser control as given in the example https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.webbrowser.objectforscripting?redirectedfrom=MSDN&view=netframework-4.8#System_Windows_Forms_WebBrowser_ObjectForScripting. The example provided in the link is for Windows forms. I am trying to do similar thing in WPF. However, I am getting following error.
Managed Debugging Assistant 'NonComVisibleBaseClass' : 'A QueryInterface call was made requesting the default IDispatch interface of COM visible managed class 'WpfApp2.MainWindow'. However since this class does not have an explicit default interface and derives from non COM visible class 'System.Windows.Window', the QueryInterface call will fail. This is done to prevent the non COM visible base class from being constrained by the COM versioning rules.'
Is there any way to resolve this? or it just cannot be done in WebBrowser-control and WPF ?
We need to create a separate class and use it for scripting
using System.Windows;
using System.Security.Permissions;
using System.Windows.Controls;
using System;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class ObjectForScriptingHelper
{
public void Test()
{
MessageBox.Show("xxxxx");
}
}
public MainWindow()
{
InitializeComponent();
button1.Content = "call script code from client code";
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//webBrowser1.AllowWebBrowserDrop = false;
//webBrowser1.IsWebBrowserContextMenuEnabled = false;
//webBrowser1.WebBrowserShortcutsEnabled = false;
webBrowser1.ObjectForScripting = new ObjectForScriptingHelper();
// Uncomment the following line when you are finished debugging.
//webBrowser1.ScriptErrorsSuppressed = true;
webBrowser1.Navigate(#"C:\temp\WpfApp2\WpfApp2\HTMLPage1.html");
}
private void Button1_Click_1(object sender, RoutedEventArgs e)
{
webBrowser1.InvokeScript("test",
new String[] { "called from client code" });
}
}
}
So i'm making a basic yahtzee program i c#, and im trying to make an actual gui and not just use the console. However i have a problem with the textbox. When i roll the dice, i want the textbox to display the number rolled. Now it shows nothing. I use two classes, one for the actual program and one for handling the gui. This is the yahtzee class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Yahtzee
{
class YahtzeeScorer {
Random rndm = new Random();
Form1 gui = new Form1();
String dice1, dice2, dice3, dice4, dice5;
public void rollDice()
{
String a = Console.ReadLine();
this.dice1 = rndm.Next(1, 7).ToString();
this.gui.tbDice_SetText(this.dice1);
}
static void Main(String[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
YahtzeeScorer ys = new YahtzeeScorer();
Application.Run(ys.gui);
ys.rollDice();
Console.WriteLine("The result was: " + ys.dice1 );
Console.Read();
}
}
}
And this is the gui class form1:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Yahtzee
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void tbDice_SetText(String s)
{
//this.ActiveControl = tbDice;
Console.WriteLine("SetText");
tbDice.Text = s;
}
public void textBox1_TextChanged(object sender, EventArgs e)
{
}
}
}
tbDice is the name of the textbox component. Any ideas?
Examine the lines:
Application.Run(ys.gui);
ys.rollDice();
rollDice() will not be called until the application exits, because the thread running Main() will block on Application.Run() until it does.
Instead, try calling ys.rollDice() in something like a button event handler.
UPDATE
You are mixing your game logic and your presentation logic by putting both aspects in YahtzeeScorer. I would suggest that you move the game logic into a separate class like this:
public class YahtzeeGame
{
public string rollDice()
{
return rndm.Next(1, 7).ToString();
}
}
public partial class Form1 : Form
{
YahtzeeGame game = new YahtzeeGame();
public Form1()
{
InitializeComponent();
}
// You need to create a new Button on your form called btnRoll and
// add this as its click handler:
public void btnRoll_Clicked(object sender, EventArgs e)
{
tbDice.Text = game.rollDice();
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Thread HeartRateThread = new Thread(startThread);
HeartRateThread.Name = "Class1";
HeartRateThread.Start();
}
private void startThread(object obj)
{
new Class1();
}
}
public class Class1
{
public Class1()
{
DispatcherTimer timer1 = new DispatcherTimer();
timer1.Interval = new TimeSpan(0,0,0,1);
timer1.Tick += timer1_tick;
timer1.Start();
}
private void timer1_tick(object sender, EventArgs e)
{
Debug.WriteLine("timer called");
}
}
I am trying to enable this timer_tick function fromanother thread as it is obvious in the code section of maInWindow. However, the Class1 constructor is called but timertick functin is not enabled. However if i do this on the main thread, everything works fine. Any reason for this.And how can I get it working?
DispatcherTimer can only work run on a UI thread. However, in your case you are creating a DispatcherTimer on a background thread. DispatcherTimer, internally tries to get Dispatcher.CurrentDispatcher, in your case it gets dispatcher for the background thread, not for the main UI thread.
Do you really need DispatcherTimer? If you are not going to manipulate any UI elements in the timer1_tick method, then you are better off to go with a different timer, like System.Timers.Timer.
Refer to this to read more about available Timers in .net.
Maybe you can try something like this:
private void timer1_tick(object sender, EventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() => Debug.WriteLine("timer called")));
}
Without having tested it, I guess you have to pass the MainWindow's Dispatcher to the DispatcherTimer on construction. Otherwise it will create its own:
private void startThread(object obj)
{
new Class1(Dispatcher);
}
...
public Class1(Dispatcher dispatcher)
{
DispatcherTimer timer1 =
new DispatcherTimer(DispatcherPriority.Background, dispatcher);
timer1.Interval = new TimeSpan(0,0,0,1);
timer1.Tick += timer1_tick;
timer1.Start();
}
you can use Dispatcher for call startThread method.
object objParameter = "parametervalue";
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(
() => startThread(objParameter)));
I'm developing a dnn module. And i used codebehind C#. But DNN shows error when I add a the module. Other pages work just fine but the page I add the module to says DotNetNuke error. The error does not have any code and it only displays my logo. Even the admin strip disappears.
What did i do wrong?
using System;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Modules.Actions;
using DotNetNuke.Services.Localization;
using DotNetNuke.Security;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Data;
using System.Web.UI;
using System.Configuration;
//imports
namespace DotNetNuke.Modules.Catagory
{
public partial class View : CatagoryModuleBase, IActionable
{
public bool inEdit = false;
private bool IsValid = true;
#region Event Handlers
override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
private void Page_Load(object sender, System.EventArgs e)
{
try
{
if (IsPostBack)
{
if (Catagory_Table.SelectedRow != null)
{ //There is a selected item, hence edit mode Catagory_Table.SelectedIndex >= 0
this.inEdit = true;
to_edit_mode();
}
else
{
to_add_mode();
}
}
else
{
to_add_mode();
}
}
catch (Exception exc) //Module failed to load
{
Exceptions.ProcessModuleLoadException(this, exc);
}
}
protected void Button1_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
SqlDataSource1.Insert();
}
//the rest if the methods to handle the buttton events....
}
You will want to try to check the Admin/Event Viewer to see what the error is specifically, then you can be better informed on what it will take to fix.
I'm getting this Exception
System.InvalidOperationException was
unhandled by user code Message="The
calling thread cannot access this
object because a different thread owns
it."
whenever I run the following code
public partial class MainScreen : Window
{
Timer trm;
public MainScreen()
{
InitializeComponent();
trm = new Timer(1000);
trm.AutoReset = true;
trm.Start();
trm.Elapsed += new ElapsedEventHandler(trm_Elapsed);
}
void trm_Elapsed(object sender, ElapsedEventArgs e)
{
lblTime.Content = System.DateTime.Now;
}
}
guys any solution... I badly wann come out of it :(
Use DispatcherTimer instead:
public partial class MainScreen : Window{
DispatcherTimer tmr;
public MainScreen() {
InitializeComponent();
tmr = new DispatcherTimer();
tmr.Tick += new EventHandler(tmr_Tick);
tmr.Start();
}
void tmr_Tick(object sender, EventArgs e) {
lblTime.Content = System.DateTime.Now;
}
}
Any time you modify Windows controls you must do so on the UI thread (the one that created the controls).
See this question for lots of details.
To be short, you should use Dispatcher.Invoke method to update UI elements.