Programmatically Added Textboxes not Appearing - c#

I'm using WinForms in VS15 with C#.
I'm dynamically adding TextBoxs and Labels to my Form based upon a user selected value in a ComboBox (essentially this looks up a value in a data collection which tells my UI what controls it needs).
When I attempt to generate the controls, the Labels appear and layout just fine, however, the TextBoxs are remarkable in there absence.
I've tried fidelling with the MaximumSize and MinimumSize properties to see if they could be messing with something but it doesn't seem to be making any difference.
The code I use for doing this is below (I know the use of the List<Pair<Label,TextBox>> is pretty unecessary but I find it helps readability):
private void GenerateControls(string formType)
{
string[] formParameters = engine.GetFormParameters(formType);
if (formParameters == null) return;
SplitterPanel panel = splitContainer.Panel1;
panel.Controls.Clear();
List<Pair<Label, TextBox>> controlPairs = new List<Pair<Label, TextBox>>();
int tabIndex = 0;
Point labelPoint = panel.Location + new Size(20, 20);
Size initialOffset = new Size(0, 30);
Size horizontalOffset = new Size(40, 0);
Size tBoxSize = new Size(40,20);
foreach (string parameter in formParameters)
{
Label label = new Label
{
Text = parameter,
Tag = "Parameter Label",
Name = $"lbl{parameter}",
Location = (labelPoint += initialOffset)
};
TextBox textBox = new TextBox
{
AcceptsTab = true,
TabIndex = tabIndex++,
Text = "",
Tag = parameter,
Name = $"txt{parameter}",
MaximumSize = tBoxSize,
MinimumSize = tBoxSize,
Size = tBoxSize,
Location = labelPoint + horizontalOffset
};
controlPairs.Add(new Pair<Label, TextBox>(label, textBox));
}
foreach (Pair<Label, TextBox> pair in controlPairs)
{
panel.Controls.Add(pair.First);
panel.Controls.Add(pair.Second);
}
}
I don't believe that my use of Point + Size is the issue as the Point class overrides the + operator like so:

Unfortunately for me the issue appears to be simply that the dX was not a big enough value to prevent the text boxes from being hidden under the labels, I forgot that labels don't have transparent backgrounds.
While I was at it: I've removed the redundant List<Pair<<>>; added support for dynamically adjusting TextBox location based on Label size; and split it out into two separate loops, so my code now looks as below and works just fine:
private void GenerateControls(string formType)
{
string[] formParameters = engine.GetFormParameters(formType);
if (formParameters == null) return;
SplitterPanel panel = splitContainer.Panel1;
panel.Controls.Clear();
int tabIndex = 0;
Point labelPoint = panel.Location + new Size(20, 20);
Size verticalOffset = new Size(0, 30);
Size tBoxSize = new Size(200,20);
int maxLabelLength = 0;
foreach (string parameter in formParameters)
{
Label label = new Label
{
Text = parameter,
Tag = "Parameter Label",
Name = $"lbl{parameter}",
Location = (labelPoint += verticalOffset),
AutoSize = true
};
panel.Controls.Add(label);
if (label.Size.Width > maxLabelLength)
{
maxLabelLength = label.Size.Width;
}
}
Size horizontalOffset = new Size(maxLabelLength + 30, 0);
labelPoint = panel.Location + new Size(20, 20) + horizontalOffset;
foreach (string parameter in formParameters)
{
TextBox textBox = new TextBox
{
AcceptsTab = true,
TabIndex = tabIndex++,
Text = "",
Tag = parameter,
Name = $"txt{parameter}",
MaximumSize = tBoxSize,
MinimumSize = tBoxSize,
Size = tBoxSize,
Location = labelPoint += verticalOffset
};
panel.Controls.Add(textBox);
}
}
Thanks everyone who helped!

Related

Dynamically created controls names not increasing its value through loops C#

