Issue with making an hangman game in UWP - c#

I'm trying to create an hangman game in UWP and I'm not quite sure where to type the button click event of each letter in the code in order to have it recognize all of the variables in MainPage without affecting functionality.
If possible to have the button clicks in a separate class, even better.
Would appreciate if you could help me, thanks in advance!
namespace Hangman
{
public sealed partial class MainPage : Page
{
int _currentIndex;
string _currentWord;
string[] _strArr = { "ant", "bee", "spider", "mosquito" };
int _difficulty = 1;
public MainPage()
{
this.InitializeComponent();
Random rnd = new Random();
_currentIndex = rnd.Next(0, 4);
_currentWord = _strArr[_currentIndex];
foreach (char c in _currentWord)
{
string _hiddenWord = string.Empty;
foreach (char ch in _currentWord)
{
_hiddenWord += "_" + (char)160;
}
_textBl.Text = _hiddenWord;
}
}
private void a_Click(object sender, RoutedEventArgs e)
{
}
}
}

I want to capture Button clicks of buttons on my XML code. I've made a property like so public char Key { get; set; } and had each Button click insert a different value dependant on the letter, for example: on button_a, Key = 'a';
I probably understand what you mean. You have a lot of buttons (like a button that makes up a keyboard). Each time you click the button, you get the button's identity and then type it into the text box.
You can use the Button.Tag property to record your key, like this:
<Button Tag="a" Content="A" Click="Button_Click" />
In code-behind, the Button_Click method has two parameters, where the sender refers to the Button that triggered the event, so you can convert it and get the Tag property.
private void Button_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
string tag = btn.Tag.ToString();
// Do Something
}
In this way, you can bind all the buttons to the same handler, which is very convenient.
Best regards.

You have to go to your XAML file where you design your UI, find the button and then add
<Button Content="Your Button Text" onClick="a_Click" />
there.

Related

Binding buttons in StackLayout displays additional things

I am trying find way to write and get items from my StackLayout in my ViewModel.
My implementation XAML:
<StackLayout x:Name="PlayerList" BindableLayout.ItemsSource="{Binding Players}"/>
And implementation for ViewModel:
public ObservableCollection<Button> Players { get; set; } = new ObservableCollection<Button>();
public GamePointViewModel()
{
InitializePlayerList();
}
public void InitializePlayerList()
{
for (int i = 0; i < GameSettings.PlayerCount; i++)
{
Button newBtn = new Button();
newBtn.Text = GameSettings.Players[i];
newBtn.ClassId = i.ToString();
newBtn.Clicked += ButtonEvent_Click;
Players.Add(newBtn);
}
}
void ButtonEvent_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
if (button.Background == Brush.Green)
{
button.Background = Brush.Gray;
}
else
{
button.Background = Brush.Green;
}
}
Unfortunately, I see some additional text in my interface:
But I expected only buttons. What I miss?
May I suggest, alternative approach.
Instead of binding visual elements (In your case buttons), you should be binding Models to your VisualElements (for example, ObservableCollection of Players to your CollectionView ItemSource).
And instead of adding event handlers to those VisualElements, you should be using Commands. (For example bound to TapGestureRecognizers of this CollectionView).
For changing the appearance of those buttons, you can use Data Triggers, Visual States, Styles, Control Templates, Value Convertors, or combination of them.
(For example Player.isActive becomes false, the color of the VisualElement becomes gray)
There is no point in using MVVM, just to bind UI to UI.

How can I clear textboxes so submit button can be re-used?

