C# XNA if-else and defaulting to first value - c#

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.

Related

How to color one of the table layout pannel controls in c#

I've created a Windows Form which looks like this:
My Windows Form
What I want to do is to color one of these numbered buttons by passing its number to the Form constructor. Here is what I've tried to do, but there are no visible changes. Any suggestions?
public SeatSelection(string seatNumber)
{
InitializeComponent();
foreach(Control ctrl in this.tableLayoutPanel1.Controls)
{
if (ctrl.Text == seatNumber)
{
ctrl.BackColor = Color.Red;
}
}
}
The if statement does find true, and the BackColor does change, but the form wont update:
Watch
Sorry folks, my bad. This code was fine. I made a mistake somewhere else. I did not realised that I called the default constructor immediately after calling this one. Missed else keyword in my if statement, so it was
int seatNumber = Convert.ToInt32(txtSeatNumber.Text);
if(seatNumber>=1 && seatNumber<=21)
seats = new SeatSelection(txtSeatNumber.Text);
seats = new SeatSelection();
seats.Show();
Instead of
int seatNumber = Convert.ToInt32(txtSeatNumber.Text);
if(seatNumber>=1 && seatNumber<=21)
seats = new SeatSelection(txtSeatNumber.Text);
else
seats = new SeatSelection();
seats.Show();

Call self in object construction

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;
}

Return place in list on button press

I'm creating a collection of buttons based on the contents of a list I have in my program. I'm filling my list from a JSON file I'm parsing in and creating the buttons like so:
foreach(string ss in prop1)
{
if(GUI.Button(new Rect(0, 100+w, 100, 100), prop1[count].ToString()))
{
SelectType();
}
}
The list prop1 contains the values from the first set of keys in my JSON. Where in my program it returns and displays two buttons with the text Foo and Boo
When I click on Foo I need to be able to return that name so I can pass it into a check like so:
public void SelectType()
{
if (obj["building"].Value == "Foo")
{
GameObject sceneObject = GameObject.Find("#" + key);
sceneObject.renderer.material.color = Color.blue;
}
}
Where as opposed to hardcoding in Foo I pass in another paramenter based on the button click. However, I've no idea how to grab the name out of the list when I press it. Could someone please point me in the right direction and help me figure out how to do this?
Do you mean something like this?
foreach(string ss in prop1)
{
if(GUI.Button(new Rect(0, 100+w, 100, 100), prop1[count].ToString()))
{
SelectType(ss);
}
}
public void SelectType(string type)
{
if (obj["building"].Value == type)
{
GameObject sceneObject = GameObject.Find("#" + key);
sceneObject.renderer.material.color = Color.blue;
}
}

Editing properties of a PictureBox from another class

