Is there a way to pass arguments on button click in Windows Phone 8.1?
I have a grid of 5x5 buttons, and they should all call the same method but with a different parameter. I am adding a handler like this:
foreach (var child in buttonGrid.Children)
{
Button b = child as Button;
if (b != null)
{
b.Click += Button_Click;
// I want to add an argument to this
}
}
Now the only way I can get the index of the button is by iterating over the whole grid and checking if the sender is equal to the button:
private void Button_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < buttonGrid.Children.Count; i++)
{
if (sender == buttonGrid.Children[i])
{
DoSomething(i);
return;
}
}
}
It works, but I don't really like this approach. Is there a more efficient way of doing this (other than creating a different method for each of the 25 buttons)?
I tried searching on the internet, but the documentation and examples for Windows Phone are really lacking. If anyone has a good repository of Windows Phone 8.1 tutorials to direct me to, that would also be of help.
You can use Tag property of the button.
For eg.
I'm trying to create a number pad which has 9 buttons with the respective number as the button content and i have set the same thing as the Tag property also.
<StackPanel>
<StackPanel Orientation="Horizontal" >
<Button Content="1" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="1" />
<Button Content="2" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="2" />
<Button Content="3" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="3" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="4" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="4" />
<Button Content="5" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="5" />
<Button Content="6" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="6" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="7" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="7" />
<Button Content="8" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="8" />
<Button Content="9" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48" FontWeight="Bold" Click="Button_Click" Tag="9" />
</StackPanel>
</StackPanel>
This produces the following output :
In your code behind you can now use the Tag property in the following manner
private void Button_Click(object sender, RoutedEventArgs e)
{
var tag = (sender as Button).Tag;
int t = Convert.ToInt16(tag);
switch (t)
{
case 1:
//Do Something
break;
case 2:
//Do Something
break;
case 3:
//Do Something
break;
case 4:
//Do Something
break;
case 5:
//Do Something
break;
case 6:
//Do Something
break;
case 7:
//Do Something
break;
case 8:
//Do Something
break;
case 9:
//Do Something
break;
default:
break;
}
}
Controls and other elements in XAML have a Tag property that you can set to an arbitrary object value for this kind of thing. Set it when you create the object and then inspect it in the event handler.
A simple solution would be to assign unique numbers to each button and then call the function with this uniquely assigned number as a parameter.
In the function, you could easily use the If-Else blocks to perform the task according to the Unique Number.
The code for 4 buttons becomes something like:-
void func(int unique_number)
{
if(unique_number==1)
{
//perform tasks for button 1
}
if(unique_number==2)
{
//perform tasks for button 2
}
if(unique_number==3)
{
//perform tasks for button 3
}
if(unique_number==4)
{
//perform tasks for button 4
}
}
private void Button_1_Click(object sender, RoutedEventArgs e)
{
func(1); //Call from button 1
}
private void Button_2_Click(object sender, RoutedEventArgs e)
{
func(2); //Call from button 2
}
private void Button_3_Click(object sender, RoutedEventArgs e)
{
func(3); //Call from button 3
}
private void Button_4_Click(object sender, RoutedEventArgs e)
{
func(4); //Call from button 4
}
I hope this makes it somewhat easy and efficient.
While the answers show you how to do this using Tag, this approach is non-convenient for, say 100 buttons.
To achieve your result, you can use closures for the job. Here's how:
// When you're attaching handlers
int i=0;
foreach (var child in buttonGrid.Children)
{
Button b = child as Button;
if (b != null)
{
b.Click += () => {
int z = i++; // You can put a different id generator here as well, like int z = <rand>%<prime> if you want
DoSomething(z); // DoSomething called with corrosponding button id
}
}
}
This approach does not require you to use tags!
Related
I have the below code but it is only happening once on first hold and not after.
Properly something is very simple but it can't seem to find a answer.
private void Contact_Tap_1_Holding(object sender, RightTappedRoutedEventArgs e)
{
contactSelected = 1;
this.Frame.Navigate(typeof(ContactAddPopUp));
}
<Button x:Name="Contact_1" HorizontalAlignment="Stretch" Margin="40,464,51,0"
RightTapped="Contact_Tap_1_Holding" VerticalAlignment="Top" Height="72"
Background="#ff4081" FontSize="11" FontWeight="Bold" Foreground="#FFFFFF"
Click="button_Click" Content="Contact 1" />
Thanks!
I need only to bind the Textboxes. I created a next and previous button this works but nothing is on the Textbox. What do I wrong? How do I get the items form the List?
The Read from the Database:
void read()
{
using (var nwe = new NORTHWNDEntities())
{
var objctx = (nwe as IObjectContextAdapter).ObjectContext;
ObjectQuery<Employee> query = new ObjectQuery<Employee>(
"SELECT VALUE n from NORTHWNDEntities.Employees as n", objctx);
List<Employee> results = query.ToList();
cursor = (CollectionView)CollectionViewSource.GetDefaultView(results);
}
}
private void countposition()
{
labelRead.Content = "Read " + (cursor.CurrentPosition + 1) + " to " + cursor.Count;
}
private void buttonNext_Click(object sender, RoutedEventArgs e)
{
if(cursor.CurrentPosition < cursor.Count -1)
{
cursor.MoveCurrentToNext();
countposition();
}
else
{
MessageBox.Show("No more data");
}
}
private void buttonPrevious_Click(object sender, RoutedEventArgs e)
{
if (cursor.CurrentPosition > 0)
{
cursor.MoveCurrentToPrevious();
countposition();
}
else
{
MessageBox.Show("No more data");
}
}
The UI Code to Bind the Data:
<TextBox x:Name="textBoxID" HorizontalAlignment="Left" Height="23" Margin="163,79,0,0" TextWrapping="Wrap" Text="{Binding Path=EmployeeID}" IsReadOnly="True" VerticalAlignment="Top" Width="87"/>
<Label x:Name="labelFirstNAme" Content="First Name" HorizontalAlignment="Left" Margin="52,157,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="textBoxFirstName" HorizontalAlignment="Left" Height="23" Margin="163,157,0,0" TextWrapping="Wrap" Text="{Binding Path=FirstName}" VerticalAlignment="Top" Width="145"/>
<Label x:Name="labelLastName" Content="Last Name" HorizontalAlignment="Left" Margin="52,224,0,0" VerticalAlignment="Top" Width="67"/>
<TextBox x:Name="textBoxLastName" HorizontalAlignment="Left" Height="23" Margin="163,224,0,0" TextWrapping="Wrap" Text="{Binding Path=LastName}" VerticalAlignment="Top" Width="145"/>
<Label x:Name="labelBirthDate" Content="Birth Date" HorizontalAlignment="Left" Margin="52,307,0,0" VerticalAlignment="Top" RenderTransformOrigin="-0.289,0.462" Width="67"/>
<TextBox x:Name="textBoxBirthDate" HorizontalAlignment="Left" Height="23" Margin="163,310,0,0" TextWrapping="Wrap" Text="{Binding Path=BirthDate}" VerticalAlignment="Top" Width="145"/>
Sorry I drank a few beers but TextBox accepts just one value, id est typically .Text="oneStringInstanceOnly".
You would like to bind List<> (that has multiple values / objects / strings / classes) to a TextBox that accepts generally one (usually string) value and that is the reason why you cannot bind a List that contains multiple values to a TexBox that accepts one value. TextBox is not a DataGridView or ListBox that accept multiple values / data tables. Evenutally you could assign the TexBox with the first value from the list myTextBox = (myList!=null && myList.Count!=0)?myList[0].ToString():"NoMoreValues";
I have 2 buttons and they do the same on different controls. How can i make this better? Because now i too much copy/paste. Here is image and code.
enter image description here
private void button_ClickOld(object sender, RoutedEventArgs e)
{
TextBoxOld.Text = SelectCatalog();
if (File.Exists(TextBoxOld + ConfigFilePath))
{
GetClientProperty(TextBoxOld.Text);
UpdateOldLabel();
}
else
{
LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
}
}
private void button_ClickNew(object sender, RoutedEventArgs e)
{
TextBoxNew.Text = SelectCatalog();
if (File.Exists(TextBoxNew + ConfigFilePath))
{
GetClientProperty(TextBoxNew.Text);
UpdateNewLabel();
}
else
{
LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
}
}
xaml
<Button x:Name="ButtonOld" Content="..." HorizontalAlignment="Left" Margin="149,35,0,0" VerticalAlignment="Top" Width="25" Click="button_ClickOld"/>
<TextBox x:Name="TextBoxOld" HorizontalAlignment="Left" Height="23" Margin="24,35,0,0" Text="" VerticalAlignment="Top" Width="120" IsReadOnly="True"/>
<Button x:Name="ButtonNew" Content="..." HorizontalAlignment="Left" Margin="447,35,0,0" VerticalAlignment="Top" Width="25" Click="button_ClickNew"/>
<TextBox x:Name="TextBoxNew" HorizontalAlignment="Left" Height="23" Margin="322,35,0,0" Text="" VerticalAlignment="Top" Width="120" IsReadOnly="True"/>` <Label x:Name="OldNameLabel" Content="Name" HorizontalAlignment="Left" Margin="24,70,0,0" VerticalAlignment="Top"/>
<Label x:Name="OldIpLabel" Content="IP" HorizontalAlignment="Left" Margin="24,100,0,0" VerticalAlignment="Top"/>
<Label x:Name="OldWebpageUriLabel" Content="WebpageUri" HorizontalAlignment="Left" Margin="24,130,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="OldConnectionStringTextBox" Text="ConnectionString" HorizontalAlignment="Left" Margin="24,160,0,0" Width="120"
VerticalAlignment="Top" Background="Linen" BorderThickness="0" IsReadOnly="True"/>
<Label x:Name="NewNameLabel" Content="Name" HorizontalAlignment="Left" Margin="322,70,0,0" VerticalAlignment="Top"/>
<Label x:Name="NewIpLabel" Content="IP" HorizontalAlignment="Left" Margin="322,100,0,0" VerticalAlignment="Top"/>
<Label x:Name="NewWebpageUriLabel" Content="WebpageUri" HorizontalAlignment="Left" Margin="322,130,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="NewConnectionStringTextBox" Text="ConnectionString" HorizontalAlignment="Left" Margin="322,160,0,0" Width="120"
VerticalAlignment="Top" Background="Linen" BorderThickness="0" IsReadOnly="True"/>
<Label x:Name="ArrowLabel" Content="<-" HorizontalAlignment="Left" Margin="221,14,0,0" VerticalAlignment="Top" FontSize="30" />
<Label x:Name="OldVersionTextBoxLabel" Content="Old Version:" HorizontalAlignment="Left" Margin="24,4,0,0" VerticalAlignment="Top"/>
<Label x:Name="NewVersionTextBoxLabel" Content="New Version:" HorizontalAlignment="Left" Margin="325,4,0,0" VerticalAlignment="Top"/>`
By the looks of your it, you don't understand MVVM and SOLID principles. If you truly want to take advantage of WPF, you must first learn MVVM, and to truly take advantage of MVVM, you need to understand SOLID. To reduce the burden of verbose XAML and boiler plate code, you should take advantage of MVVM frameworks, Caliburn.Micro is super easy to use but require you to have a good architecture to be able to fully utilize it.
Further, using MVVM will make your XAML code so much simpler. Old Version and New Version section will just have one UserControl and may look like
<views:VersionView DataContext={Binding OldVersionViewModel}/>
<views:VersionView DataContext={Binding NewVersionViewModel}/>
You will save yourself a lot of pain and make you delighted you chose WPF for your UI once you learn the power of MVVM.
But if this is just a small project and you insist on using code behind, you can do
private void button_ClickOld(object sender, RoutedEventArgs e)
{
SelectVerifyAndLog(TextBoxOld, UpdateOldLabel);
}
private void button_ClickNew(object sender, RoutedEventArgs e)
{
SelectVerifyAndLog(TextBoxNew, UpdateNewLabel);
}
void SelectVerifyAndLog(TextBox textBox, Action updateLabel)
{
textBox.Text = SelectCatalog();
if (File.Exists(textBox + ConfigFilePath))
{
GetClientProperty(textBox.Text);
updateLabel();
}
else
{
LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
}
}
1) You can reuse your code
private void button_ClickOld(object sender, RoutedEventArgs e)
{
ButtonHelper(TextBoxOld);
}
private void button_ClickNew(object sender, RoutedEventArgs e)
{
ButtonHelper(TextBoxNew);
}
void ButtonsHelper(TextBox textBox) {
TextBoxNew.Text = SelectCatalog();
if (File.Exists(textBox + ConfigFilePath))
{
GetClientProperty(textBox.Text);
UpdateNewLabel();
}
else
{
LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
}
}
2) In WPF, use MVVM, otherwise you just don't have advantages of WPF
3) If you have many groups of controls like you marked on your picture and they have much of code, make them controls. And each of them will contain it's own xaml, it's own code, and you can reuse it. It's not necessary to put all the xaml in one file.
I don't know how to get text from "firstBox" and "secondBox" after button click.
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<!-- some code -->
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Data}" VerticalAlignment="Top" Height="18" Width="100" FontSize="13.333" Margin="162,9,0,0"/>
<TextBlock HorizontalAlignment="Left" Margin="0,35,0,0" TextWrapping="Wrap" Text="{Binding D_gospodarzy}" FontSize="14.667" VerticalAlignment="Top" Height="59" Width="100"/>
<TextBlock HorizontalAlignment="Center" Margin="268,35,7,0" TextWrapping="Wrap" Text="{Binding D_gosci}" FontSize="14.667" VerticalAlignment="Top" Width="100" Height="59"/>
<TextBox x:Name="firstBox" ... />
<Button Content="Click" " Click="Button_Click_1"/>
<TextBox x:Name="secondBox" ... />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
I get only the object
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var myobject = (sender as Button).DataContext;
}
There are cuple of ways to do it, for example you can traverse the VisualTree of clicked button's parent and retrive TextBox with the name you want. In this case, I would take advantage of an extension method written by yasen in this answer.
Then it can look for example like this:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var parent = (sender as Button).Parent;
TextBox firstOne = parent.GetChildrenOfType<TextBox>().First(x => x.Name == "firstBox");
Debug.WriteLine(firstOne.Text);
}
Remember to put an extension method somewhere in a static class:
public static class Extensions
{
public static IEnumerable<T> GetChildrenOfType<T>(this DependencyObject start) where T : class
{
// rest of the code
Here's how to get the text..
String text1 = firstBox.Text;
String text2 = secondBox.Text;
note: firstBox and secondBox must be class members to use them in different class methods.
<Grid x:Name="LayoutRoot">
<Button x:Name="btn_num" Width="51" Margin="318.849,158,262.15,0" Height="45" VerticalAlignment="Top" d:LayoutOverrides="HorizontalMargin">
<Grid Height="38.166" Width="44.833">
<Label x:Name="lbl_2" Content="2" Margin="4.483,-2.042,7,-1.626" FontSize="11.333"/>
<Label x:Name="lbl_1" Content="1" Margin="4.483,0,7,-19.251" FontSize="11.333" Height="41.834" VerticalAlignment="Bottom"/>
<Label x:Name="lbl_3" Content="3" Margin="0,8.083,-15,-11.751" FontSize="11.333" HorizontalAlignment="Right" Width="33.35" Foreground="Black"/>
</Grid>
</Button>
<Button x:Name="btn_a" Content="A" HorizontalAlignment="Left" Margin="225.333,158,0,0" Width="55" Foreground="Black" Height="45" VerticalAlignment="Top" Click="btn_alt_Click" />
</Grid>
It's design will be like this
public partial class button : Window
{
static int _AClick = 0;
public button()
{
this.InitializeComponent();
}
private void btn_alt_Click(object sender, RoutedEventArgs e)
{
if (_AClick == 0)
{
_AClick = 1;
Fill();
}
else
{
btn_num.Content = "";
_AClick = 0;
}
}
public void Fill()
{
btn_num.Content = "3";
}
}
The result after window loaded
If i click A button first time. The result will be like this
If I click A button second time. The result will be like this
when I click A button second time. I need the result like below. what should I do for that.
There are a lot of ways available in WPF to achieve this. One way to do this is to have two ControlTemplates (one having all three numbers and other having just one number) and then set the template of your button in code -
<Grid x:Name="LayoutRoot">
<Grid.Resources>
<ControlTemplate
x:Key="threeNumberTemplate"
TargetType="{x:Type Button}">
<Grid Height="38.166" Width="44.833">
<Label x:Name="lbl_2" Content="2" Margin="4.483,-2.042,7,-1.626" FontSize="11.333"/>
<Label x:Name="lbl_1" Content="1" Margin="4.483,0,7,-19.251" FontSize="11.333" Height="41.834" VerticalAlignment="Bottom"/>
<Label x:Name="lbl_3" Content="3" Margin="0,8.083,-15,-11.751" FontSize="11.333" HorizontalAlignment="Right" Width="33.35" Foreground="Black"/>
</Grid>
</ControlTemplate>
<ControlTemplate
x:Key="oneNumberTemplate"
TargetType="{x:Type Button}">
<Label x:Name="lbl_3" Content="3" FontSize="11.333"/>
</ControlTemplate>
</Grid.Resources>
<Button x:Name="btn_num" Width="51" Margin="318.849,158,262.15,0" Height="45" VerticalAlignment="Top" Template="{StaticResource threeNumberTemplate}"></Button>
<Button x:Name="btn_a" Content="A" HorizontalAlignment="Left" Margin="225.333,158,0,0" Width="55" Foreground="Black" Height="45" VerticalAlignment="Top" Click="btn_alt_Click" />
</Grid>
Code behind -
private void btn_alt_Click(object sender, RoutedEventArgs e)
{
if (_AClick == 0)
{
_AClick = 1;
btn_num.Template = FindResource("oneNumberTemplate") as ControlTemplate;
}
else
{
btn_num.Template = FindResource("threeNumberTemplate") as ControlTemplate;
_AClick = 0;
}
}
Same can be achieved through triggers by making _AClick as DependecyProperty and using it's value to swap templates in triggers.
Another approach is to have two Buttons and hide/show them based on the _AClick value in code.
You can create three DataTemplate and use DataTemplateSelector class to load the corresponding data template on run time.
MSDN - DataTemplateSelector