I am making a program for school in C#, and its purpose is to allow the user to enter film data, which it then puts into an object for that film. It will also include other functionality such as the user being able to search for a film (it says I have to make 3 film objects and store them in an array all being input by the user).
I have created the first part of the Windows Forms application and it is a screen that gets all the input from the user like the name, director, rating, etc... and there is a submit button which creates the object. Is there a way, without creating a new form, to use the same screen and clear the textboxes so that when the submit button is clicked again it creates a NEW OBJECT like 'film2'?
Here is my code for the submit button:
private void button1_Click(object sender, EventArgs e)
{
int year = Convert.ToInt32(dBox_year.Text);
Film film1 = new Film(tbox_name.Text, tbox_director.Text, tbox_actor1.Text, tbox_actor2.Text, year, tbox_rating.Text);
filmArray[0] = film1;
}
So, you see how I would like to have the textboxes on the main screen clear themselves, and reuse the same screen but only it would be 'Film film2 = ...' etc.
This is not an assesed piece and we haven't covered this in class yet so I have tried.
private void button1_Click(object sender, EventArgs e)
{
int year = Convert.ToInt32(dBox_year.Text);
Film film1 = new Film(tbox_name.Text, tbox_director.Text, tbox_actor1.Text, tbox_actor2.Text, year, tbox_rating.Text);
filmArray[0] = film1;
//clearing after adding to array
//or you can just use .Clear() method
tbox_name.Text = String.Empty;
tbox_director.Text = String.Empty;
tbox_actor1.Text = String.Empty;
tbox_actor2.Text = String.Empty;
tbox_rating.Text = String.Empty;
}
tbox_name.Clear() - Clears all text from the text box control.(Inherited from TextBoxBase.)
You could use a List instead of an Array, declared at form level:
private List<Film> filmList = new List<Film>();
Then your button click even would look like
private void button1_Click(object sender, EventArgs e)
{
int year = Convert.ToInt32(dBox_year.Text);
filmList.Add(new Film(tbox_name.Text, tbox_director.Text, tbox_actor1.Text, tbox_actor2.Text, year, tbox_rating.Text));
tbox_name.Text = string.Empty;
tbox_director.Text = string.Empty;
tbox_actor1.Text = string.Empty;
tbox_actor2.Text = string.Empty;
tbox_rating.Text = string.Empty;
dBox_year.Text = string.Empty;
}
Here you're creating a new Film object and adding it straight away to the list of films, and then clearing the text boxes afterwards.
If there's a specific reason you need an array, then you can always later do
filmList.ToArray()
Hope this helps!
When Submit button is clicked you want to add the object at the end of the array, not put it at the first position.So you will need an extra variable named, let say, filmCount, which you initialize with 0 and increment on each submit.
Film film1 = new Film(tbox_name.Text, tbox_director.Text, tbox_actor1.Text, tbox_actor2.Text, year, tbox_rating.Text);
filmArray[filmCount++] = film1;
then you clear the texboxes
foreach(TextBox TB in this.Controls)
{
TB.Text = "";
}

Referencing a dynamically created control in a new TabPage

