wpf threading, thread must be STA - wpf

I have a window(say main window) with a frame which has a page in it. A button on the page opens another window(say popup window). Now i am trying to invoke a method in the main window from a button on the popup window. The method has to be multi-threaded, i had a similar solution running in windows forms but i keep getting the calling thread must be STA because many UI components require this in WPF.
The method on the page which opens the popup window modally
Scripts showStocks = new Scripts();
showStocks.ShowInTaskbar = false;
showStocks.ShowDialog();
if (showStocks.DialogResult==true)
{
Window1 wd1 = new Window1();
wd1.doneDeal();
}
Here window1 is our main window. The doneDeal method is
public void doneDeal()
{
// **Some Code**
BackgroundWorker wworks1 = new BackgroundWorker();
wworks1.DoWork += Tickes;
wworks1.RunWorkerCompleted += Tickes2;
wworks1.RunWorkerAsync();
// Page1 pg1 = frame1.Content as Page1;
//NextPrimeDelegate dd=new NextPrimeDelegate(okreport);
// pg1.addScriptBtn.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
// new NextPrimeDelegate(okreport));
//startStopButton.Dispatcher.BeginInvoke(
// DispatcherPriority.Normal,
// new NextPrimeDelegate(CheckNextNumber));
//new Thread(() => Tick(stock, rowID, exchange)) { IsBackground = false }.Start();
}
Finally the method that i am trying to run in the background
public void Tickes(object sender, DoWorkEventArgs e)
{
}
Also i want to populate a gridview from the result of the tickes method, this will be looping and running over and over in the background but periodically returning data to be added to the grid. SHould i do that in the progress update event ? Have tried a lot to wrap my head around the dispatcher and background worker in wpf but am failing to understand the STA apartment state bit. If someone can help me to get my tickes method going or point me in the right direction, i would be very very thankful.

Well i finally was able to solve the STA thread problem am posting the answer just in case somebody comes across a similar problem in the future.
public void doneDeal()
{
if (StockData.flag == 1)
{
row1 = table.NewRow();
row1[col1] = "";
row1[col2] = "";
row1[col3] = "";
row1[col4] = "";
row1[col5] = "";
row1[col6] = "";
row1[col7] = "";
row1[col8] = "";
row1[col9] = "";
row1[col10] = "";
row1[col11] = "";
row1[col12] = "";
table.Rows.Add(row1);
string stock = StockData.stock;
int rowID = (table.Rows.Count - 1);
string exchange = StockData.exchange;
Thread bh = new Thread(delegate()
{
Tick7(stock, rowID, exchange);
});
bh.SetApartmentState(ApartmentState.STA);
bh.IsBackground = true;
bh.Start();
StockData.flag = -1;
}
}
The Tick7 method which is being called is declared like this
[STAThread]
public void Tick7(string stock, int rowID, string exchange)
{
int rowNum = rowID;
int counter = -1;
deletecounter = StockData.deletecounter;
Thread.CurrentThread.Name = StockData.stock;
.
.
.
}

Related

How to disable remove button for KryptonPage with context menu close item?

