How to programmatically set tab order - c#

I am building a window from code.
I add a header TextBlock and then some various elements for a listBox in which each element is made out of
Grid ---> children[0] a TextBlock to explain what is the element
---> children1 a TextBox or combobox to input data.
At the end a button.
After having generated put the focus on the first element (generally the first TextBox) so that the user can immediately input data. Up to that everything works.
--ADD--
I forgot to mention that every element = Grid = Textblock + TextBox or combobox, is an element of the parent listBox. So I would like to move from every textbox or combobox independently from the listbox element they are in.
After that I want the user to be able to move to next element (textbox or combobox) through TAB. So when generating the previous windows I use a counter and set
tb.TabIndex = tabIndex++;
or
ComboBox.TabIndex = tabIndex++;
Now the problem is that after having input data in the first TextBox when I press TAB the caret gets lost and so the focus...
---ADD2---
Here is the code:
private void PreparareTraceFieldGrid(ListBox lbTracefields, ObservableCollection<Tuple<string, object, object>> obc, bool IsReadOnly)
{
bool IsFocusSet = false;
/*---TITOLO---*/
OutlinedTextBlock otbTitle = CreateOtbForTraceFieldInputWindow(Languages.Word(eWords.InsertTracefields));
lbTracefields.Items.Add(otbTitle);
/*----CICLO----*/
int tabIndex = 0;
foreach (var item in obc)
{
Grid gridInternal = new Grid();
gridInternal.Background = Brushes.Transparent;
ColumnDefinition cd1 = new ColumnDefinition();
cd1.Width = new GridLength(300, GridUnitType.Pixel);
ColumnDefinition cd2 = new ColumnDefinition();
cd2.Width = new GridLength(1.0, GridUnitType.Star);
gridInternal.ColumnDefinitions.Add(cd1);
gridInternal.ColumnDefinitions.Add(cd2);
OutlinedTextBlock otb = CreateOtbForTraceFieldInputWindow(item.Item1);
otb.FontSize = easyRunData.OptionsGraphical.FontSize;
otb.Stroke = new SolidColorBrush(easyRunData.OptionsGraphical.StrokeColour);
otb.StrokeThickness = easyRunData.OptionsGraphical.StrokeSize;
Grid.SetColumn(otb, 0);
gridInternal.Children.Add(otb);
string strDataType = item.Item2.ToString();
eTraceFieldDataTypes eDataType = (eTraceFieldDataTypes)Enum.Parse(typeof(eTraceFieldDataTypes), strDataType);
switch (eDataType)
{
case eTraceFieldDataTypes.STRING:
case eTraceFieldDataTypes.FLOAT:
case eTraceFieldDataTypes.INTEGER:
case eTraceFieldDataTypes.STRING_READONLY:
TextBox tb = new TextBox();
tb.CaretBrush = Brushes.White;
tb.FontSize = easyRunData.OptionsGraphical.FontSize;
tb.MinWidth = 200;
tb.Height = easyRunData.OptionsGraphical.FontSize + 15;
tb.VerticalAlignment = VerticalAlignment.Center;
tb.Background = Brushes.Transparent;
tb.Margin = new Thickness(10);
tb.TabIndex = tabIndex++;
tb.KeyDown += (senderEvent, args) => { AnalyzeTraceFields_IF_EMPTY(easyRunData.Tracefields.TraceFieldsUser, (Grid)lbTracefields.Parent); };
if (eDataType == eTraceFieldDataTypes.STRING_READONLY && !IsReadOnly)
tb.BorderBrush = Brushes.Yellow;
else
tb.BorderBrush = Brushes.Gainsboro;
Grid.SetColumn(tb, 1);
gridInternal.Children.Add(tb);
lbTracefields.Items.Add(gridInternal);
if (!IsFocusSet)
{
tb.Focus();
IsFocusSet = true;
}
break;
case eTraceFieldDataTypes.BOOL:
case eTraceFieldDataTypes.BOOL_READONLY:
Border brd = new Border();
brd.Margin = new Thickness(10);
brd.MinWidth = 200;
brd.Height = easyRunData.OptionsGraphical.FontSize + 15;
if (eDataType == eTraceFieldDataTypes.BOOL_READONLY && !IsReadOnly)
brd.BorderBrush = Brushes.Yellow;
else
brd.BorderBrush = Brushes.Gainsboro;
brd.BorderThickness = new Thickness(3);
ComboBox cmb = new ComboBox();
cmb.VerticalAlignment = VerticalAlignment.Center;
cmb.Background = Brushes.Transparent;
cmb.Items.Add(Languages.Word(eWords.True));
cmb.Items.Add(Languages.Word(eWords.False));
cmb.BorderBrush = Brushes.Gainsboro;
cmb.BorderThickness = new Thickness(3);
cmb.Margin = new Thickness(0);
cmb.TabIndex = tabIndex++;
cmb.DropDownClosed += (senderEvent, args) => { AnalyzeTraceFields_IF_EMPTY(easyRunData.Tracefields.TraceFieldsUser, (Grid)lbTracefields.Parent); };
Grid.SetColumn(brd, 1);
brd.Child = cmb;
gridInternal.Children.Add(brd);
lbTracefields.Items.Add(gridInternal);
if (!IsFocusSet)
{
cmb.Focus();
IsFocusSet = true;
}
break;
default:
break;
}
}

Related

Buttons that delete their StackPanel in WPF C#

I'm trying to create a contacts app. When I try to edit a contact it opens a window that looks like this: image
The code that loads the contact model is:
private void LoadContactToEdit() {
FirstNameTextBox.Text = contactToEdit.FirstName;
LastNameTextBox.Text = contactToEdit.LastName;
string[] phoneNumbers = contactToEdit.PhoneNumbers.Split('|');
int i = 0;
foreach(string phoneNumber in phoneNumbers) {
StackPanel sp = new StackPanel();
NameScope.SetNameScope(this, new NameScope());
sp.Name = $ "PNStackPanel{i}";
RegisterName(sp.Name, sp);
sp.Orientation = Orientation.Horizontal;
sp.HorizontalAlignment = HorizontalAlignment.Center;
TextBox txtbox = new TextBox();
txtbox.Name = $ "PNTextBox{i}";
txtbox.Text = phoneNumber;
txtbox.Width = 200;
txtbox.Background = Brushes.White;
txtbox.Margin = new Thickness(0, 10, 0, 0);
sp.Children.Add(txtbox);
if (i > 0) {
Button btn = new Button();
btn.Name = $ "PNButton{i}";
btn.Content = btn.Name;
btn.Width = 100;
btn.Click += DeletePhoneNumberTextBox;
btn.Margin = new Thickness(0, 10, 0, 0);
sp.Children.Add(btn);
}
PhoneNumberStackPanel.Children.Add(sp);
i++;
}
string[] emailAddresses = contactToEdit.EmailAddresses.Split('|');
i = 0;
foreach(string emailAddress in emailAddresses) {
StackPanel sp = new StackPanel();
sp.Name = $ "EAStackPanel{i}";
sp.Orientation = Orientation.Horizontal;
sp.HorizontalAlignment = HorizontalAlignment.Center;
TextBox txtbox = new TextBox();
txtbox.Name = $ "EATextBox{i}";
txtbox.Text = emailAddress;
txtbox.Width = 200;
txtbox.Background = Brushes.White;
txtbox.Margin = new Thickness(0, 10, 0, 0);
sp.Children.Add(txtbox);
if (i > 0) {
Button btn = new Button();
btn.Name = $ "EAButton{i}";
btn.Content = btn.Name;
btn.Width = 100;
//btn.Click += DeleteEmailAddressTextBox;
btn.Margin = new Thickness(0, 10, 0, 0);
sp.Children.Add(btn);
}
EmailAddressStackPanel.Children.Add(sp);
i++;
}
}
Look at the phone number code for now. I am trying to create buttons that dynamically deletes the stackpanel the are part of.
this is their code:
private void DeletePhoneNumberTextBox(object sender, RoutedEventArgs e){
string s = (sender as Button).Name;
char c = s[s.Length - 1];
string x = $ "PNStackPanel{c}";
StackPanel sp = PhoneNumberStackPanel.FindName(x) as StackPanel;
PhoneNumberStackPanel.Children.Remove(sp);
}
However only the last button deletes its stackpanel. I tried messing with itemsControl instead of stackpanels and I only got more confused. What do I do wrong?
[EDIT]: I converted the StackPanel into ItemsControl after some researching and removing items is a lot easier.

Dynamically created c# label not visible

I'm attempting to display some dynamically generated labels next to dynamically generated text boxes. The text boxes appear but the labels do not.
I've looked at several solutions and have tried to make sure I defined all the label properties. I looked at some threading related solution that seem unnecessary because i'm not changing visibility state, I would just like to pop up the labels next to the text boxes.
TextBox[] channelNames = new TextBox[numOfChannels];
GroupBox channelBox = new GroupBox();
Label[] labelNames = new Label[numOfChannels];
for (int currentChannelIndex = 0; currentChannelIndex < numOfChannels; currentChannelIndex++)
{
var txt = new TextBox();
channelNames[currentChannelIndex] = txt;
txt.Name = channelCollection[currentChannelIndex].PhysicalName;
txt.Text = "ben";
txt.Location = new Point(200, 32 + (currentChannelIndex * 28));
txt.Visible = true;
this.channelBox.Controls.Add(channelNames[currentChannelIndex]);
var lbl = new Label();
labelNames[currentChannelIndex] = lbl;
lbl.AutoSize = true;
lbl.Name = channelCollection[currentChannelIndex].PhysicalName;
lbl.Size = new Size(55, 13);
lbl.TabIndex = 69;
lbl.Text = channelCollection[currentChannelIndex].PhysicalName;
lbl.Location = new Point(175, 32 + (currentChannelIndex * 28));
lbl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.channelBox.Controls.Add(labelNames[currentChannelIndex]);
}
Here are a few things to check:
1) You are setting "AutoSize" and "Size". Trying removing "Size"
2) The default font is likely too large for the (55,13) size.
Try explicitly setting the font to something small to see if it shows up.
Does channelCollection[currentChannelIndex].PhysicalName actually contain a non-Empty string? e.g.:
class Something
{
public string PhysicalName { get; set; }
}
private void AddLabels()
{
Something[] channelCollection = new Something[]
{
//Applying this to Label.Text makes it "invisible"
new Something() { PhysicalName = "" }
};
var currentChannelIndex = 0;
var txt = new TextBox();
txt.Name = channelCollection[currentChannelIndex].PhysicalName;
txt.Text = "ben";
txt.Location = new Point(200, 32);
txt.Visible = true;
this.Controls.Add(txt);
var lbl = new Label();
lbl.AutoSize = true;
lbl.Name = channelCollection[currentChannelIndex].PhysicalName;
lbl.Size = new Size(55, 13);
lbl.TabIndex = 69;
lbl.Text = channelCollection[currentChannelIndex].PhysicalName;
lbl.Location = new Point(175, 32);
lbl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.Controls.Add(lbl);
}
I actually had an exception that downstream of this code block that was causing the issue. I assumed that i would see the labels since the exception was thrown after the call to the label. Thanks for your suggestions.