I'm working on a personal project where I'm building a notes generator, and I have this TextBox dynamically created everytimes a button is clicked, it works fine just like how I expected but things gets weird when I tried to name each of these TextBox to different name by using a loop Name = "Note" + i where i is the loop variable.
So what I was expecting to happens is that each of the TextBox names to be something like Note1 Note2 Note3 ... but instead when I retrieved each of the TextBox name to a MessageBox in the same loop which is used to generates the TextBox, the MessageBox throws this: Note 1 Note 1 Note 1 ... instead when I clicked the button thrice.
int curr = 0;
private void guna2Button1_Click(object sender, EventArgs e) {
int top = 25;
int h_p = 170;
curr++;
for(int i=1; i<curr+1; i++) {
// Notes
var new_note = new Guna2TextBox() {
Text = "Title\n",
Name = "Note" + i,
Multiline = true,
AcceptsTab = true,
AcceptsReturn = true,
WordWrap = false,
ScrollBars = ScrollBars.Vertical,
Width = 220,
Height = 110,
BorderRadius = 8,
Font = new Font("Bahnschrift", 13),
ForeColor = Color.White,
FillColor = ColorTranslator.FromHtml("#1E1E1E"),
BorderColor = ColorTranslator.FromHtml("#2C2C2C"),
Location = new Point(450,top)
};
MessageBox.Show(i.ToString());
top += h_p;
flowLayoutPanel1.Controls.Add(new_note);
curr = 0;
}
}
The problem is caused by the fact that inside the loop you set always curr back to zero. And the loop is not needed at all because you want to add a textbox at each click. So you just need to look at the Count property of the FlowLayoutPanel and use that value to prepare the name.
Another problem to solve is how to position the next control inside the panel but again you could calculate easily with a the Count property
private void guna2Button1_Click(object sender, EventArgs e)
{
int nextTop = 25 + (flowLayoutPanel.Controls.Count * 170);
var new_note = new Guna2TextBox() {
Text = "Title\n",
Name = "Note" + flowLayoutPanel.Controls.Count + 1,
.....
Location = new Point(450,nextTop)
};
flowLayoutPanel1.Controls.Add(new_note);
}
I don't think you need to use the For loop in this case. You can just use the variable curr for each textboxes. So instead of the For loop, you can use this :
int top = 25;
int h_p = 170;
curr++;
var new_note = new Guna2TextBox() {
Text = "Title\n",
Name = "Note" + curr,
Multiline = true,
AcceptsTab = true,
AcceptsReturn = true,
WordWrap = false,
ScrollBars = ScrollBars.Vertical,
Width = 220,
Height = 110,
BorderRadius = 8,
Font = new Font("Bahnschrift", 13),
ForeColor = Color.White,
FillColor = ColorTranslator.FromHtml("#1E1E1E"),
BorderColor = ColorTranslator.FromHtml("#2C2C2C"),
Location = new Point(450,top)
top += h_p;
flowLayoutPanel1.Controls.Add(new_note);
};

Zoom Image using WPF MVVM, will move the top layer controls. How can it be fixed on image zoom time?