How to block KryptonPage for close and i need to remove button of docking area and context menu option for close
i am using https://github.com/ComponentFactory/Krypton
Visual Studio 2015 Community
Win 10
There are details about my code for clear understanding
Following screenshot is Form designer about using controls
screenshot of Form designer using controls 1
screenshot of Form designer using controls 2
Following screenshot of ruining application
application ruining time for close menu item for block i want it
There are my form code c#
// this is main form code
public partial class frmMain : KryptonForm
{
public frmMain()
{
InitializeComponent();
kryptonPanel1.Dock = DockStyle.Fill;
kryptonDockableWorkspace.Dock = DockStyle.Fill;
kryptonPanel.Dock = DockStyle.Fill;
}
private void Form1_Load(object sender, EventArgs e)
{
KryptonDockingWorkspace w = kryptonDockingManager.ManageWorkspace(kryptonDockableWorkspace);
kryptonDockingManager.ManageControl(kryptonPanel, w);
kryptonDockingManager.ManageFloating(this);
kryptonDockingManager.AddDockspace("Control", DockingEdge.Left, new KryptonPage[] { NewWinTools() });
kryptonDockingManager.AddDockspace("Control", DockingEdge.Bottom, new KryptonPage[] { NewWinTools(), NewWinTools(), NewWinTools(), NewWinTools() , NewWinTools() });
kryptonDockingManager.AddToWorkspace("Workspace", new KryptonPage[] { NewWinControl() });
}
private KryptonPage NewPage(string name, int image, Control content)
{
// Create new page with title and image
KryptonPage p = new KryptonPage();
p.Text = name;
p.TextTitle = name;
p.TextDescription = name;
p.ImageSmall = imageListSmall.Images[image];
// Add the control for display inside the page
content.Dock = DockStyle.Fill;
p.Controls.Add(content);
return p;
}
private KryptonPage NewWinControl()
{
UserControl1 br = new UserControl1();
KryptonPage page = NewPage("New Tab", 0, br);
page.ClearFlags(KryptonPageFlags.DockingAllowAutoHidden | KryptonPageFlags.DockingAllowDocked);
return page;
}
private KryptonPage NewWinTools()
{
UserControl1 br = new UserControl1();
KryptonPage page = NewPage("Tools 1 ", 2, br);
page.ClearFlags( KryptonPageFlags.DockingAllowClose);
return page;
}
}
please help for block close KryptonPage
I have just come across the same issue. I can see that this question was answered here
It looks like there is no way of actually removing the close button but you can intercept it and then ignore the event.
In the interest of completeness, this is the code you need to write:
private void CreateDockWorkspace()
{
KryptonDockingWorkspace w = kryptonDockingManager.ManageWorkspace("Workspace", kryptonDockableWorkspace);
kryptonDockingManager.ManageControl("Control", kryptonPanel, w);
kryptonDockingManager.ManageFloating("Floating", this);
kryptonDockingManager.AddToWorkspace("Workspace", new KryptonPage[] {
NewPage("Overview"),
NewPage("Main"),
NewPage("Report"),
});
// This is where you wire up the CloseAction event handler
var workspace = kryptonDockingManager.CellsWorkspace.FirstOrDefault();
workspace.CloseAction += HandleTabCloseAction;
}
private void HandleTabCloseAction(object sender, CloseActionEventArgs e)
{
// This event handler ignores the action
e.Action = CloseButtonAction.None;
}
private KryptonPage NewPage(string name)
{
var p = new KryptonPage();
p.Text = name;
p.TextTitle = name;
p.TextDescription = name;
content.Dock = DockStyle.Fill;
p.Controls.Add(content);
return p;
}

datagridview control continues update, gui flickers when scrolling window

