I am initializing an object with several properties. However, there are multiple properties that are always the same (styling).
Consider the following initializing block of code:
private static Button _saveButton = new Button
{
Text = "Save",
HorizontalOptions = LayoutOptions.Center,
WidthRequest = 500,
IsVisible = false
//applyStandard(this) ?
};
I would like to pass _saveButton to a method, which changes its TextColor and BorderColor property with something like void applyStandard(View v).
How could I do that, if possible?
You can't access the button instance in the initializer, but you can make an extension method that you call right after it:
public static class Extensions {
public static Button ApplyStandard(this Button button) {
button.TextColor = Colors.Red;
return button;
}
}
By returning the button from the extension method, you can chain it into the creation:
private static Button _saveButton = new Button {
Text = "Save",
HorizontalOptions = LayoutOptions.Center,
WidthRequest = 500,
IsVisible = false
}.ApplyStandard();
You can't do the in the object initializer. You need to separate the method call from initialization.
What you have is nearly there, i think youre approaching the problem from the wrong direction. As already mentioned, you cant do what youre proposing with object initialization syntax. The simplest way to solve your problem (without simply creating your own button type) would be to have a method that creates a button, and sets all of your common properties. You can then set any of the others on a per instance basis:
private static Button CreateCustomButton()
{
Button button = new Button();
button.ForeColor = Color.Black;
// set other properties, initial setup etc...
return button;
}
Related
I have design 1 winform to look like the picture. But I want the highlighted yellow part to be dockable with dockpanel suite reference. Is that do-able or any other suggestion of better design?
Right now the treeview is on the dockpanel and the red box part is a usercontrol placed in the same dockpanel. I tried to put the redbox as another form but I can't place it as it is in the picture. Also, this winform is need to be responsive so I put in the redbox part in a table layout panel.winform design and not familiar actually with the dockpanel suite reference. If there is a beginner tutorial that I can refer to, it would be much appreciated.
Current design:
There are two approach to your problem. First is dirty one and second elegant one. By dirty and elegant i mean way they display. Method they work are both same.
I will explain to you how to do it on empty form and you just implement that in your populated one.
First create new form.
Add 2 or more GroupBoxes to it
Add some items inside them (just to see if it works)
At the top of the each boxes add Button which will toggle visibility
Our form now looks like this and let's look of code behind it.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
public partial class TestForm : Form
{
// This is property
bool ShowFirstGroupBox
{
get
{
// We let user get our property from private variable
return _ShowFirstGroupBox;
}
set
{
// When user change this property we do something based on that
switch(value)
{
case true:
groupBox1.Size = new Size(groupBox1.Width, FirstGroupBoxDefaultHeight);
break;
case false:
groupBox1.Size = new Size(groupBox1.Width, 55);
break;
}
_ShowFirstGroupBox = value;
}
}
bool ShowSecondGroupBox
{
get
{
return _ShowSecondGroupBox;
}
set
{
switch (value)
{
case true:
groupBox2.Size = new Size(groupBox1.Width, FirstGroupBoxDefaultHeight);
break;
case false:
groupBox2.Size = new Size(groupBox1.Width, 55);
break;
}
_ShowSecondGroupBox = value;
}
}
// We store our boxes current state ( TRUE = shown, FALSE = HIDDEN )
bool _ShowFirstGroupBox = true;
bool _ShowSecondGroupBox = true;
// We store our default height for groupboxes
int FirstGroupBoxDefaultHeight;
int SecondGroupBoxDefaultHeight;
public TestForm()
{
InitializeComponent();
// Assigning default height of our groupboxes
FirstGroupBoxDefaultHeight = groupBox1.Height;
SecondGroupBoxDefaultHeight = groupBox2.Height;
}
private void button1_Click_1(object sender, EventArgs e)
{
ShowFirstGroupBox = !(_ShowFirstGroupBox); // This sets our property value to opposite of this boolean
}
private void button1_Click_1(object sender, EventArgs e)
{
ShowSecondGroupBox = !(_ShowSecondGroupBox); // This sets our property value to opposite of this boolean
}
}
}
Now when we have code like this and press button it will collapse groupbox.
NOTE: Controls under groupbox are still on place but just hidden since they are child of groupbox and everything outside of bounds is not visible to user.
This is dirty way since i would like to display it much prettier with MINUS sign on the right side of the groupbox title so i do not have button inside it. To do this you would need to create custom control which inherits groupbox, add button to it and position it in title bar and create event for it. It is easy if you have ever tried creating custom controls but if you haven't and you think dirty approach is okay with you then do not try it.
I made a custom TextBox so that I can have it bordered, that works fine...
The problem is that I want to set PasswordChar to *, and that doesn't workHere is my code:
public class TextBoxEx : TextBox
{
// The TextBox
private TextBox textBox = new TextBox();
// Border color of the textbox
private Color borderColor = Color.Gray;
// Ctor
public TextBoxEx()
{
this.PasswordChar ='*';
this.Paint += new PaintEventHandler(TextBoxEx_Paint);
this.Resize += new EventHandler(TextBoxEx_Resize);
textBox.Multiline = true;
textBox.BorderStyle = BorderStyle.None;
this.Controls.Add(textBox);
this.UseSystemPasswordChar = true;
InvalidateSize();
}
// Exposed properties of the textbox
public override string Text
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
// ... Expose other properties you need...
// The border color property
public Color BorderColor
{
get { return borderColor; }
set { borderColor = value; Invalidate(); }
}
// Expose the Click event for the texbox
public event EventHandler TextBoxClick
{
add { textBox.Click += value; }
remove { textBox.Click -= value; }
}
// ... Expose other events you need...
private void TextBoxEx_Resize(object sender, EventArgs e)
{
InvalidateSize();
}
private void TextBoxEx_Paint(object sender, PaintEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, borderColor, ButtonBorderStyle.Solid);
}
private void InvalidateSize()
{
textBox.Size = new Size(this.Width - 2, this.Height - 2);
textBox.Location = new Point(1, 1);
}
}
Generally when I try to set the properties of custom control by default it doesn't work, for example if I set
this.ReadOnly=true;
This won't work either. So the problem isn't in PasswordChar itself.
Anybody know the solution?
Since the class is itself inheriting the TextBox class, you don't need to create an inner textbox.
With that in mind, you can take out your declaration of private TextBox textBox, and replace references to this member with this, since this is a TextBox descendant.
In the constructor, you will also remove this.Controls.Add(textBox); since there is no longer an inner control to add.
The overridden Text property can also be removed, as it doesn't add functionality to the TextBox definition.
The InvalidateSize method will need to be reworked, since adjusting the Size member triggers the TextBoxEx_Resize handler method, which calls the InvalidateSize method again, eventually causing a StackOverflowException.
One last thing, and an important one. According to MSDN...
If the Multiline property is set to true, setting the PasswordChar property has no visual effect. When the PasswordChar property is set to true, cut, copy, and paste actions in the control using the keyboard cannot be performed, regardless of whether the Multiline property is set to true or false.
Meaning the textbox PasswordCharacter will not display if the textbox is Multiline
Im going to take a stab at this,
private TextBox textBox = new TextBox();
...
this.Controls.Add(textBox);
The above seems to be the problem,
It seems your shadow textbox is actually whats displaying,
If you need shadow properties in the back ground (and without really knowing your goal), probably just best creating the properties you need.
Basically I want to make functionality, when I input text to my Editor it will appear inserted data to my label. And if I will swipe page to another page, that data should be bind'ed to that label in previous page where I entered data.
So I have portable class. In that class I have method public ContentPage CreatePage(MyObject thing) here I define many Labels, boxes , buttons and etc. But I will indicate most important things: Here I am define my Label and Editor:
public partial class CoolPage: CarouselPage
{
public CoolPage()
{
foreach (MyObject p in things)
{
Children.Add(CreatePage(p));
}
}
public ContentPage CreatePage(MyObject thing) {
var emptyLabel = new Label
{
Text = "Text",
WidthRequest = 50,
HeightRequest = 50,
BackgroundColor = Color.White
};
((StackLayout)page.Content).Children.Add(emptyLabel);
var inputNumb = new Editor
{
Text=thing.Number,
TextColor = Color.Black,
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
IsVisible = true,
BackgroundColor = Color.White
};
inputNumb.SetBinding(Label.TextProperty, "Text");
inputNumb.BindingContext = thing.Number;
((StackLayout)page.Content).Children.Add(inputNumb);
}
}
I have tried to impelemnt such a event:
inputNumb.Completed += (sender, args) =>
{
inputNumb.SetBinding(Label.TextProperty, "Text");
inputNumb.BindingContext = thing.Number;
};
but it is not working. And I think because it is on same method. Also I tried to do out of method scope, by implementing such a line on CreatePage method inputCarNumb.Completed += InputCarNumb_Completed; But then when you define your variable inputNumb it doesn't recognize and I don't know how to implement in other case. I know it is very simple, but I think I miss something by doing SetBinding / BindingContext .
I solved this problem like this:
emptyLabel.SetBinding(Label.TextProperty, "Text");
emptyLabel.BindingContext = inputNumb;
Make sure your MyObject inherits from and implements INotifyPropertyChanged so that PropertyChanged fires whenever Number changes. I generally inherit from XLabs's ViewModel, and use their SetProperty method. Don't bother setting the binding in the event. But the 2nd parameter of SetBinding should be "Number" which is MyObject's property name. Also the BindingContext should = thing.
So I am developing a custom ButtonGUI class for my game. Here's the initialization of the button object:
// Button code:
ButtonGUI btn1 = new ButtonGUI("Button 1", new Rectangle(150, 300, (int)myFont.MeasureString(menuButtons[0]).X, (int)myFont.MeasureString(menuButtons[0]).Y), myFont, Color.CornflowerBlue);
Now consider this code:
// Draw() method:
btn1.Draw(spriteBatch);
if (btnHover)
{
btn1.btnRect = new Rectangle(140, 300, (int)hoverFont.MeasureString(menuButtons[0]).X, (int)hoverFont.MeasureString(menuButtons[0]).Y);
btn1.btnFont = hoverFont;
btn1.btnColour = Color.Red;
}
else
{
btn1.btnRect = new Rectangle(150, 300, (int)myFont.MeasureString(menuButtons[0]).X, (int)myFont.MeasureString(menuButtons[0]).Y);
btn1.btnFont = myFont;
btn1.btnColour = Color.CornflowerBlue;
}
This would be OK if I had only 1 button... But if I have like 10 buttons or more? This really isn't what DRY suggests. I feel like I'm missing something, there must be a way to return button properties to their default values once the condition is no longer met without doing the whole thing manually, or is there? Thanks in advance!
It may make sense to create a structure to hold all of the values that may change.
class ButtonData
{
// put members corresponding to each member of ButtonGUI you wish
// to change
}
class ButtonSwapper
{
ButtonGUI myButton;
ButtonData hoverData;
ButtonData notHoverData;
void change(bool hover)
{
ButtonData dataToUse = hover ? hoverData : notHoverData;
// set each relevant member of myButton to its pair in
// dataToUse
}
}
then call change as necessary.
I have a uvSelfLoadingTextBox with multiple instances on a form.
I would like to load the tooltip with the _value property at run time.
I've tried
public ucSelfLoadingTextBox()
{
Windows.Forms.ToolTip myToolTip;
myToolTip.AutomaticDelay = 5000;
myToolTip.AutoPopDelay = 50000;
myToolTip.InitialDelay = 100;
myToolTip.ReshowDelay = 500;
myToolTip.SetToolTip(this, _value);
inside the control but that does not work.
I have tried using the tooltip that is dragged onto the form
ucSelfLoadingLogicTextBox uc = new ucSelfLoadingLogicTextBox();
toolTipA.SetToolTip(uc,uc._value );
and that does not work.
What is the correct way to do this?
You forgot to instantiate myToolTip. You need to set it to new Tooltip().
Also, I don't think it's a good practice to assign the tooltip in the textbox's constructor. You could do this in OnCreateControl() (that you need to override).
Your code could therefore become:
protected override void OnCreateControl()
{
base.OnCreateControl();
var myToolTip = new System.Windows.Forms.ToolTip
{
AutomaticDelay = 5000,
AutoPopDelay = 50000,
InitialDelay = 100,
ReshowDelay = 500
};
myToolTip.SetToolTip(this, this.Text);
}
Many visible controls on windows form have ToolTip property. Just set the Tooltip with your newly created one. You can also add tooltip to your form. Have you tried this?
myToolTip.ShowAlways = true;
And try to set this tip to a button control. This may be a good test for your tooltip.