Currently i am working on image processing project, where i have one review screen in which i set the image on image container, and on top of the image, all four corners has meta data, which are fixed. Means while i zoom in/out the image, the top content will remain at the fixed position not move. This is my requirement.
Now i have set all content dynamically using the stack panel and all meta data will stay on fixed position except the bottom right position, which will be moved while image is zoomed in/out.
below is the reference screen shot where red mark shows the metadata will moved and hide at right side.
Here is the code for bottom right content
public async Task<ScrollViewer> CreateNewScrollViewer(ImageInfo item)
{
ScrollViewer scrollViewerObj = new ScrollViewer();
byte[] rawData;
try
{
//this will update the values of any older sharpness data to 5
if (item.AnnotationSchemaVersion != null && item.AnnotationSchemaVersion.Equals("1.0", StringComparison.InvariantCulture))
{
item.AdjustmentValue.Sharpness = item.BytePerPixel == 3 ? _samSettingsManager.GetTrueColorSharpnessDefaultValue() : _samSettingsManager.GetSingleColorSharpnessDefaultValue();
var saveSharpness = new Task(() => this.UpdateImageAnalysis(item));
saveSharpness.Start();
}
scrollViewerObj.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_ScrollViewer");
scrollViewerObj.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_ScrollViewer");
scrollViewerObj.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
scrollViewerObj.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
scrollViewerObj.Margin = new Thickness(5, 5, 5, 5);
scrollViewerObj.Focusable = true;
scrollViewerObj.SizeChanged += new SizeChangedEventHandler(ScrollViewerSizeChanged);
Point? fixationTarget = null;
Point? foveaXY = null;
Point? onhXY = null;
FixationType fixationMode = FixationType.Internal;
bool performDistortionCorrection = false;
// Provide fixation values only for WF and Non-External(Non-AnteriorSegment) scans, as distortion correction shall only be applied to WF and Non-External(Non-AnteriorSegment) images.
// All composite UWF/Montage/Auto-Montage images will be distortion corrected (Montage algorithm generates distortion corrected image)
if (Convert.ToInt32(item.FOV, CultureInfo.InvariantCulture) == FOVConstants.Widefield &&
item.ExamMode != ExamModes.AnteriorSegment && SAMConstants.SAMExamSourceUID == item.ExamSourceUID)
{
fixationTarget = item.FixationXY;
foveaXY = item.FoveaXY;
onhXY = item.ONHXY;
fixationMode = item.FixationMode;
performDistortionCorrection = true;
}
//bool isOD = item.Laterality == "OD" ? true : false;
string imageCacheFilePath = _imageCacheFilePath;
string imageFileName = System.IO.Path.GetFileName(item.ImagePath);
//creates the image cache folder if it doesn't exist
if (!Directory.Exists(imageCacheFilePath))
Directory.CreateDirectory(imageCacheFilePath);
ImageContainer imageObj = new ImageContainer(_pixelBufferSize);
await Task.Run(() =>
{
imageObj.Initialize(item.ImagePath, item.ImageCompressionType,
item.ImageWidth, item.ImageHeight, item.BytePerPixel, item.ExamSourceUID, item.Laterality, imageCacheFilePath, _pixelBufferSize, fixationTarget,
foveaXY, item.ProjectedXMin, item.ProjectedYMax, item.ProjectedXMax, item.ProjectedYMin, performDistortionCorrection,
onhXY, fixationMode, item.ONHIdentificationMode);
});
imageObj.InitializeZoomValues(((int)ActualHeight - 40) / 4, ((int)ActualWidth - 40) / 4);
PyramidTools.PyramidImageProcessing processImage = new PyramidTools.PyramidImageProcessing();
//Sets up the pyramid
if (!System.IO.File.Exists(imageCacheFilePath + imageFileName + ExtensionConstants.Raw) || (!System.IO.File.Exists(imageCacheFilePath + imageFileName + ExtensionConstants.Text) && SAMConstants.SAMExamSourceUID == imageObj.ExamSourceUID))
{
rawData = imageObj.ImageDataObj.GetData();
if (rawData != null)
{
processImage.CreatePyramidForGivenImage(rawData, item.BytePerPixel, (int)imageObj.ImageZoom.LowestZoomPercentage, imageFileName, imageObj.ImageDataObj.Width, imageObj.ImageDataObj.Height, imageCacheFilePath);
}
}
else if (!processImage.IsPyramidCreated(imageCacheFilePath + imageFileName, (int)imageObj.ImageZoom.LowestZoomPercentage))
{
rawData = File.ReadAllBytes(imageCacheFilePath + imageFileName + ExtensionConstants.Raw);
if (rawData != null)
{
processImage.CreatePyramidForGivenImage(rawData, item.BytePerPixel, (int)imageObj.ImageZoom.LowestZoomPercentage, imageFileName, imageObj.ImageDataObj.Width, imageObj.ImageDataObj.Height, imageCacheFilePath);
}
}
// For image sharpness
imageObj.ImageProcessing = imageProcessing;
imageObj.TrueColorSharpnessRadius = _trueColorSharpnessRadius;
imageObj.TrueColorSharpnessMinAmount = _trueColorSharpnessMinAmount;
imageObj.TrueColorSharpnessMaxAmount = _trueColorSharpnessMaxAmount;
imageObj.TrueColorSharpnessResizeFactor = _trueColorSharpnessResizeFactor;
imageObj.SingleColorSharpnessRadius = _singleColorSharpnessRadius;
imageObj.SingleColorSharpnessMinAmount = _singleColorSharpnessMinAmount;
imageObj.SingleColorSharpnessMaxAmount = _singleColorSharpnessMaxAmount;
imageObj.SingleColorSharpnessResizeFactor = _singleColorSharpnessResizeFactor;
imageObj.TrueColorSharpnessFactor = _trueColorSharpnessFactor;
imageObj.SingleColorSharpnessFactor = _singleColorSharpnessFactor;
imageObj.IsConstituteImage = item.IsConstituteImage;
imageObj.FOV = item.FOV;
imageObj.SelectedChannel = ChannelTypes.TrueColorChannel;
imageObj.TonalOptimizedValues = new Tonal(128, 128, 128);
imageObj.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_ImageContainer");
imageObj.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_ImageContainer");
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/SAMProduction.FundusImageDisplay;component/Images/RotateBlue.png");
logo.EndInit();
imageObj.ImageRotationShow = new System.Windows.Controls.Image();
imageObj.ImageRotationShow.Source = logo;
imageObj.ImageRotationShow.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_180DegreeIcon");
imageObj.ImageRotationShow.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_180DegreeIcon");
//imageObj.ImageRotationShow.SetResourceReference(Canvas.BackgroundProperty, "180DegreeIcon");
imageObj.ImageRotationShow.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
imageObj.ImageRotationShow.VerticalAlignment = System.Windows.VerticalAlignment.Top;
imageObj.ImageRotationShow.Visibility = System.Windows.Visibility.Collapsed;
imageObj.ImageRotationShow.Width = 30;
imageObj.ImageRotationShow.Height = 30;
imageObj.ImageRotationShow.Margin = new Thickness(0, 10, 0, 0);
imageObj.ImageFrameNoMessage = item.ImageFrameNoMessage;
Style textBlockStyle = this.TryFindResource("TextWhite16") as Style;
#region Top Left Panel Information
StackPanel topLeftPanelInfo = new StackPanel();
topLeftPanelInfo.Width = 160;
topLeftPanelInfo.Name = "TopLeftPanel";
topLeftPanelInfo.Uid = "TopLeftPanel";
topLeftPanelInfo.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
topLeftPanelInfo.VerticalAlignment = System.Windows.VerticalAlignment.Top;
topLeftPanelInfo.Margin = new Thickness(10, 5, 0, 0);
UpdateTopLeftPanel(item, imageObj, topLeftPanelInfo, textBlockStyle);
#endregion
#region Bottom Left Panel Information
StackPanel bottomLeftPanelInfo = new StackPanel();
bottomLeftPanelInfo.Name = "BottomLeftPanel";
bottomLeftPanelInfo.Uid = "BottomLeftPanel";
bottomLeftPanelInfo.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
bottomLeftPanelInfo.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
bottomLeftPanelInfo.Margin = new Thickness(10, 0, 0, 5);
UpdateBottomLeftPanel(item, imageObj, bottomLeftPanelInfo, textBlockStyle);
#endregion
#region Bottom Right Panel Information
StackPanel bottomRightPanelInfo = new StackPanel();
bottomRightPanelInfo.Name = "BottomRightPanel";
bottomRightPanelInfo.Uid = "BottomRightPanel";
bottomRightPanelInfo.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_BottomRightPanelInfo");
bottomRightPanelInfo.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_BottomRightPanelInfo");
bottomRightPanelInfo.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
bottomRightPanelInfo.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
bottomRightPanelInfo.Margin = new Thickness(0, 0, 10, 5);
UpdateBottomRightPanel(item, imageObj, bottomRightPanelInfo, textBlockStyle);
#endregion
#region Top Right Panel Information
StackPanel topRightPanelInfo = new StackPanel();
topRightPanelInfo.Name = "TopRightPanel";
topRightPanelInfo.Uid = "TopRightPanel";
topRightPanelInfo.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_TopRightPanelInfo");
topRightPanelInfo.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_TopRightPanelInfo");
topRightPanelInfo.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
topRightPanelInfo.VerticalAlignment = System.Windows.VerticalAlignment.Top;
topRightPanelInfo.Margin = new Thickness(0, 5, 10, 0);
UpdateTopRightPanel(item, imageObj, topRightPanelInfo, textBlockStyle);
#endregion
Grid gridObj = new Grid() { ClipToBounds = true };//
gridObj.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_Grid");
gridObj.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_Grid");
gridObj.Children.Add(imageObj);
if (topLeftPanelInfo != null)
{
gridObj.Children.Add(topLeftPanelInfo);
}
if (bottomLeftPanelInfo != null)
{
gridObj.Children.Add(bottomLeftPanelInfo);
}
if (topRightPanelInfo != null)
{
gridObj.Children.Add(topRightPanelInfo);
}
if (bottomRightPanelInfo != null)
{
gridObj.Children.Add(bottomRightPanelInfo);
}
gridObj.Children.Add(imageObj.SelectedBorder);
gridObj.Children.Add(imageObj.ImageRotationShow);
gridObj.Children.Add(imageObj.OverlayGrid);
imageObj.OverlayGrid.MouseLeftButtonUp += OverlayGrid_MouseLeftButtonUp;
imageObj.OverlayGrid.MouseMove += OverlayGrid_MouseMove;
imageObj.OverlayGrid.MouseLeftButtonDown += OverlayGrid_MouseLeftButtonDown;
imageObj.OverlayGrid.PreviewMouseRightButtonDown += OverlayGrid_PreviewMouseRightButtonDown;
imageObj.OverlayGrid.PreviewMouseRightButtonUp += OverlayGrid_PreviewMouseRightButtonUp;
scrollViewerObj.Content = gridObj;
// This binding required to align image properly when it is loading.
Binding HeightBinding = new Binding();
RelativeSource relativeheightSource = new RelativeSource();
relativeheightSource.Mode = RelativeSourceMode.FindAncestor;
relativeheightSource.AncestorType = typeof(ScrollViewer);
HeightBinding.RelativeSource = relativeheightSource;
HeightBinding.Path = new PropertyPath("ActualHeight");
HeightBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
HeightBinding.Mode = BindingMode.OneWay;
imageObj.SetBinding(System.Windows.Controls.Image.HeightProperty, HeightBinding);
Binding WidthBinding = new Binding();
RelativeSource relativeWidthSource = new RelativeSource();
relativeWidthSource.Mode = RelativeSourceMode.FindAncestor;
relativeWidthSource.AncestorType = typeof(ScrollViewer);
WidthBinding.RelativeSource = relativeWidthSource;
WidthBinding.Path = new PropertyPath("ActualWidth");
WidthBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
WidthBinding.Mode = BindingMode.OneWay;
imageObj.SetBinding(System.Windows.Controls.Image.WidthProperty, WidthBinding);
imageObj.ImageSourceChanged += this.ImageObj_ImageSourceChanged;
imageObj.ZoomValueChanged += this.ImageObj_ZoomValueChanged;
scrollViewerObj.AllowDrop = true;
scrollViewerObj.Drop += ScrollViewer_Drop;
imageObj.ContainerTonalValueChanged += ImageObj_ContainerTonalValueChanged;
// Previously MouseLeftButtonDown event was used.
// Change set no 141851 has change code of CreateNewScrollViewer(). He set Scrollviewer’s Focable property to true.
// It is required to set focusable true for that change set.
// In ScrollViewer's original code (.net code) it is handling event (e.Handled = true) if it can get focus.
// So side effect of 141851 change set is MouseLeftButtonDown event of scrollviewer do not get call when mouse down on it.
// So it misbehaves.
// So here PreviewMouseLeftButtonDown event used.
scrollViewerObj.PreviewMouseLeftButtonDown += ScrollViewerObj_PreviewMouseLeftButtonDown;
scrollViewerObj.MouseLeftButtonUp += this.ScrollViewerObj_MouseLeftButtonUp;
scrollViewerObj.PreviewMouseWheel += ScrollViewerObj_PreviewMouseWheel;
// No need to handle this event
//imageObj.SizeChanged += this.ImageObj_SizeChanged;
imageObj.MouseMove += this.ImageObj_MouseMove;
imageObj.MouseLeftButtonDown += this.ImageObj_MouseLeftButtonDown;
imageObj.MouseLeftButtonUp += this.ImageObj_MouseLeftButtonUp;
gridObj.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
gridObj.VerticalAlignment = System.Windows.VerticalAlignment.Center;
//It is not necessary to initalize the data
imageObj.ImageID = item.ImageId;
//imageObj.ImagePath = item.ImagePath;
if (imageObj.ExamSourceUID == SAMConstants.SAMExamSourceUID &&
imageObj.ExamMode != ExamModes.AnteriorSegment)
imageObj.OverlayGrid.IsHitTestVisible = IsOverlayGridEnable;
else
imageObj.OverlayGrid.IsHitTestVisible = false;
// imageObj.OverlayGrid.IsHitTestVisible = IsOverlayGridEnable;
//imageObj.ImageSource = imageObj.ImageDataObj;
scrollViewerObj.ContextMenu = CreateContextMenu(scrollViewerObj, imageObj); // set contextmenu
}
catch (Exception ex)
{
_services.Logger.Log(LogLevel.Error, "SAMProduction.FundusImageDisplay", "ImageEditViewerBase", "CreateNewScrollViewer: Error occurred while creating new scrollviewer. : " + ex);
}
finally
{
rawData = null;
}
return scrollViewerObj;
}
Please, let me help out to resolve the moved content on top layer of image, if any one can do. Thanks in Advance.
I find creating views in code very unreadable, so this is how to achieve this in XAML:
<Grid>
<Image .../> // or whatever custom control you use to allow zoom
<StackPanel Name="TopLeft HorizontalAligment="Left" VerticalAligment="Top">
<contente: labels etc ../>
</StackPanel>
...
<StackPanel Name="BottomRight" HorizontalAligment="Right" VerticalAligment="Bottom">
<contente: labels etc ../>
</StackPanel>
</Grid>
The trick is to wrap everything that you want to be in the same place and/or overlay in a Grid. If the StackPanels are after an Image in Grid content, their z-index will be higher and they will be displayed on top of the image.
The Image control by default will be streched to the whole grid, so you should manipulate the zoom with its content, not its size. If that's problematic, just wrap the Image control with another panel, or at best, custom UserControl and work out the size issues there.
Thanks to the Grid, the StackPanels will anchored to the corners, no matter the size and shape of the grid.
Also, you used tag MVVM and your code is almost textbook non-MVVM.
Maybe this will help you rewrite your code.