Problem:
I have a Winform application with a form en on this form i have a databound DataGridView.
The datagridview is updated from the backend by updating the bind object continuesly using a timer to get the data every 10 seconds. In order to update the gui with this new data i call a RefreshDatabindings. (if i do not do this, the gui is nog updated, i am binding to a BindingList and the object implement the INotifyPropertyChanged)
When the form is big enough to show the whole datagridview at once everything is working wel. But when the form is not big enough to show the hole datagridview a scrollbar appears.
When i scroll to the right to see the rest of the datagridview i see the gui flickering (only the part that wasn't visible before scrolling). When i strech the form to make de gridview fitting again, everything is working wel (no flashing and flickering). the flickering only happens when i have to scroll.
I am lost, can please somebody help me :)?
I allready tryed the DoubleBuffered = true.
Thanks in advance!
BindingList<InstanceTableViewModel> viewModelList;
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
functionParamList = new List<FunctionParameter>();
functionParamList.Add(new FunctionParameter { DeviceValue = 100, InstanceId = "1", Name = "A" });
functionParamList.Add(new FunctionParameter { DeviceValue = 200, InstanceId = "2", Name = "B" });
functionParamList.Add(new FunctionParameter { DeviceValue = 300, InstanceId = "3", Name = "C" });
viewModelList = CreateInstanceTableViewModelList();
dataGridView1.DataSource = viewModelList;
//Create timer
updateDataTimer = new System.Timers.Timer();
updateDataTimer.Interval = 500;
updateDataTimer.Elapsed += updateDataTimer_Elapsed;
updateDataTimer.Start();
}
private void updateDataTimer_Elapsed(object sender, ElapsedEventArgs e)
{
ThreadPool.QueueUserWorkItem(ReadDataThreadPoolMethod);
}
private void ReadDataThreadPoolMethod(object state)
{
Random random = new Random();
int randomNumber = random.Next(0, 100);
foreach (FunctionParameter param in functionParamList)
{
param.DeviceValue = Convert.ToInt64(randomNumber);
}
}
void functionParameter_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var functionParameter = sender as FunctionParameter;
var propertyName = e.PropertyName;
var propertyValue = functionParameter.DeviceValue;
var parameterName = functionParameter.Name;
UpdateViewModel(functionParameter.InstanceId, propertyName, propertyValue, parameterName);
}
private void UpdateViewModel(string instanceId, string propertyName, long propertyValue, string parameterName)
{
var instanceViewModel = viewModelList.Single(x => x.InstanceId == instanceId && x.NameLabel == parameterName);
if (instanceViewModel != null)
{
instanceViewModel.ValueHex = Convert.ToUInt16(propertyValue);
}
ResetBindingsSource();
}
delegate void UpdateBindingsInvoker();
public void ResetBindingsSource()
{
if (!this.IsDisposed)
{
if (this.InvokeRequired)
{
this.Invoke(new UpdateBindingsInvoker(UpdateDataGrid));
}
else
{
UpdateDataGrid();
}
}
}
private void UpdateDataGrid()
{
dataGridView1.Refresh();
}
So here my solution:
You only uses the Forms DoubleBuffering, but the following code is an extension method to the DataGridview and successfully works (at my tests ;)
public static void DoubleBuffered(this DataGridView dgv, bool setting)
{
Type dgvType = dgv.GetType();
PropertyInfo pi = dgvType.GetProperty("DoubleBuffered",
BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(dgv, setting, null);
}
I found this code right here at Codeprojct.
You can use it in this way:
YourDataGridView.DoubleBuffered(true);
I hope i could help you ^^

Silverlight 4 Async wait how to?

I have a problem:
//Get All master record
entryE_QuestMaster = new ObservableCollection<E_QuestMaster>();
//Here I am calling my web service to get data
QuestVM.getExamsMasterbyExamID(eUtility.ConvertInt32(this.txtID.Text), ref entryE_QuestMaster);
//Loop to show questions
int iNumber=1;
foreach (var oIn in entryE_QuestMaster)
{
Node subNode = new Node();
subNode.Content = oIn.e_Question;
subNode.Name = "Quest_" + iNumber.ToString().Trim();
subNode.Tag = oIn.e_QID.ToString();
subNode.Icon = "/Images/Number/" + iNumber.ToString().Trim() + ".gif";
iNumber++;
this.tvMainNode.Nodes.Add(subNode);
}
Whenever I call
QuestVM.getExamsMasterbyExamID(eUtility.ConvertInt32(this.txtID.Text), ref entryE_QuestMaster);
It runs the following code
public void getExamsMasterbyExamID(int ID, ref ObservableCollection<E_QuestMaster> iCollectionData)
{
ObservableCollection<E_QuestMaster> iCollectionDataResult = iCollectionData;
eLearningDataServiceClient client = new eLearningDataServiceClient();
isSync = true;
client.getExamsMasterCompleted+=(s,e)=>
{
iCollectionDataResult = e.Result;
};
client.getExamsMasterAsync(ID);
}
My problem is I wanted to wait until my e.result comes back in iCollectionDataResult.
Currently after calling this service the system continues to the next line of code which is in the foreach loop. In this stage my entryE_QuestMaster does not have any record, I just wanted to wait till my result comes back before the loop continues.
After Answering ChrisF
no dought what chrisf said will work for me, but i wanted to do every thing in my MVVM class rather then in form level , here what i have change in my code , i still need your help guys and whated to do some professional code rather then just writing huge code.
i have added these two lines in my MVVM class
public delegate void ShowQuestionTreeView(ObservableCollection<sp_GetQuestMasterbyExamID_Result> iResultQuestMaster);
public event ShowQuestionTreeView ShowQuestionforTreeview;
then in method i have added this
/// <summary>
///
/// </summary>
/// <param name="ID"></param>
public void getExamsMasterbyExamID(int ID, ref ObservableCollection<sp_GetQuestMasterbyExamID_Result> iCollectionData)
{
ObservableCollection<sp_GetQuestMasterbyExamID_Result> iCollectionDataResult = iCollectionData;
eLearningDataServiceClient client = new eLearningDataServiceClient();
client.getExamsMasterbyExamIDCompleted+= (s, e) =>
{
iCollectionDataResult = e.Result;
**ShowQuestionforTreeview(iCollectionDataResult);**
};
client.getExamsMasterbyExamIDAsync(ID);
}
on client end i have done this
//Generate Treeview for question
QuestVM.ShowQuestionforTreeview += new eQuestCreateVM.ShowQuestionTreeView(QuestVM_ShowQuestionforTreeview);
method :
void QuestVM_ShowQuestionforTreeview(ObservableCollection<sp_GetQuestMasterbyExamID_Result> iResultQuestMaster)
{
//Loop to show questions
int iNumber = 1;
foreach (var oIn in iResultQuestMaster)
{
Node subNode = new Node();
subNode.Content = oIn.e_Question;
subNode.Name = "Quest_" + iNumber.ToString().Trim();
subNode.Tag = oIn.e_QID.ToString();
subNode.Icon = "/Images/Number/" + iNumber.ToString().Trim() + ".gif";
subNode.Title = oIn.e_Question_Text;
iNumber++;
tvCreateQuestion.Nodes[0].Nodes.Add(subNode);
}
}
You need to move this code:
client.getExamsMasterCompleted+=(s,e)=>
{
iCollectionDataResult = e.Result;
};
outside your call to getExamsMasterbyExamID. This will also mean moving where you declare and initialise the eLearningDataServicesClient.
The way you have your code set up at the moment means that you are assuming that iCollectionDataResult will be set when the method returns. However, this is not the case. The method will return before the getExamsMasterCompleted event is fired.
You will need to organise your code along the following lines:
eLearningDataServiceClient client = new eLearningDataServiceClient();
client.getExamsMasterCompleted += (s,e) =>
{
//Loop to show questions
}
client.getExamsMasterAsync(ID);
Or alternatively bind the display of questions to the ObservableCollection so when it gets set the UI updated automatically.

How to show and hide the Popup?

void Start()
{
System.Windows.Controls.Primitives.Popup p = new System.Windows.Controls.Primitives.Popup();
p.HorizontalOffset = this.ActualWidth / 2;
p.Width = 100;
p.Height = 100;
p.VerticalOffset = this.ActualHeight / 2;
DockPanel dock = new DockPanel();
dock.Children.Add(new Button() { Content = "Обновлено" });
p.Child = dock;
p.IsOpen = true;
Thread t = new Thread(StopPopup);
t.Start(p);}
function:
private void StopPopup(object obj)
{
try
{
System.Windows.Controls.Primitives.Popup p = (System.Windows.Controls.Primitives.Popup)obj;
this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
dataGrid1.DataContext = DataSetCreator.AllItems();
Thread.Sleep(1500);
p.IsOpen = false;
}));
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
but why this code is triggered once = (
}
It looks like you're trying to show a control from a non-UI thread and not connecting it to the Application UI in any way (as far as I can see here). WPF UI elements need to created and manipulated on the UI thread and need to be associated with some Window based control in order to be rendered.
In addition to what John said, I would suggest looking at a Modeless dialog box. When you call Show() on the dialog box, the method returns immediately. This allows the application to continue instead waiting for a response from the dialog. You can also attach to button's click event so you know when the button is clicked.