Context: I am trying to make a little game of Backgammon in Windows.Forms. I have 3 classes GameBoard.cs, Points.cs and Checkers.cs (as well as Form1.cs). What I need to be able to do is change values of some properties of a PictureBox using some of my other classes.
Specifically I have this code:
// gameBoard.cs
namespace backgammon
{
public class gameBoard
{
Checker checker1;
Points point1;
Points[] pointsArray;
public gameBoard()
{
// make new checker (ID, PictureBox, startingPoint)
checker1 = new Checker(1, checkerPicBox1, 1);
// make new Point (ID, arrayOfCheckers)
point13 = new Points(1, new Checker[]{checker1 /*,checker2... etc*/});
pointsArray = new Points[MAX_POINTS];
pointsArray[0] = point1;
}
}
}
so this is how I have "setup" the checkers and points. My checker and point classes can get and set on all variables that were passed into its construction.
Problem: what I am trying to achieve is to "highlight" a checker once it is clicked.
In Form1:
// Form1.cs
private void checkerPicBox1_Click(object sender, EventArgs e)
{
int pointNumber = gameBoard.checker1.getPointMember();
// find the top most checker in the checker array so we can highlight it
Checker topMost = gameBoard.pointsArray[pointNumber - 1].getCheckerFromIndex(gameBoard.pointsArray[pointNumber - 1].getCheckerArray().Length - 1);
// get the picturebox and change the image
topMost.getPictureBox().BackgroundImage = global::Backgammon.Properties.Resources.blackCheckerSelected;
}
The code compiles and runs but when it gets to the last line of checkerPicBox_Click nothing seems to happen (the image doesn't change).
What is happening here? Do I not have the correct instance of my PictureBox? Or am I doing this in a weird way/not the way i'm supposed to be?
Since the checkers are connected to the pictureboxes, why not create a new reference property for them in the Checker class?
You could pass the form containing the pictureboxes in the constructor, and use the form to create your references to the right picturebox instances.
// gameBoard.cs
namespace backgammon
{
public class gameBoard
{
Checker checker1;
Points point1;
Points[] pointsArray;
public gameBoard(Form gameForm)
{
// make new checker (ID, PictureBox, startingPoint)
checker1 = new Checker(1, gameForm.checkerPicBox1, 1);
// make new Point (ID, arrayOfCheckers)
point13 = new Points(1, new Checker[]{checker1 /*,checker2... etc*/});
pointsArray = new Points[MAX_POINTS];
pointsArray[0] = point1;
}
}
}
Add the picturebox property to your Checker class:
// checker.cs
public class Checker
{
PictureBox _picturebox;
//... other code here
public Checker(int ID, PictureBox picturebox, Points startingPoint)
{
_picturebox = picturebox;
//...other code here
}
}
Then we can use this in the game form:
gameBoard gameBoard1 = new gameBoard(this);
gameBoard1.checker1._picturebox.BackgroundImage = global::Backgammon.Properties.Resources.blackCheckerSelected;
gameBoard1.checker1._picturebox.Invalidate();

Common class for WPF Containers (Canvas, Grid, etc)

I am creating a method that is invoked by a button. The method then adds a canvas to the button's parent container control. So, e.g., the button is on a grid. Then the method creates a canvas that is shown just below the button. But I have 2 issues:
How can I get a reference to the button's parent container?
Is there a class for container controls? I don't care if the button is in a grid, a canvas, a Stackpanel, etc. So I am looking for an interface that all types of contianers implement or a class that they inherit.
The second aspect is more important as I could pass a reference to the container manually.
EDIT:
It should look like this (minus the colors, those are only to show the different elements.
The red canvas is supposed to pop up to handle a confirmation. Maybe even with a nice animation. My idea was to create a class that can be invoked similar to this:
MyPopup popup = new MyPopup("Are you sure?", "Yes", "No", delegateFirstButton, delegateSecondButton);
popup.Show();
My code so far is not yet a class but only a method. The text parts are hard coded for the moment. The marked line needs to be more flexible and is the reason for my question.
public void ShowPopup(Control senderControl)
{
//I need to have a parameter that accepts all containers instead of this line:
this.myGrid.Children.Add(popup);
Border border = new Border();
popup.Children.Add(border);
border.Margin = new Thickness() { Top = 10 };
border.Child= text;
text.Text = "Are you sure?";
text.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
popup.SizeChanged += delegate { border.Width = popup.ActualWidth; };
popup.Children.Add(btn1);
btn1.Content = "Yes";
btn1.Height = 22;
btn1.Padding = new Thickness(10, 0, 10, 0);
btn1.Margin = new Thickness() { Left = 15, Top = 35 };
popup.Children.Add(btn2);
btn2.Content = "No";
btn2.Height = 22;
btn2.Padding = new Thickness(10, 0, 10, 0);
btn1.SizeChanged += delegate { btn2.Margin = new Thickness() { Left = 30 + btn1.ActualWidth, Top = 35 }; };
popup.Height = 70;
btn2.SizeChanged += delegate
{
popup.Width = 45 + btn1.ActualWidth + btn2.ActualWidth;
updatePositions(senderControl);
};
popup.Background = Brushes.Red;
popup.VerticalAlignment = System.Windows.VerticalAlignment.Top;
popup.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
}
public void updatePositions(Control senderControl)
{
Point location = senderControl.TranslatePoint(new Point(0, 0), this.myGrid);
popup.Margin = new Thickness()
{
Left = location.X + (senderControl.ActualWidth / 2) - (popup.Width / 2),
Top = location.Y + senderControl.ActualHeight + 15
};
}
Sounds like you're choosing the hard way to do that.
If you need a popup, then use a Popup.
Otherwise, if for whatever reasons you don't want to use that, You'd better place a grid somewhere near the root of your XAML, and ALWAYS use that as a container:
<Window>
<Grid x:Name="MainUI"/>
<Grid x:Name="PopupContainer"/>
</Window>
Otherwise, you'll almost invariably encounter Z-Index problems (if you follow your current approach).
Also, it's a really bad idea to create all that UI stuff in code. Either encapsulate your Yes/No dialog in a UserControl or create a proper Template for that.
As I said before, avoid at all costs creating/manipulating UI elements in code, as it creates a lot of maintainability issues.

Categories