How to get text from TextBox inside ListViewItem's DataTemplate - c#

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.

Related

How to get string value from Listbox as user selected?

I can't get string value from Listbox after selected one item.
In my Listbox I have the Image (blinding source) and TextBlock (blinding source).
My code at .xaml page:
<ListBox Name="carListBox" Height="431" Canvas.Left="28" Canvas.Top="65" Width="446" SelectionChanged="ListBoxOnSelection">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Name="brandImage" Source="{Binding Image}" Width="100" Height="150"></Image>
<Image Name="carImage" Source="{Binding Image}" Width="150" Height="150"></Image>
<TextBlock Name="textDisplay" Text="{Binding ShowDetail}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My code at .xaml.cs page (C#)
private void ListBoxOnSelection(object sender, SelectionChangedEventArgs args)
{
MessageBox.Show(carListBox.SelectedItem.ToString());
string saveData = carListBox.SelectedItem.ToString();
}
MessageBox can't show string value and I can't get value after user selected.
MessageBox show [1]https://i.imgur.com/2VSjhgN.jpg
You have to somehow get the Car object before you can have access to it's properties.
Something like this:
private void ListBoxOnSelection(object sender, SelectionChangedEventArgs args)
{
Car myCar=carListBox.SelectedItem as Car;
if(myCar != null)
MessageBox.Show(myCar.ShowDetail); //or any property.
}

delayed trigger for calculation with data binding

