I have created a very simple winform app that has a single form and a single button on it. Its click event is wired up as shown below. If you click the button, the app behaves as expected ie the ExecTasks exits. If you replace the lock statement by lock(this), ExecTasks will not exit and the debugger shows a thread in a sleep/wait/join at the code in Exec. Question why does the choice of locking object change this behaviour - why is the form instance not a valid choice ?
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 TestDeadlock
{
public partial class Form1 : Form
{
private object _lock = new object();
public Form1()
{
InitializeComponent();
}
private void Button1Click(object sender, EventArgs e)
{
Task.Factory.StartNew(ExecTasks);
}
private void ExecTasks()
{
lock (_lock) /* replace by lock(this) to see the blocked behavior */
{
var taskList = new List<Task>();
for (var i = 0; i < 2; ++i)
{
taskList.Add(Task.Factory.StartNew(Exec));
}
Task.WaitAll(taskList.ToArray());
}
}
private void Exec()
{
Invoke((Action)delegate{});
}
}
}
I see this blocking behavior. When you call the Invoke method, it result in calling the Control.FindMarshalingControl method which is implemented as follows:
private Control FindMarshalingControl()
{
lock (this)
{
Control parentInternal = this;
....
}
}
Here is a link on a similar issue:
Control.BeginInvoke will also be blocked
Related
I want a comboBox to autocomplete and I found the below code:
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 testcomboBox
{
public partial class Form1 : Form
{
List<string> listOnit = new List<string>() { "Stephen_Curry", "Kevin_Durant", "Draymond_Green", "Zaza_Pachulia","Gerald Green" };
List<string> listSearchUpdate = new List<string>();
public Form1()
{
InitializeComponent();
}
private void comboBox1_TextUpdate(object sender, EventArgs e)
{
comboBox1.Items.Clear();
listSearchUpdate.Clear();
foreach (var item in listOnit)
{
if (item.Contains(comboBox1.Text))
{
listSearchUpdate.Add(item);
}
}
comboBox1.Items.AddRange(listSearchUpdate.ToArray());
comboBox1.SelectionStart = comboBox1.Text.Length;
Cursor = Cursors.Default;
comboBox1.DroppedDown = true;
}
}
}
The code has a bug When type letter "G",the comboBox immediately autoselects "Gerald Green" and fills it to the edit control of the comboBox,but if you type "G" again,the edit control just fine to show "G" and pop up list of "Draymond_Green" and "Gerald Green". So how to disable autoselection function when type string in the edit control of the comboBox?
refer to this linkenter link description here
I revised code below and it is ok.
private void comboBox1_TextUpdate(object sender, EventArgs e)
{
comboBox1.Items.Clear();
listSearchUpdate.Clear();
string strTemp = string.Empty;
foreach (var item in listOnit)
{
if (item.Contains(comboBox1.Text))
{
strTemp = comboBox1.Text;
listSearchUpdate.Add(item);
}
}
comboBox1.Items.AddRange(listSearchUpdate.ToArray());
comboBox1.DroppedDown = true;
comboBox1.SelectionStart = strTemp.Length;
Cursor = Cursors.Default;
}
I am trying to click on "btnPunch". This button is located in an iFrame. I am unable to make this work. I have used the Selenium IDE to record this button being clicked and created a DLL that also runs this process in NUnit without a problem. Any help would be appreciated after three months of working on this.
Thank you
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using NUnit.Framework;
using Selenium;
using OpenQA.Selenium.IE;
using OpenQA.Selenium;
namespace TimeClockEntry
{
public partial class PNow : Form
{
IWebDriver driver = new InternetExplorerDriver();
//driver = new InternetExplorerDriver();
//private ISelenium selenium;
//private StringBuilder verificationErrors;
//public void SetupTest()
//{
// selenium = new DefaultSelenium("localhost", 4444, "*chrome", "https://ew23.ultipro.com/");
// selenium.Start();
// verificationErrors = new StringBuilder();
//}
int linkcount = 0;
string userName;
string passWord;
public PNow()
{
InitializeComponent();
webBrowser1.Navigate("https://ew23.ultipro.com/login.aspx");
}
private void PNow_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Normal;
userName = Properties.Settings.Default.userName;
passWord = Properties.Settings.Default.passWord;
}
private void PNow_FormClosed(object sender, FormClosedEventArgs e)
{
this.Hide();
welcome f1 = new welcome();
f1.ShowDialog();
this.Close();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
this.Focus();
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
linkcount++;
if (linkcount == 1)
{
webBrowser1.Document.GetElementById("ctl00_Content_Login1_UserName").SetAttribute("value", userName);
webBrowser1.Document.GetElementById("ctl00_Content_Login1_Password").SetAttribute("value", passWord);
webBrowser1.Document.GetElementById("ctl00_Content_Login1_LoginButton").InvokeMember("click");
}
if (linkcount == 2)
{
HtmlElement link = (from HtmlElement elem in webBrowser1.Document.GetElementsByTagName("a")
where elem.InnerHtml == "Time Clock Entry"
select elem).ElementAt(0);
link.InvokeMember("Click");
}
if (linkcount == 3)
{
// driver.FindElement(By.Id("btnPunch")).Click();
webBrowser1.Document.GetElementById("ctl00_Content_lnkLogout").InvokeMember("click");
this.Close();
}
}
}
}
You can try this also:-
if (linkcount == 3)
{
WebElement frameSwitch = driver.findElement(By.xpath("Xpath of iframe")); //Frame Xpath
driver.switchTo().frame(frameSwitch);
driver.FindElement(By.Id("btnPunch")).Click();
webBrowser1.Document.GetElementById("ctl00_Content_lnkLogout").InvokeMember("click");
driver.switchTo().defaultContent();
this.Close();
}
Try this.
if (linkcount == 3)
{
//get back to basic html source.
driver.SwitchTo().DefaultContent();
//switch to new frame
driver.SwitchTo().Frame("<FRAME NAME OR ID>");
driver.FindElement(By.Id("btnPunch")).Click();
}
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();
}
}
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.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsistec.Domain;
using Microsistec.Client;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Microsistec.Tools;
using System.Json;
using Microsistec.SystemConfig;
using System.Threading;
using Microsoft.Silverlight.Testing;
namespace Test
{
[TestClass]
public class SampleTest : SilverlightTest
{
[TestMethod, Asynchronous]
public void login()
{
List<PostData> data = new List<PostData>();
data.Add(new PostData("email", "xxx"));
data.Add(new PostData("password", MD5.GetHashString("xxx")));
WebClient.sendData(Config.DataServerURL + "/user/login", data, LoginCallBack);
EnqueueCallback(?????????);
EnqueueTestComplete();
}
[Asynchronous]
public void LoginCallBack(object sender, System.Net.UploadStringCompletedEventArgs e)
{
string json = Microsistec.Client.WebClient.ProcessResult(e);
var result = JsonArray.Parse(json);
Assert.Equals("1", result["value"].ToString());
TestComplete();
}
}
Im tring to set ???????? value but my callback is generic, it is setup on my WebClient .SendData, how i implement my EnqueueCallback to a my already functio LoginCallBack???
You have to take a different approach to make this work. Why do you want to enqueue LoginCallBack? It would get called asynchronously when sendData has ended, would it not?
Also, I see no point in having a TestComplete() in LoginCallBack and EnqueueTestComplete() in login. Would this not work:
[TestClass]
public class SampleTest : SilverlightTest
{
[TestMethod, Asynchronous]
public void login()
{
List<PostData> data = new List<PostData>();
data.Add(new PostData("email", "xxx"));
data.Add(new PostData("password", MD5.GetHashString("xxx")));
WebClient.sendData(Config.DataServerURL + "/user/login", data, LoginCallBack);
}
[Asynchronous]
public void LoginCallBack(object sender, System.Net.UploadStringCompletedEventArgs e)
{
string json = Microsistec.Client.WebClient.ProcessResult(e);
var result = JsonArray.Parse(json);
Assert.Equals("1", result["value"].ToString());
TestComplete();
}
}
I'm unsure of how LoginCallback gets called but if you make sure that that happens it should make the test pass!