Accessing TextBlock in a grid with LINQ

I am dynamically generating rows in a XAML grid:
for (int i = 0; i < AssociatedSteps.Length; i++)
{
//if (i == 0 || AssociatedSteps[i].OriginPkg != AssociatedSteps[i-1].OriginPkg)
//{
//Define new Row to add
RowDef = new RowDefinition();
RowDef.Height = new GridLength(60);
//Add row definition to Grid
WorkPackageViewResults.RowDefinitions.Add(RowDef);
//Define the control that will be added to new row
Text1 = new TextBlock();
Text1.Text = AssociatedSteps[i].SF01;
Text1.Width = Settings.workPackageColumn5Width;
Text1.TextAlignment = TextAlignment.Center;
Text2 = new TextBlock();
Text2.Text = AssociatedSteps[i].SF10;
Text2.Width = Settings.workPackageColumn5Width;
Text2.TextAlignment = TextAlignment.Center;
Text3 = new TextBlock();
Text3.Text = AssociatedSteps[i].OriginPkg;
Text3.Width = Settings.workPackageColumn5Width;
Text3.TextAlignment = TextAlignment.Center;
Button1 = new Button();
Button1.Content = AssociatedSteps[i].Description;
Button1.Width = Settings.workPackageColumn5Width;
Button1.Click += new RoutedEventHandler(ProgressUpdateButton_Click);
Button1.Tag = AssociatedSteps[i].StepID;
//create stackpanel and define which row to add the stackpanel to
StackP = new StackPanel();
//StackP.Background = new SolidColorBrush(Colors.Wheat);
StackP.SetValue(Grid.RowProperty, i);
StackP.Orientation = Orientation.Horizontal;
StackP.Margin = new Thickness(0, 0, 0, 0);
PercentComplete = new TextBlock();
PercentComplete.Text = (Convert.ToDouble(AssociatedSteps[i].ToDateQty) / Convert.ToDouble(AssociatedSteps[i].MTOQty)).ToString();
PercentComplete.Width = Settings.workPackageColumn5Width;
PercentComplete.TextAlignment = TextAlignment.Center;
//add your control to the stackpanel
StackP.Children.Add(Text1);
StackP.Children.Add(Text2);
StackP.Children.Add(Text3);
StackP.Children.Add(Button1);
StackP.Children.Add(PercentComplete);
//add the stackpanel to the grid
WorkPackageViewResults.Children.Add(StackP);
}
I'm trying to use LINQ to get access to the grid being programatically updated above:
<Grid Name="WorkPackageViewResults">
</Grid>
I'm not seeing they type of options you would for a cell. I want to to access a particular rows PercentComplete TextBlock so I can update the text. How do I accomplish this?
Since there's only one StackPanel you could say e => e.GetType() == typeof(StackPanel). If you ever have many, then add a Name to the StackPanel and pull it by that.

