I have a control with textbox. After user input few lines of text and submit that by button then, for every line of text I need to show a childwindow with grid where user has to select some value.
Let's say that user inputs 5 lines of text with names of clients (one line one client name).
For every of them aften click Submit, he must select Salesperson from ChildWindow.
Of course now effect of my loop is opening 5 ChildWindows with the in the same time.
How can I do user get next ChildWindow only after choosing an element from Childwindow grid ?
Maybe your control could use a class that looks something like this.
public class SalesPersonSelector
{
private Queue<string> _clientNamesToProcess;
private Dictionary<string, SalesPerson> _selectedSalesPersons;
private Action<IDictionary<string, SalesPerson>> _onComplete;
private string _currentClientName;
public void ProcessNames(IEnumerable<string> clientNames, Action<IDictionary<string, SalesPerson>> onComplete)
{
this._clientNamesToProcess = new Queue<string>(clientNames);
this._selectedSalesPersons = new Dictionary<string, SalesPerson>();
this._onComplete = onComplete;
this.SelectSalespersonForNextClient();
}
private void SelectSalespersonForNextClient()
{
if (this._clientNamesToProcess.Any())
{
this._currentClientName = this._clientNamesToProcess.Dequeue();
ChildWindow childWindow = this.CreateChildWindow(this._currentClientName);
childWindow.Closed += new EventHandler(childWindow_Closed);
childWindow.Show();
}
else
{
this._onComplete(this._selectedSalesPersons);
}
}
private ChildWindow CreateChildWindow(string nextClientName)
{
// TODO: Create child window and give it access to the client name somehow.
throw new NotImplementedException();
}
private void childWindow_Closed(object sender, EventArgs e)
{
var salesPerson = this.GetSelectedSalesPersonFrom(sender as ChildWindow);
this._selectedSalesPersons.Add(this._currentClientName, salesPerson);
this.SelectSalespersonForNextClient();
}
private SalesPerson GetSelectedSalesPersonFrom(ChildWindow childWindow)
{
// TODO: Get the selected salesperson somehow.
throw new NotImplementedException();
}
}
Assuming your control has already split up the names from the TextBox into a list called "names", then you can do this:
var salesPersonSelector = new SalesPersonSelector();
salesPersonSelector.ProcessNames(names, selections =>
{
foreach (var selection in selections)
{
var clientName = selection.Key;
var salesPerson = selection.Value;
// TODO: Do something with this information.
}
});
I haven't tested this, but Visual Studio isn't giving me any red squiggly lines.
Related
I have a wpf application that has a datagrid with names in the first column and additional info in other columns. The names are in sorted order. If a user presses a key on the keyboard, say p, I would like the datagrid to go to the first row where the name begins with p. If the user then presses e, go to the first row that begins with pe, etc. Is this possible in a datagrid? I haven't been able to find anything or examples on this. Please help.
For that you should add keydown event.
And Step 1 : OnkeyDown event get text of key.
Step 2 : find item as per your condition from list.
Step 3 : Change selected item.
Step 4 : and scroll datagrid to selected item.
Window keydown event work correctly, in my case datagrid event worked when row was selected.
Here is code.
List<Employee> empData = new List<Employee>();
private Task task;
private CancellationToken token;
private CancellationTokenSource tokenSource;
private string searchText = "";
KeyDownEvent :
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (task != null && tokenSource != null)
{
// cancel task
tokenSource.Cancel();
tokenSource = null;
Console.WriteLine("Task cancel");
}
// Set condition for key
string txt = new KeyConverter().ConvertToString(e.Key);
if (txt.ToString().ToList().Any(x => !Char.IsLetterOrDigit(x)))
{
Console.WriteLine("Retrun from.");
return;
}
searchText = searchText + new KeyConverter().ConvertToString(e.Key);
Console.WriteLine("Search text : " + searchText);
var item = empData.FirstOrDefault(x=>x.FirstName.StartsWith(searchText));
if (item != null)
{
myGrid.SelectedItem = item;
myGrid.UpdateLayout();
myGrid.ScrollIntoView(myGrid.SelectedItem);
}
// create task for clean text
Console.WriteLine("Task generate");
tokenSource = new CancellationTokenSource();
token = tokenSource.Token;
task = new Task(()=> CleanSearchText(token), token);
task.Start();
}
Task for clean text after sometime
private void CleanSearchText(CancellationToken token)
{
// Throw if cancellation request
token.ThrowIfCancellationRequested();
// Wait for sometime for next key prss
Thread.Sleep(400);
// Do nothing if cancelation request
if (token.IsCancellationRequested)
{
return;
}
Console.WriteLine("Clean text");
searchText = "";
}
It is possible. A simple example for Datagrid:
http://www.wpf-tutorial.com/datagrid-control/details-row/
Then handle event keydown in Datagrid
<DataGrid Name="dgUsers" AutoGenerateColumns="False" KeyDown="DgUsers_OnKeyDown">
code behind simple:
private void DgUsers_OnKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
foreach (var row in dgUsers.Items)
{
User user = (User) row;
user.Name = e.Key.ToString();
dgUsers.SelectedItem = row;
break;
}
}
This is already built in!
<DataGrid IsTextSearchEnabled="True" ...
Now just let the models "ToString" method return the text you want to search for - done!
See also https://msdn.microsoft.com/en-us/library/system.windows.controls.textsearch.aspx
I have an array of pictureboxes named from B11 (co-ords 1,1) to B55 (co-ords 5,5). I would like to hide these all on startup (and in the middle of running). I was thinking of making an array of the names manually but would it be the best solution?
If they all have a common parent control, such as a panel or groupbox (or even the form):
Parent.SuspendLayout()
For Each pbox As PictureBox in Parent.Controls.OfType(Of PictureBox)()
pbox.Visible = False
Next pbox
Parent.ResumeLayout()
The Suspend/Resume-Layout() is to avoid flickering as you modify a bunch of controls at once.
You could extend the PictureBox class and use event handling to accomplish this by:
Adding a public property to the form to tell if the picture boxes should be shown or hidden.
Adding an event to the form that is raised when the show/hide picture box property is changed.
Extending the PictureBox class so that it subscribes to the event of the parent form.
Setting the visible property of the extended PictureBox class to the show/hide property of the parent form.
When the show/hide flag is changed on the parent form all of the picture boxes will change their visibility property accordingly.
Form Code:
public partial class PictureBoxForm : Form {
public PictureBoxForm() {
InitializeComponent();
this.pictureBoxesAdd();
}
private void pictureBoxesAdd() {
MyPictureBox mp1 = new MyPictureBox();
mp1.Location = new Point(1, 1);
MyPictureBox mp2 = new MyPictureBox();
mp2.Location = new Point(200, 1);
this.Controls.Add(mp1);
this.Controls.Add(mp2);
}
public event EventHandler PictureBoxShowFlagChanged;
public bool PictureBoxShowFlag {
get { return this.pictureBoxShowFlag; }
set {
if (this.pictureBoxShowFlag != value) {
pictureBoxShowFlag = value;
if (this.PictureBoxShowFlagChanged != null) {
this.PictureBoxShowFlagChanged(this, new EventArgs());
}
}
}
}
private bool pictureBoxShowFlag = true;
private void cmdFlip_Click( object sender, EventArgs e ) {
this.PictureBoxShowFlag = !this.PictureBoxShowFlag;
}
}
Extended PictureBox Code:
public class MyPictureBox : PictureBox {
public MyPictureBox() : base() {
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.ParentChanged += new EventHandler(MyPictureBox_ParentChanged);
}
private void MyPictureBox_ParentChanged( object sender, EventArgs e ) {
try {
PictureBoxForm pbf = (PictureBoxForm)this.Parent;
this.Visible = pbf.PictureBoxShowFlag;
pbf.PictureBoxShowFlagChanged += new
EventHandler(pbf_PictureBoxShowFlagChanged);
} catch { }
}
private void pbf_PictureBoxShowFlagChanged( object sender, EventArgs e ) {
PictureBoxForm pbf = (PictureBoxForm)sender;
this.Visible = pbf.PictureBoxShowFlag;
}
}
...or just put 'em all on a Panel, and change the panel's visibility.
I am using a win form to search the record and when the record is selected from a grid on celldoubleclick event. The search form should be closed and the selected row record is loaded back to to main form from which search form is begin called.
The code to open the search form.
private void F1Button_Click(object sender, EventArgs e)
{
Forms.frmSearchNewAccount frm = new Forms.frmSearchNewAccount();
frm.ShowDialog();
if (frm.DialogResult == System.Windows.Forms.DialogResult.OK)
{
//here comes the selected record
}
}
//Search Form grid view cell double click event code is here
try
{
if (e.RowIndex >= 0)
{
this._SelectedRecord = new Flour_Mills.PARTY();
_SelectedRecord.PARTY_ID = (string)((DataTable)SearchPartydataGrid.DataSource).Rows[e.RowIndex]["PARTY_ID"];
_SelectedRecord.NAME = (string)((DataTable)SearchPartydataGrid.DataSource).Rows[e.RowIndex]["NAME"];
Controller.PartyDAL.Load(_SelectedRecord.PARTY_ID);
DialogResult = System.Windows.Forms.DialogResult.OK;
this.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The _selectedRecord is a static variable but it is not accessible in main form.
Any Suugestions????
If u need more explination I am here to to elaborate more.
Simply it can be do as:
public var _selectedRecordFromSearchForm;
private void F1Button_Click(object sender, EventArgs e)
{
Forms.frmSearchNewAccount frm = new Forms.frmSearchNewAccount();
frm.ShowDialog(this); // pass this form as Owner
if (frm.DialogResult == System.Windows.Forms.DialogResult.OK)
{
//here comes the selected record
}
}
In search form:
this._SelectedRecord = new Flour_Mills.PARTY();
_SelectedRecord.PARTY_ID = (string)((DataTable)SearchPartydataGrid.DataSource).Rows[e.RowIndex]["PARTY_ID"];
_SelectedRecord.NAME = (string)((DataTable)SearchPartydataGrid.DataSource).Rows[e.RowIndex]["NAME"];
Controller.PartyDAL.Load(_SelectedRecord.PARTY_ID);
this.Owner._selectedRecordFromSearchForm = _SelectedRecord; // set _searchRecoed to owners field
DialogResult = System.Windows.Forms.DialogResult.OK;
this.Close();
You could declare _SelectedRecord as public in your search form and when the form closes you can access the variable like this :
if (frm.DialogResult == System.Windows.Forms.DialogResult.OK)
{
var SelectedRecord = frm._SelectedRecord;
}
I am following this exactly:
http://msdn.microsoft.com/en-us/library/ms185301.aspx
but can't get it to work. The form appears when I try and add my new item, but when I input text and click the button, nothing happens.
For posterity's sake here is my code:
The non-empty methods in the Wizard class which extends IWizard
public void RunStarted(object automationObject,
Dictionary<string, string> replacementsDictionary,
WizardRunKind runKind, object[] customParams)
{
try
{
// Display a form to the user. The form collects
// input for the custom message.
inputForm = new UserInputForm();
inputForm.ShowDialog();
customMessage = inputForm.get_CustomMessage();
// Add custom parameters.
replacementsDictionary.Add("$custommessage$",
customMessage);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
// This method is only called for item templates,
// not for project templates.
public bool ShouldAddProjectItem(string filePath)
{
return true;
}
The user input form code:
public partial class UserInputForm : Form
{
private string customMessage;
public UserInputForm()
{
InitializeComponent();
}
public string get_CustomMessage()
{
return customMessage;
}
private void button1_Click(object sender, EventArgs e)
{
customMessage = textBox1.Text;
this.Dispose();
}
}
And the button is indeed named button 1:
this.button1.Location = new System.Drawing.Point(200, 180);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(100, 40);
this.button1.TabIndex = 0;
this.button1.Text = "Click Me";
this.button1.UseVisualStyleBackColor = true;
So I don't have much experience with Windows Forms (do web apps), but I am following the directions on MSDN and it's pretty clear cut. Any suggestions? Can anyone else get this to work?
Okay I figured it out. I had to add the event handler in the form's constructor manually:
public UserInputForm()
{
InitializeComponent();
button1.Click += button1_Click;
}
Why this isn't in the documentation on MSDN boggles my mind.
If you use the WinForms designer mode to drag your button from the Toolbox, and then double-clicked the button in the designer view, it would have added the event handler and stubbed that Click method for you. Just FYI.
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);
}
}