newbie programmer here after hours of searching has left me stumped.
I'm having trouble with referencing a control inside a tab created at RunTime with a button press. Basically what I have is a tabletop RPG calculator, using a Windows Form, that has a tabControl holding tab pages, with each tab page holding user-inputted stats for that individual enemy to be used in calculations.
The problem is that I want the user to be able to click a button to generate a new enemy tab page. Here is my code for generating an enemy tab page with a TextBox.
int enemyNumber = 0;
// Creates a new Enemy Tab
private void button2_Click_1(object sender, EventArgs e)
{
// Create a new TabPage
var newTabPage = new TabPage()
{
Text = "Enemy " + enemyNumber,
};
// Add Enemy Name Box
var newEnemyNameBox = new TextBox()
{
Name = "enemyNameBox" + enemyNumber,
Text = "",
Location = new Point(127, 11),
Size = new Size(133, 20)
};
// Add the controls to the new Enemy tab
newTabPage.Controls.Add(newEnemyNameBox);
// Add the TabPage to the TabControl
tabControl1.TabPages.Add(newTabPage);
// Increases the enemy's "reference number" by 1
// So that enemy tabs will be generated in order enemyTab0, enemyTab1, etc.
enemyNumber += 1;
}
This all works nicely. Unfortunately, after this point things have gotten ugly. I need to reference that TextBox named "enemyNameBox" + enemyNumber, and I'm not sure how to do so.
What I did was create "archVariables" to store the values from whatever enemy tab is selected, then use the appropriate archVariable in the program's calculations. IE: archEnemyName. The idea is that whatever tab the user is currently selected on (determined via SelectedIndex) the TextBox from that page will be used for the program's output.
Here are the two things I've tried after researching the matter:
// Attempt 1
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
archEnemyNameBox = ((TextBox)Controls["enemyNameBox" + i]).Text;
}
}
This code simply throws a NullReferenceException when I press the button. So after researching more I tried this:
// Attempt 2
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
TextBox tb2 = new TextBox();
tb2 = ((TextBox)(enemyTab.Controls.Find("enemyNameBox" + i, true)));
archEnemyNameBox = tb2.Text;
}
}
This time I got an Error: Cannot convert type 'System.Windows.Forms.Control[]' to 'System.Windows.Forms.TextBox'
I feel like the second method I have here is probably closer to the correct way to do this, but apparently I'm still not getting it right. I've learned a lot by searching the information on stackoverflow and msdn.microsoft but nothing has gotten me past this problem.
Any help would be appreciated.
basically the problem with your second attemp is that enemyTab.Controls.Find("enemyNameBox" + i, true) returns an array of Controls Control[] and you're trying to convert that to a Control here is the problem, you should get the first control in that array and then convert it to a Control so it should be like this:
private void defendCalcButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < tabControl1.SelectedIndex; i++)
{
TextBox tb2 = new TextBox();
tb2 = ((TextBox)(enemyTab.Controls.Find("enemyNameBox" + i, true)[0]));
archEnemyNameBox = tb2.Text;
}
}
but it is not the BestWay to do so it seems that everytime a user adds a new tabPage it will have the same Controls right? so why not create an userControl with any Control you have on your TabPage? so when you press the user press to add a new tab your code should be like so:
private void CreateNewEnemyTab()
{
var newTabPage = new TabPage()
{
Text = "Enemy " + enemyNumber,
};
EnemyTabUserControl enemyTab = new EnemyTabUserControl(enemyNumber);
here the EnemyTabUserControl should have all the components you need;
newTabPage.Controls.Add(enemyTab);
tabControl1.TabPages.Add(newTabPage);
}
and the code to bring the TextBox from the current tab could be as follow (you are going to need to reference LINQ)
using System.Linq;
//First Lets create this property, it should return the selected EnemyTabUserControl inside the tabControl
public EnemyTabUserControl CurrentTab {
get {
return tabControl1.SelectedTab.Controls.OfType<EnemyTabUserControl>().First();
}
}
// then if we make the textbox you want to reference from outside the code we can do this
CurrentTab.NameOfTheTextBox;
Patrick has solved your fundamental problem, but I don't think you need the loop in there at all. Here I've broken the steps out so you can see what needs to happen a little better:
private void defendCalcButton_Click(object sender, EventArgs e)
{
Control[] matches = this.Controls.Find("enemyNameBox" + tabControl1.SelectedIndex.ToString(), true);
if (matches.Length > 0 && matches[0] is TextBox)
{
TextBox tb = (TextBox)matches[0];
archEnemyNameBox = tb.Text;
}
}

One property for multiple buttons