Click event for programatically generated XAML buttons

I'm programatically generating a table where Text2 the columns are a button:
for (int i = 0; i < workPackages.Length; i++)
{
//Define new Row to add
RowDef = new RowDefinition();
RowDef.Height = new GridLength(60);
//Add row definition to Grid
WorkPackageResults.RowDefinitions.Add(RowDef);
//Define the control that will be added to new row
Text1 = new TextBlock();
Text1.Text = workPackages[i].EWPStatus;
Text1.Width = 100;
Text1.TextAlignment = TextAlignment.Center;
Text2 = new Button();
Text2.Content = workPackages[i].EWPCode;
Text2.Width = 300;
Text3 = new TextBlock();
Text3.Text = workPackages[i].Description;
Text3.Width = 500;
Text3.TextAlignment = TextAlignment.Center;
Text4 = new TextBlock();
Text4.Text = workPackages[i].ForeBadge;
Text4.Width = 100;
Text4.TextAlignment = TextAlignment.Center;
//create stackpanel and define which row to add the stackpanel to
StackP = new StackPanel();
StackP.SetValue(Grid.RowProperty, i);
StackP.Orientation = Orientation.Horizontal;
StackP.Margin = new Thickness(50, 0, 0, 0);
//add your control to the stackpanel
StackP.Children.Add(Text1);
StackP.Children.Add(Text2);
StackP.Children.Add(Text3);
StackP.Children.Add(Text4);
//add the stackpanel to the grid
WorkPackageResults.Children.Add(StackP);
}
How do I programatically add a click event? And when that click event is executed how do I know which button it came from?
Add an event handler to Text2.Click that will pass the sender as a parameter, that's how you know which one was clicked.