I'm very new to WPF and currently learning the concepts of data binding.
my simplified XAML code. besides my problem (below) it works fine - quick and dirty placing of objects via GUI, will be cleaned up once works:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
</Grid>
<Grid Grid.Row="1">
<GroupBox Header="Change Type:" Height="95" Width="100" VerticalAlignment="Top" Margin="270,4,422,0" >
<StackPanel>
<RadioButton x:Name="RbtAdd" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
<WrapPanel>
<TextBlock Text="Add" Foreground="Green"/>
</WrapPanel>
</RadioButton>
<RadioButton x:Name="RbtPull" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
<WrapPanel>
<TextBlock Text="Pull" Foreground="Blue"/>
</WrapPanel>
</RadioButton>
<RadioButton x:Name="RbtModify" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
<WrapPanel>
<TextBlock Text="Modify" Foreground="DarkGray"/>
</WrapPanel>
</RadioButton>
</StackPanel>
</GroupBox>
<TextBlock x:Name="txtCurStock" HorizontalAlignment="Left" Margin="330,181,0,0" TextWrapping="Wrap" Text="{Binding Path=CurrentStock}" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" TextAlignment="Center"/>
<Label Content="Current stock:" HorizontalAlignment="Left" Margin="289,156,0,0" VerticalAlignment="Top"/>
<Label x:Name ="lblOperation" Content="Stock to Pull:" HorizontalAlignment="Left" Margin="507,156,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="txtEntry" HorizontalAlignment="Left" Height="32" Margin="489,181,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="120" FontSize="20" FontWeight="Bold" TextChanged="TxtEntry_TextChanged"/>
<Label Content="New Stock" HorizontalAlignment="Right" Margin="714,156,0,0" VerticalAlignment="Top" Width="68"/>
<TextBlock Text="{Binding Path=NewStock}" HorizontalAlignment="Right" Margin="0,186,10,0" TextAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" Width="68"/>
<TextBox x:Name="txtComment" HorizontalAlignment="Left" Height="86" Margin="289,233,0,0" TextWrapping="Wrap" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="493"/>
<Label Content="Comment:" HorizontalAlignment="Left" Margin="289,207,0,0" VerticalAlignment="Top"/>
<TextBlock x:Name ="txtModindicator" HorizontalAlignment="Left" Margin="433,181,0,0" TextWrapping="Wrap" Text="-" FontSize="20" FontWeight="Bold" VerticalAlignment="Top"/>
<TextBlock x:Name ="txtResindicator" HorizontalAlignment="Left" Margin="663,182,0,0" TextWrapping="Wrap" Text="=" FontSize="20" FontWeight="Bold" VerticalAlignment="Top"/>
</Grid>
</Grid>
now the shortened c# code:
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace SomeWPF
{
/// <summary>
/// Interaction logic for ModifyWindow.xaml
/// </summary>
public partial class MainWindow : INotifyPropertyChanged
{
public enum Mymode
{
add,
pull,
modify
}
public Mymode mode;
public MainWindow()
{
DataContext = this;
InitializeComponent();
CurrentStock = 5;
RbtPull.IsChecked = true;
ModEntry = 1;
}
private void ModeRadio_Checked(object sender, RoutedEventArgs e)
{
if (sender != null)
{
if (sender.Equals(RbtAdd))
{
mode = Mymode.add;
txtModindicator.Text = "+";
txtComment.Text = "Add";
lblOperation.Content = "Stock to Add:";
}
else if (sender.Equals(RbtPull))
{
mode = Mymode.pull;
txtModindicator.Text = "-";
txtComment.Text = "Pull";
lblOperation.Content = "Stock to Pull:";
}
else
{
mode = Mymode.modify;
txtModindicator.Text = "~";
lblOperation.Content = "Corrected Quantity:";
txtComment.Text = "Mod";
}
TxtEntry_TextChanged(sender, null);
}
}
private void TxtEntry_TextChanged(object sender, TextChangedEventArgs e)
{
if (mode == Mymode.add)
{
NewStock = CurrentStock + ModEntry;
}
else if (mode == Mymode.pull)
{
NewStock = CurrentStock - ModEntry;
}
else
{
NewStock = ModEntry;
}
}
#region Binding Stuff
private int _newstock;
public int NewStock
{
get
{
return _newstock;
}
set
{
if (_newstock != value)
{
_newstock = value;
OnPropertyChanged();
}
}
}
private int _modentry;
public int ModEntry
{
get
{
return _modentry;
}
set
{
if (_modentry != value)
{
_modentry = value;
OnPropertyChanged();
}
}
}
private int _currentstock;
public int CurrentStock
{
get
{
return _currentstock;
}
set
{
if (_currentstock != value)
{
_currentstock = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
So this window is a popup in a little program for an inventory storage for the users to enter movements of the inventory.
everything loads fine so far and I now wanted to do the quite simple calculation part. with "old" winforms c# you'd just take the values and update the text property of the result "manually" but of course we (I) want to learn new stuff and do stuff with data binding.
The code also does the calculation, but the trigger is somehow not what I want.
let's say current stock is 5
when window loads, the mode is set to Pull (RbtPull) and the user entry (Binding to ModEntry) is set to 1 via code. The NewStock therefore should be 4 which displays correctly. (yey)
Also the comment field (for debugging for now) displays the ModEntry value 1.
so far so good.
Now I enter 3 in the Stock to Pull field, but nothing happens. (I want it to react "realtime"). The new Stock is still displayed as 4, the comment is still displayed as 1.
When I leave the field (and click into the comment field) - the property change is detected and the Comment Field shows also 3 (=ModEntry) - so it's not "realtime" but only triggers when the field is losing focus, but that would be also acceptable.
The real problem is: The new Stock stays 4 and does not calculate.
Now when I enter the Stock to Pull field again and change the value to let's say 5, the New Stock field updates to 2 (so to the value I entered before 5-3=2)
Overwriting the field with again 5 will change the new Stock to 0.
So it's always "one step behind".
From what I have found i have an idea, that I need some kind of Binding Converter instead of my method of calculating things, but I can't really find anything suitable and am not familiar enough yet with data binding. Have tried out some things already directly in the binding variable code but none worked. If anyone could hint me in the right direction I'd be very thankful. (don't need a silver plate solution but just an idea what way to search (e.g. if the sort of binding I use makes sense at all or if there's something I have to add etc.).
Thanks a lot!
PS: of course if someone is motivated to give a silver plate solution I'd also be grateful. :) - and sorry for the bad english, no native speaker.
#nosale 's second link (see comments) provided the answer to the Problem.
Setting both XAML fields txtEntry and the Result field to UpdateSourceTrigger=PropertyChanged solved the issue.
so the correct block Looks like this now without changes to the c# code:
<Label Content="Current stock:" HorizontalAlignment="Left" Margin="289,156,0,0" VerticalAlignment="Top"/>
<Label x:Name ="lblOperation" Content="Stock to Pull:" HorizontalAlignment="Left" Margin="507,156,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="txtEntry" HorizontalAlignment="Left" Height="32" Margin="489,181,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="{Binding Path=ModEntry, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120" FontSize="20" FontWeight="Bold" TextChanged="TxtEntry_TextChanged"/>
<Label Content="New Stock" HorizontalAlignment="Right" Margin="714,156,0,0" VerticalAlignment="Top" Width="68"/>
<TextBlock Text="{Binding Path=NewStock, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Right" Margin="0,186,10,0" TextAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" Width="68"/>
<TextBox x:Name="txtComment" HorizontalAlignment="Left" Height="86" Margin="289,233,0,0" TextWrapping="Wrap" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="493"/>
<Label Content="Comment:" HorizontalAlignment="Left" Margin="289,207,0,0" VerticalAlignment="Top"/>
Reason is, that textboxes have a Default UpdateSourceTrigger=LostFocus and not PropertyChanged to prevent updates with user having entered typos.
something new learned: WPF is cool and automatically handles non plausible values like null or strings and marks the field red! :)
thanks again for the links!

Binding Click action to custom xaml component

I have the following custom control in XAML:
<Button x:Name="button" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Center" Width="200">
<StackPanel Orientation="Horizontal" Width="170">
<TextBlock Text="" FontFamily="Segoe UI Symbol" Visibility="{Binding isFolder, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Text="" FontFamily="Segoe UI Symbol" Foreground="Gold" Visibility="{Binding isFolder, Converter={StaticResource InverseBooleanToVisibilityConverter}}"/>
<TextBlock Text="{Binding title}" Margin="5,0" Foreground="Black"/>
</StackPanel>
I want to bind click action on isFolder. So I created a xaml page and in code behind I added the control as follow:
MyControl item = new MyControl();
item.DataContext = context;
// item.click += context.isFolder ? folderAction : nonFolderAction
There is no item.click. How can I add delegate to click based on boolean value?
You can use relaycommands where you can specify the condition when the command should be executed.
For example: (in your case)
In your viewmodel: (do this)
private RelayCommand myCommandInViewModel;
public RelayCommand MyCommandInViewModel
{
get { return myCommandInViewModel?? (myCommandInViewModel= new RelayCommand(myCommandInViewModelAction,()=> { return isFolder; })); }
}
where myCommandInViewModelAction has your method definition.
Above is the advised way of doing.
Else you can have another way where in the button.Click event you can get the datacontext of the sender and check for isFolder property in it.
private void someClickEvent(object sender, RoutedEventArgs e)
{
var buttonDataContext = (sender as Button).DataContext;
if(buttonDataContext.isFolder)
{
doSomeThing();
}
else
{
return;
}
}

LongListSelector set image visibility on selection change

I have a LongListSelector with some textblocksand images inside.
How can I set the Image's visibility programmatically?
I have them set to collapsed and I want to enable them on selection_changed event of the LongListSelector.
XAML:
<phone:LongListSelector Name="LongListSel" Margin="0,-38,-22,2" ItemsSource="{Binding Items}" SelectionChanged="LongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="12,2,0,4" Height="110" Width="432">
<StackPanel Width="311" Margin="0,0,0,0">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Margin="10,0" Style="{StaticResource PhoneTextExtraLargeStyle}" FontSize="{StaticResource PhoneFontSizeLarge}" />
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="10,-2,10,0" Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
<StackPanel Name="playImage" Height="50" Width="50" Margin="0,0,10,0">
<Image Source="Assets/Tiles/Iconsmind-Outline-Play-Music.ico" Visibility="{Binding ImageVis}" Width="50" Height="50" HorizontalAlignment="Left" Tap="Image_Tap_1"/>
</StackPanel>
<StackPanel Name="downloadImage" Height="50" Width="50" Margin="0,0,0,0">
<Image Source="Assets/Tiles/Download.ico" Visibility="{Binding ImageVis}" Width="50" Height="50" HorizontalAlignment="Left" Tap="Image_Tap_1"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</phone:PanoramaItem>
selection changed event:
private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ItemViewModel item = new ItemViewModel();
item.ImageVis = Visibility.Visible;
//it can't be called the way you are doing it of course and it still doesn't work
}
ViewModel
private Visibility _imageVis;
public Visibility ImageVis
{
get { return _imageVis; }
set
{
_imageVis = value;
NotifyPropertyChanged("ImageVis");
}
}
Create a property of type Visibility an bind it to your image visibility.
ViewModel:
private Visibility _DownloadImage;
public Visibility DownloadImage
{
get { return _DownloadImage; }
set
{
if (_DownloadImage != value)
{
_DownloadImage = DownloadImage;
OnPropertyChanged("DownloadImage");
}
}
}
xaml
<Image Source="Assets/Tiles/Download.ico" Visibility="{Binding DownloadImage}" ... />
xaml.cs (I would prefer to bind the command also to the ViewModel, to keep the MVVM pattern)
private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DownloadImage = Visibility.Visible;
}

Accessing items in DataTemplate using Visual Tree Helper in ListBox

I have the following DataTemplate:
<DataTemplate x:Key="ToDoListBoxItemTemplate">
<Grid x:Name="item2Expanded" HorizontalAlignment="Left" VerticalAlignment="Top" Width="480" Background="{Binding Converter={StaticResource RowColour}}" MinHeight="81">
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Width="420" Margin="60,0,0,0">
<TextBox x:Name="taskTitle" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding ItemName}" VerticalAlignment="Top" Width="420" Background="{x:Null}" BorderBrush="{x:Null}" CaretBrush="#FF0080FF" SelectionBackground="#FFCFCFCF" Foreground="#FF4E4E4E" BorderThickness="3,3,3,6" FontSize="29.333" Style="{StaticResource listTextBoxTemplate}" InputScope="Text" SelectionForeground="#FF4E4E4E" KeyUp="taskTitle_KeyUp" LostFocus="taskTitle_LostFocus" Tap="taskTitle_Tap" IsReadOnly="True" Margin="0,1,0,0" DoubleTap="taskTitle_DoubleTap"/>
<TextBox x:Name="taskDetail" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Tea is an essential English beverage, it has a nice calming effect, and is often served alongside biscuits." VerticalAlignment="Top" Width="420" Background="{x:Null}" BorderBrush="{x:Null}" CaretBrush="#FF0080FF" SelectionBackground="#FFCFCFCF" Foreground="#FF878787" BorderThickness="3,0,3,6" FontSize="21.333" Style="{StaticResource listTextBoxTemplate}" InputScope="Text" SelectionForeground="#FF878787" Margin="0,-20,0,0" KeyUp="taskDetail_KeyUp" LostFocus="taskDetail_LostFocus" Padding="2,5,2,2" IsHitTestVisible="False"/>
<Grid Height="170" Margin="0,-20,0,0">
<Button x:Name="chooseDateButton" Content="27/06/2013" HorizontalAlignment="Left" Margin="6,13,0,0" VerticalAlignment="Top" BorderBrush="#FF959595" Foreground="#FF959595" Width="157" HorizontalContentAlignment="Left" FontSize="20" Style="{StaticResource selectorButtonTemplate}"/>
<Button x:Name="chooseTimeButton" Content="12:00" HorizontalAlignment="Left" Margin="146,13,0,0" VerticalAlignment="Top" BorderBrush="#FF959595" Foreground="#FF959595" Width="99" HorizontalContentAlignment="Left" FontSize="20" Style="{StaticResource selectorButtonTemplate}"/>
<Button x:Name="setOrClearButton" Content="REMIND ME" HorizontalAlignment="Left" Margin="228,13,0,0" VerticalAlignment="Top" BorderBrush="#FF959595" Foreground="White" Width="180" FontSize="20" Background="#FF959595" Style="{StaticResource greyButtonTemplate}"/>
<Button x:Name="deleteButton" Content="DELETE TASK" HorizontalAlignment="Left" Margin="6,85,0,0" VerticalAlignment="Top" BorderBrush="#FFEE4747" Foreground="White" Width="180" FontSize="20" Background="#FFEE4747" Style="{StaticResource redButtonTemplate}"/>
<Image x:Name="retractButton" Margin="347,107,21,11" Source="/Assets/retract.png" Stretch="Fill" Tap="retractButton_Tap"/>
</Grid>
</StackPanel>
<CheckBox x:Name="checkBox" IsChecked="{Binding IsComplete, Mode=TwoWay}" Content="" HorizontalAlignment="Left" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Width="72" BorderThickness="0" Template="{StaticResource checkBoxTemplate}" Checked="checkBox_Checked" Unchecked="checkBox_Unchecked"/>
</Grid>
</DataTemplate>
Where the Grid item2Expanded is placed dynamically in a ListBox (Name="allToDoItemsListBox"). Text is added to each item via bindings.
The image retractButton has Tap="retractButton_Tap", As shown in the code:
private void retractButton_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
if (isItemExpanded == true)
{
// Compacts current item
itemGrid.Height = taskTitle.ActualHeight; // Restores itemGrid height to fit only taskTitle
taskTitle.IsReadOnly = true; // taskTitle becomes only double-tap editable, single tap to expand once more
taskDetail.IsHitTestVisible = false; // Stops overlapping taps
isItemExpanded = false;
}
// Adds the event handler for single tap event
tapTimer.Tick += new EventHandler(tapTimer_Tick);
tapTimer.Start();
}
private void tapTimer_Tick(object sender, EventArgs e)
{
// Stop timer
tapTimer.Tick -= new EventHandler(tapTimer_Tick);
tapTimer.Stop();
// Rest of the single tap function
if (isItemExpanded == false)
{
taskDetail.IsHitTestVisible = true;
taskDetail.IsEnabled = false;
// Expands current item
itemGrid.Height = double.NaN; // Sets itemGrid height to auto
isItemExpanded = true;
// Yeah... don't ask.
// Stops temporary text highlighting/auto jumping to keyboard
taskTitle.IsEnabled = false;
taskTitle.IsEnabled = true;
taskDetail.IsEnabled = true;
}
}
But I cannot access itemGrid, taskTitle, or taskDetail for this specific item. And I have no idea how to pass them to the tapTimer_Tick function.
I have been able to use the Tag="{binding itemID}" on elements, but that still hasn't allowed me to solve this issue.
How do I find the grid item2Expanded that the Tap originated from, and then access elements in the same grid by name?
If I want to access the same element as was clicked, then it's easy:
private void taskTitle_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
TextBox taskTitle = (TextBox)sender;
taskTitle.IsEnabled = false;
}
I've been trying to work out how to use Visual Tree Helper to solve this problem, but I have no idea how to do it.

Categories