Dynamic dialog boxes

I am working with Winforms and I have a question about making these more dynamic. For instance I can create a winform that has a group of text boxes that displays data however how would I make this dynamic? In terms of the number of text boxes the user can see depends on what data is found?
I know I can do something along the lines of the below:
TextBox tb = new TextBox();
In my scenario I have an application that reads through a bunch of documents and if a $ is found then a prompt appears asking the user to input a proper value, however, if the document has a lot of values that need updating then this is a lot of dialog boxes. So a good way to resolve this is to have the dialog box appear at the end (after the file has been read) with all the values that need updating and the user can update all these at once.
The problem that I see is that the number of values that need to be displayed can be anything from 1 on wards, which means the loop would need to account for this.
My current code is as below;
foreach (FileInfo fi in rgFiles)
{
current++;
fileProcessBar.Value = current / count * 60 + 40;
string[] alllines = File.ReadAllLines(fi.FullName);
for (int i = 0; i < alllines.Length; i++)
{
if (alllines[i].Contains("$"))
{
// prompt
int dollarIndex = alllines[i].IndexOf("--");
Regex regex = new Regex(#"(--.{1,100})");
var chars = regex.Match(alllines[i]).ToString();
string PromptText = chars.Replace("-", "");
string promptValue = CreateInput.ShowDialog(PromptText, fi.FullName);
if (promptValue.Equals(""))
{
}
else
{
alllines[i] = alllines[i].Replace("$", promptValue);
File.WriteAllLines(fi.FullName, alllines.ToArray());
}
}
}
prompt method:
public static string ShowDialog(string text, string caption)
{
Form prompt = new Form()
{
Width = 600,
Height = 150,
FormBorderStyle = FormBorderStyle.FixedDialog,
Text = caption,
StartPosition = FormStartPosition.CenterScreen
};
Label textLabel = new Label() { Left = 50, Top = 15, Width = 500, Text = text };
TextBox textBox = new TextBox() { Left = 50, Top = 52, Width = 500 };
Button confirmation = new Button() { Text = "Add", Left = 450, Width = 100, Top = 72, DialogResult = DialogResult.OK };
confirmation.Click += (sender, e) => { prompt.Close(); };
prompt.Controls.Add(textBox);
prompt.Controls.Add(confirmation);
prompt.Controls.Add(textLabel);
prompt.AcceptButton = confirmation;
prompt.MaximizeBox = false;
return prompt.ShowDialog() == DialogResult.OK ? textBox.Text : "";
}
My question is how can a winform be more dynamic as in terms of size and what is displayed? how can I create a new form without specifying size and position? but still not being a jumbled mess?
Make a new Form with a certain size. Then add a FlowLayoutPanel to the form which has almost the same width as the form and almost the same height. Leave enough space for the button that you need:
In the panel properties set the fields AutoSize to true and AutoSizeMode to GrowAndShrink:
Don't forget to specify the FlowDirection:
this.panel.FlowDirection = FlowDirection.TopDown;
Now you need just a method which adds your prompting controls to the controls of the FlowLayoutPanel (which will order them in an automatic fashion) :
public void AddToCanvas(string text)
{
this.flowLayoutPanel1.Controls.Add(new Label() {Text = text});
this.flowLayoutPanel1.Controls.Add(new TextBox());
Resize();
}
And a resize method to adjust the form to the amount of current controls inside it:
public void Resize()
{
Size s = new Size();
s.Height = this.flowLayoutPanel1.Height + this.button_Accept.Height +
(this.flowLayoutPanel1.Controls.Count * 10) + y_offset;
s.Width = this.flowLayoutPanel1.Width + 10;
this.MaximumSize = s;
this.Size = s;
}
With this input:
random text
$ Name
$ Address
random text
$ Age
random text
$ Planet
$ Continent
random text
$ StarSystem
I get the following Result:
EDIT:
Create a variable after you have read the contents of one file (before you loop through the lines):
DynamicPrompt dp = new DynamicPrompt("YourCaption");
for (int i = 0; i < alllines.Length; i++)
{
if (alllines[i].Contains("$"))
{
Start the loop and if you get to the important line call
dp.AddToCanvas(PromptText);

Can't put a horizontal scroll on my TableLayoutPanel

I have a form in which there is a TableLayoutPanel in which there are several RadioButtons.
The form has a fixed size and the controls are dynamically generated.
Sometimes, the text of the RadioButtons is too long to be entirely displayed and I'd like to enable a horizontal scroll to the TableLayout in this case. But no matter how I tried, I can't figure out how to do it. Simply setting the TableLayoutPanel Autoscroll property to true did nothing.
I've tried to nest the TableLayout inside a Panel, but it didn't work. I've tried to put each RadioButton inside a Panel, then put the Panel inside the TableLayout. This made the horizontal scroll appear but of course the RadioButtons weren't in the same container any more so they were independant from each other. I've messed with several properties of the controls but to no avail.
I really have no idea what to do.
Here is how the controls are generated (this is the original code, prior to my modifications) :
public static Panel ChoicePanel(string title, string description, string internalName, bool radio, string oldValue, List<string> choices, int num, bool required)
{
var nbrow = (string.IsNullOrWhiteSpace(description) ? 1 : 2);
var nbcol = 1; var currentRow = realFirstRow;
if (radio) nbrow += choices.Count();
else nbrow += 1;
var panel = GeneratePanel(title, nbcol, nbrow, num, required);
foreach (var ch in choices)
{
var rb = new RadioButton()
{
Name = "rb" + internalName + currentRow,
Text = ch,
Checked = !string.IsNullOrEmpty(oldValue) && ch == oldValue,
Dock = DockStyle.Fill,
AutoCheck = true,
};
panel.Controls.Add(rb, firstCol, currentRow);
currentRow++;
}
AddDescription(description, currentRow, panel);
return panel;
}
private static TableLayoutPanel GeneratePanel(string title, int numcol, int numlines, int num, bool required)
{
var panel = new TableLayoutPanel()
{
AutoSize = true,
AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly,
Dock = DockStyle.Fill,
ColumnCount = numcol + 1,
RowCount = numlines,
Name = "panel" + num,
};
for (var i = 0; i < numlines; i++)
{
panel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
}
((Panel)panel).Margin = new Padding(5, 10, 10, 5);
var lTitle = GenerateTitle(title, required);
panel.Controls.Add(lTitle, 1, 0);
panel.SetColumnSpan(lTitle, numcol);
var labColor = new Label()
{
Dock = DockStyle.Fill,
BackColor = notErrorColor,
Name = "lbColor",
};
panel.Controls.Add(labColor, 0, 0);
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 10));
panel.SetRowSpan(labColor, numlines);
return panel;
}
Please note that it was someone else who wrote this code, but I will try to answer questions as best as I can.
Thanks for your help.

Visual Studio-style undo drop-down button - custom ToolStripSplitButton

I'm looking to implement a Visual Studio-style undo drop-down button:
I've looked all over the internet, and can't seem to find any real implementations of this.
I've started by deriving from ToolStripSplitButton, but don't really know where to go from there. Its DropDown property is a ToolStripDropDown, but that doesn't seem to have anything regarding multiple items being selected, much less scrolling, and the text at the bottom.
So instead of the default ToolStripDropDown, I'm thinking maybe the whole drop down part should be a custom control, based on a combobox. The question then, is how to cause the right-side (drop down arrow) button to do something other than show its default drop down?
Am I on the right track here? Thanks!
Yes, I think you're on the right track. And in this case, ToolStripControlHost is your friend.
You don't necessarily need to derive from it (unless you are making your own control), but try just subscribing to the ToolStripSplitButton's DropDownOpening event:
Working example:
private ListBox listBox1;
public Form1()
{
InitializeComponent();
listBox1 = new ListBox();
listBox1.IntegralHeight = false;
listBox1.MinimumSize = new Size(120, 120); \\ <- important
listBox1.Items.Add("Item 1");
listBox1.Items.Add("Item 2");
}
private void toolStripSplitButton1_DropDownOpening(object sender, EventArgs e) {
ToolStripControlHost toolHost = new ToolStripControlHost(listBox1);
toolHost.Size = new Size(120, 120);
toolHost.Margin = new Padding(0);
ToolStripDropDown toolDrop = new ToolStripDropDown();
toolDrop.Padding = new Padding(0);
toolDrop.Items.Add(toolHost);
toolDrop.Show(this, new Point(toolStripSplitButton1.Bounds.Left,
toolStripSplitButton1.Bounds.Bottom));
}
Here is the result:
For your application, you would need to replace the ListBox with your own UserControl, so you can contain whatever your want in it. The ToolStripControlHost can only hold one control, and it's important to set the MinimumSize property, or else the dropped control isn't sized correctly.
Extra thanks to LarsTech! (I didn't know about ToolStripControlHost a few hours ago)
Here is my implementation, which is really close to the VS drop down...
You should be able to just drop this delegate & function into your Form:
public delegate void UndoRedoCallback(int count);
private void DrawDropDown(ToolStripSplitButton button, string action, IEnumerable<string> commands, UndoRedoCallback callback)
{
int width = 277;
int listHeight = 181;
int textHeight = 29;
Panel panel = new Panel()
{
Size = new Size(width, textHeight + listHeight),
Padding = new Padding(0),
Margin = new Padding(0),
BorderStyle = BorderStyle.FixedSingle,
};
Label label = new Label()
{
Size = new Size(width, textHeight),
Location = new Point(1, listHeight - 2),
TextAlign = ContentAlignment.MiddleCenter,
Text = String.Format("{0} 1 Action", action),
Padding = new Padding(0),
Margin = new Padding(0),
};
ListBox list = new ListBox()
{
Size = new Size(width, listHeight),
Location = new Point(1,1),
SelectionMode = SelectionMode.MultiSimple,
ScrollAlwaysVisible = true,
Padding = new Padding(0),
Margin = new Padding(0),
BorderStyle = BorderStyle.None,
Font = new Font(panel.Font.FontFamily, 9),
};
foreach (var item in commands) { list.Items.Add(item); }
if (list.Items.Count == 0) return;
list.SelectedIndex = 0;
ToolStripControlHost toolHost = new ToolStripControlHost(panel)
{
Size = panel.Size,
Margin = new Padding(0),
};
ToolStripDropDown toolDrop = new ToolStripDropDown()
{
Padding = new Padding(0),
};
toolDrop.Items.Add(toolHost);
panel.Controls.Add(list);
panel.Controls.Add(label);
toolDrop.Show(this, new Point(button.Bounds.Left + button.Owner.Left, button.Bounds.Bottom + button.Owner.Top));
// *Note: These will be "up values" that will exist beyond the scope of this function
int index = 1;
int lastIndex = 1;
list.Click += (sender, e) => { toolDrop.Close(); callback(index); };
list.MouseMove += (sender, e) =>
{
index = Math.Max(1, list.IndexFromPoint(e.Location) + 1);
if (lastIndex != index)
{
int topIndex = Math.Max(0, Math.Min(list.TopIndex + e.Delta, list.Items.Count - 1));
list.BeginUpdate();
list.ClearSelected();
for (int i = 0; i < index; ++i) { list.SelectedIndex = i; }
label.Text = String.Format("{0} {1} Action{2}", action, index, index == 1 ? "" : "s");
lastIndex = index;
list.EndUpdate();
list.TopIndex = topIndex;
}
};
list.Focus();
}
You can set it up and test like this, assuming you have a blank form (Form1) with a toolStrip that has 1 ToolStripSplitButton (toolStripSplitButton1) added:
public Form1()
{
InitializeComponent();
// Call DrawDropDown with:
// The clicked ToolStripSplitButton
// "Undo" as the action
// TestDropDown for the enumerable string source for the list box
// UndoCommands for the click callback
toolStripSplitButton1.DropDownOpening += (sender, e) => { DrawDropDown(
toolStripSplitButton1,
"Undo",
TestDropDown,
UndoCommands
); };
}
private IEnumerable<string> TestDropDown
{
// Provides a list of strings for testing the drop down
get { for (int i = 1; i < 1000; ++i) { yield return "test " + i; } }
}
private void UndoCommands(int count)
{
// Do something with the count when an action is clicked
Console.WriteLine("Undo: {0}", count);
}
Here is a better example using the Undo/Redo system from: http://www.codeproject.com/KB/cs/AutomatingUndoRedo.aspx
public Form1()
{
InitializeComponent();
// Call DrawDropDown with:
// The Undo ToolStripSplitButton button on the Standard tool strip
// "Undo" as the action name
// The list of UndoCommands from the UndoRedoManager
// The Undo method of the UndoRedoManager
m_TSSB_Standard_Undo.DropDownOpening += (sender, e) => { DrawDropDown(
m_TSSB_Standard_Undo,
"Undo",
UndoRedoManager.UndoCommands,
UndoRedoManager.Undo
); };
}
*Note: I did modify the Undo & Redo methods in the UndoRedoManager to accept a count:
// Based on code by Siarhei Arkhipenka (Sergey Arhipenko) (http://www.codeproject.com/KB/cs/AutomatingUndoRedo.aspx)
public static void Undo(int count)
{
AssertNoCommand();
if (CanUndo == false) return;
for (int i = 0; (i < count) && CanUndo; ++i)
{
Command command = history[currentPosition--];
foreach (IUndoRedo member in command.Keys)
{
member.OnUndo(command[member]);
}
}
OnCommandDone(CommandDoneType.Undo);
}
I'd suggest implementing the popup separately from the toolbar button. Popups are separate windows with a topmost-flag which auto-close when losing focus or pressing escape. If you code your own popup window that frees you from having to fit your behaviour to a preexisting model (which is going to be hard in your case). Just make a new topmost window with a listbox and status bar, then you are free to implement the selection behavior on the listbox like you need it.
Vs 2010 is a WPF application. If you are in the beginning of this application development than use WPF as a core technology. WPF drop down button is implemented in WPF ribbon. Source code is available on CodePlex.

Categories