How to display only row border of a grid (not column) using Border()

I am using c# in silverlight application.
I have a grid with 1 row and 3 columns.
There are 2 things that i am not able to know how to do:
(1) I have to display the boundaries of just row (not columns, only rows). How to do that?
Currently i have a grids like this:
//The p in function call below is yhe object obtained on deserialixing xml.
private static Grid GenerateGrid(Parameters p)
{
Grid myGrid = new Grid();
myGrid.Width = 650;
myGrid.HorizontalAlignment = HorizontalAlignment.Left;
myGrid.VerticalAlignment = VerticalAlignment.Top;
myGrid.ShowGridLines = false;
ColumnDefinition colDef1 = new ColumnDefinition();
ColumnDefinition colDef2 = new ColumnDefinition();
ColumnDefinition colDef3 = new ColumnDefinition();
myGrid.ColumnDefinitions.Add(colDef1);
myGrid.ColumnDefinitions.Add(colDef2);
myGrid.ColumnDefinitions.Add(colDef3);
int totalRows = p.Parameter.Count() + p.Separator.Count();
for (int i = 0; i < totalRows; i++)
{
myGrid.RowDefinitions.Add(new RowDefinition());
}
return (myGrid);
}
Call to this function is :
XmlParameterClasses.Parameters parameter =
(XmlParameterClasses.Parameters)deserializer.Deserialize(reader);
Grid BigGrid = GenerateGrid(parameter);
My try to achieve is this: (I used Border to do this, see at the end of the function)
private static Grid GenerateComboBox(ViewModel.XmlParameterClasses.Parameter param, int LoopCount, Grid g)
{ //param is the object of the class Parameter
StackPanel sp1 = new StackPanel(); //These three stackpanels are inside the grid cell
StackPanel sp2 = new StackPanel();
StackPanel sp3 = new StackPanel();
ComboBox cb = new ComboBox();
TextBlock txtblk1 = new TextBlock();
TextBlock txtblkLabel = new TextBlock();
////////////////////////////////////
//Label Display
txtblkLabel.Text = param.Label;
txtblkLabel.VerticalAlignment = System.Windows.VerticalAlignment.Center;
txtblkLabel.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
txtblkLabel.TextAlignment = System.Windows.TextAlignment.Center;
txtblkLabel.FontWeight = FontWeights.Bold;
txtblkLabel.FontSize = 15;
txtblkLabel.FontStyle = FontStyles.Normal;
txtblkLabel.Padding = new Thickness(5, 10, 5, 10);
sp1.Orientation = Orientation.Horizontal;
sp1.Children.Add(txtblkLabel);
sp1.Width = 100;
sp1.Height = 50;
Grid.SetRow(sp1, LoopCount);
Grid.SetColumn(sp1, 0);
g.Children.Add(sp1);
foreach(var item in param.Component.Attributes.Items) {
cb.Items.Add(item);
}
cb.SelectionChanged += new SelectionChangedEventHandler(comboBox1_SelectionChanged);
cb.SelectedIndex = cb.Items.Count - 1;
//For text Display
txtblk1.Text = cb.SelectedValue.ToString() + " millions";
txtblk1.VerticalAlignment = System.Windows.VerticalAlignment.Center;
txtblk1.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
txtblk1.TextAlignment = System.Windows.TextAlignment.Center;
txtblk1.FontWeight = FontWeights.Bold;
txtblk1.FontSize = 15;
txtblk1.FontStyle = FontStyles.Normal;
txtblk1.Padding = new Thickness(5, 10, 5, 10);
sp2.Orientation = Orientation.Horizontal;
sp2.Children.Add(txtblk1);
Grid.SetColumn(sp2, 2);
Grid.SetRow(sp2, LoopCount);
g.Children.Add(sp2);
//For combo box display
cb.Width = 45;
cb.Height = 25;
sp3.Orientation = Orientation.Horizontal;
sp3.Children.Add(cb);
sp3.Width = 50;
sp3.Height = 50;
Grid.SetColumn(sp3, 1);
Grid.SetRow(sp3, LoopCount);
g.Children.Add(sp3);
////////////Here is the Border Display ////////////////////////////
Border rect = new Border();
rect.Width = g.Width;
rect.Height = g.Height;
rect.BorderThickness = new Thickness(5);
rect.BorderBrush = new SolidColorBrush(Colors.Black);
g.Children.Add(rect);
////////////////////////////////////////////////////////////////////
return (g);
}
but the output obtained is like this : (It just cover the border of first cell not the other two in that row, whereas i just want one border over one row(not over the column in that row, just row boundary))
Could some one please help me in achieving this step ? Is it possible to implement what i want trying to do?
Note: Please note that code has to be implemented using c# only , not xaml.
I have done it by creating a grid of 1 column and rows (instead of 3*3 cell it must be 1*3 (row*column)). Then creating Border in each row and then again creating grid with 1 row and 3 columns and then creating border of this small grid.
code is:
Border rect = new Border();
rect.Width = g.Width;
rect.Height = g.Height;
rect.BorderThickness = new Thickness(2);
rect.BorderBrush = new SolidColorBrush(Colors.Black);
Grid childGrid = new Grid();
ColumnDefinition colDef1 = new ColumnDefinition();
ColumnDefinition colDef2 = new ColumnDefinition();
ColumnDefinition colDef3 = new ColumnDefinition();
childGrid.ColumnDefinitions.Add(colDef1);
childGrid.ColumnDefinitions.Add(colDef2);
childGrid.ColumnDefinitions.Add(colDef3);
TextBlock txtblk3 = new TextBlock();
var border = new Border()
{
Background = new SolidColorBrush(Colors.LightGray)
};
border.Height = 14;
var border1 = new Border()
{
Background = new SolidColorBrush(Colors.White)
};
border1.Height = 14;
Grid.SetColumnSpan(border, 3);
Grid.SetRow(childGrid, LoopCount);
childGrid.Children.Add(border);
txtblk3.FontSize = 14;
txtblk3.FontWeight = FontWeights.Bold;
txtblk3.Text = param.Separator[SeparatorPosition];
Grid.SetColumn(border1, 1);
Grid.SetRow(border1,LoopCount);
border1.Child = txtblk3;
childGrid.Children.Add(border1);
g.Children.Add(childGrid);
return (g);
Where "g" has only 1 column and "LoopCount" numbers of row. And it worked for me.
You should override CellPainting event of DataGridView control as the code snippet below:
private void grid_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
e.AdvancedBorderStyle.Left = DataGridViewAdvancedCellBorderStyle.None;
e.AdvancedBorderStyle.Right = DataGridViewAdvancedCellBorderStyle.None;
}

Categories

Resources