Is there a way to write in c# one property for multiple items. e.g. i have 5 buttons, i don't want to write button1.text = "etc", button2.text = "etc, I want to write button.text="etc" and have button1.text through button5.text to have "etc" text.
I guess this is feasible with something similar to:
public void SetButtonText(string value) {
this.Controls.OfType<Button>().ToList().ForEach(b => b.Text = value);
}
Or the same through a property:
public string ButtonText {
set {
Controls
.OfType<Button>()
.ToList()
.ForEach(b => b.Text = value);
}
}
EDIT
After a further research, I found out that there are no direct way to access the controls of a page in Windows Phone as I know. So it all depends on whether you wish to get down from the PhoneApplicationPage:
As I see it, your solution revolves around the Page.LogicalChildren Property.
public class MyPage : Page {
public string ButtonText {
set {
LogicalChildren
.OfType<Button>()
.ToList()
.ForEach(b => b.Text = value);
}
}
}
Since the LogicalChildren has a protected accessor, you need to access it through a derived class, which shall be convenient for any kind of page you're working on Windows Phone, I guess.
Or drop a Grid right onto the PhoneApplicationPage and then drop other controls over it such as your buttons, then you shall access them through the Grid.Children property.
So, having dropped your Grid and naming it myBaseGrid, one would do the following:
public void SetButtonsText(string text) {
myBaseGrid.Children
.OfType<Button>()
.ToList()
.ForEach(b => b.Text = "myText");
}
I would personally go with the method which name makes it clear what you're doing by spelling the word Button in plural as in my sample.
Perhaps you are looking for control arrays: http://msdn.microsoft.com/en-us/library/aa289500(v=vs.71).aspx?
You can't assign all 5 buttons to the same reference, so that button.text = "etc" will work.
You can however, bind the buttons to the same property:
<Button Content="{Binding myText}"/>
<Button Content="{Binding myText}"/>
<Button Content="{Binding myText}"/>
<Button Content="{Binding myText}"/>
If the binding is set properly with INotifyPropertyChanged, then all will update when myText is updated.
You could also put the controls into a collection and foreach over them to set their Content property as others have suggested.
One way would be to create a method that sets them all for you, which you would have to manually write once:
public void SetAllButtonTexts(string text)
{
button1.text = text;
button2.text = text;
// . . .
}
Alternatively you could use a loop:
public void SetAllButtonTexts(string btnText)
{
foreach (var control in this.Controls.OfType<Button>())
{
(control).Text = btnText;
}
}
And if you don't want to update ALL the buttons, one easy but not-so-elegant thing you could do is modify the Tag property of the buttons you want to change with some custom text, and only update those:
public void SetAllButtonTexts(string btnText, string tagText = "")
{
foreach (var control in this.Controls.OfType<Button>()
.Where(b => string.IsNullOrEmpty(tagText)
|| (b.Tag != null && b.Tag.Equals(tagText))))
{
(control).Text = btnText;
}
}
In a few words: Group up all your buttons which should get changed in a list. Then later loop through this list and set your text of all buttons.
Here's some code.
First of all:
public static List<Button> buttonList = new List<Button>{};
On form_load:
buttonList.AddRange(new List<Button>{ button1,button2,button3,...}); // Group your buttons
Now it depends on 'when' or 'where' you want to change it. If the buttons should be changed right in the beginning, put the following code into the form_load-event. Else when it should be fired on an event, place it into an event.
foreach(Button btn in buttonList)
{
btn.Text = "Change all button-texts from list at one time.";
}
You can also handle multiple lables or boxes etc. like this. Just declare the right datatype.
Greetings

Custom dialog box control in c#

I have a question I hope some of you might be able to answer, I haven't found any ways to do this on google or here.
What I want:
- A custom control that functions just like an input box. (But it has to be a winform control that can be added to a form. Not a form.)
- It has to be able to grab the value from its text box and send it to the parent in the function it was called in.
Here is how I want to call it:
string str = MyBox.GetString("control title");
Can anyone help?
I don't know if this is event possible in c#. I couldn't figure it out, but if anyone can please answer!
You want something like this
public partial class MyBox : Form
{
public MyBox()
{
InitializeComponent();
}
public string ResultText { get; set; }
public static string GetString(string title)
{
var box = new MyBox {Text = title};
if (box.ShowDialog() == DialogResult.OK)
{
return box.ResultText;
}
return string.Empty;
}
private void okButton_Click(object sender, EventArgs e)
{
this.ResultText = txtUserInput.Text;
this.DialogResult = DialogResult.OK;
}
}
where MyBox would be a Form with TextBox - txtUserInput and an okay button linked to the okButton_Click event.
And you can make calls from other forms like this:
string userInput = MyBox.GetString("Title for MyBox");
If you want the box to reside on a form, you can just use a regular TextBox to get the inupt. Maybe eclose it in a GroupBox to give a "title", add a description label.
Lastly, and most importantly, add an "Update" Button to the GroupBox. Inside this button's Click handler, you can retrieve the value of the textbox with string str = textbox.Text.

Categories