How do I access a MessageBox with white?

I have a simple message box in a WPF application that is launched as below:
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Howdy", "Howdy");
}
I can get white to click my button and launch the message box.
UISpy shows it as a child of my window I couldn't work out the method to access it.
How do I get access to my MessageBox to verify its contents?
Found it! The window class has a MessageBox method that does the trick:
var app = Application.Launch(#"c:\ApplicationPath.exe");
var window = app.GetWindow("Window1");
var helloButton = window.Get<Button>("Hello");
Assert.IsNotNull(helloButton);
helloButton.Click();
var messageBox = window.MessageBox("Howdy");
Assert.IsNotNull(messageBox);
Please try this
Window messageBox = window.MessageBox("");
var label = messageBox.Get<Label>(SearchCriteria.Indexed(0));
Assert.AreEqual("Hello",label.Text);
Contained in the White source code are some UI tests projects (to test White itself).
One of the test includes MessageBox tests, which includes a way to obtain the displayed message.
[TestFixture, WinFormCategory, WPFCategory]
public class MessageBoxTest : ControlsActionTest
{
[Test]
public void CloseMessageBoxTest()
{
window.Get<Button>("buttonLaunchesMessageBox").Click();
Window messageBox = window.MessageBox("Close Me");
var label = window.Get<Label>("65535");
Assert.AreEqual("Close Me", label.Text);
messageBox.Close();
}
[Test]
public void ClickButtonOnMessageBox()
{
window.Get<Button>("buttonLaunchesMessageBox").Click();
Window messageBox = window.MessageBox("Close Me");
messageBox.Get<Button>(SearchCriteria.ByText("OK")).Click();
}
}
Evidently, the label used to display the text message is owned by the window displaying the messagebox, and its primary identification is the max word value (65535).
window.MessageBox() is a good solution!!
But this method would stuck for a long time if the messagebox doesn't appear. Sometimes I want to check "Not Appearance" of a messagebox (Warning, Error, etc.). So I write a method to set the timeOut by threading.
[TestMethod]
public void TestMethod()
{
// arrange
var app = Application.Launch(#"c:\ApplicationPath.exe");
var targetWindow = app.GetWindow("Window1");
Button button = targetWindow.Get<Button>("Button");
// act
button.Click();
var actual = GetMessageBox(targetWindow, "Application Error", 1000L);
// assert
Assert.IsNotNull(actual); // I want to see the messagebox appears.
// Assert.IsNull(actual); // I don't want to see the messagebox apears.
}
private void GetMessageBox(Window targetWindow, string title, long timeOutInMillisecond)
{
Window window = null ;
Thread t = new Thread(delegate()
{
window = targetWindow.MessageBox(title);
});
t.Start();
long l = CurrentTimeMillis();
while (CurrentTimeMillis() - l <= timeOutInMillsecond) { }
if (window == null)
t.Abort();
return window;
}
public static class DateTimeUtil
{
private static DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long currentTimeMillis()
{
return (long)((DateTime.UtcNow - Jan1st1970).TotalMilliseconds);
}
}

Resources