Another "The name 'itembutton' does not exist in the current context" (WP8, XAML) - xaml

I know that this question has been posted about a thousand times, but I did not find a solution that solved my problem.
I've got a LongListSelector with this ItemTemplate:
<DataTemplate x:Key="AddrBookItemTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock FontWeight="Bold" Text="{Binding Name}" HorizontalAlignment="Stretch" VerticalAlignment="Center" Grid.Column="0" Grid.Row="0" />
<Button x:Name="itembutton" CommandParameter="{Binding ItemID}" Content="{Binding ButtonCaption}" Width="150" HorizontalAlignment="Right" Grid.Column="1" Grid.Row="0" Click="ItemButtonClick"/>
</Grid>
</DataTemplate>
So what happens is simply that I get this beautiful error message that I posted in the title. And I do not have a clue, why?!
private void ItemButtonClick(object sender, RoutedEventArgs e)
{
if (sender == this.itemButton) {
....

From the DataTemplate it looks like you're showing this button in a container like a ListBox or LongListSelector.
That means that there isn't an itembutton in this scope (presumably this is either UserControl or PhoneApplicationPage): there is in fact one for each of your ListBoxItems!
You'll have to find another way of finding your button.
Update:
You should find that the DataContext of your button matches the item of the list it is contained in. That's probably the easiest way of proceeding: however if all else fails you can use the Tag property as you suggest.
Like:
private void ItemButtonClick(object sender, RoutedEventArgs e)
{
var theButton = (Button) sender;
var myItem = (TypeOfAnObjectInMyList) theButton.DataContext;
doSomethingWithMyItem(myItem);

Related

Editor goes behind the keyboard when it resized using Wordwrap in Xamarin.Forms (iOS)?

I am proceeding further and generating new ticket as it is quite different from this issue How to prevent Editor to go behind the keyboard in Xamarin.Forms?
I have chat page and autosize editor. When user type more than 1-2 lines, Editor expand correctly but it goes behind the keyboard.
However, if user add multiple lines using "return" it works correctly. I think I am missing something in Xaml page to play with Editor and StackLayout.
Please suggest
Please note that I don't use Xam.Plugins.Forms.KeyboardOverlap. To manage layout on keyboard visibility, I use custom stacklayout WrapperStackLayoutRenderer which set bottom padding on appear and disappear of keyboard.
Page Xaml
<ContentPage.Content>
<local1:WrapperStackLayout>
<Grid Margin="0" Padding="0" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ListView x:Name="MessagesListView"
ItemTemplate="{StaticResource MessageTemplateSelector}"
ItemsSource="{Binding Conversations}"
HasUnevenRows="True"
Margin="0"
Grid.Row="0"
SeparatorVisibility="None"/>
<Grid RowSpacing="1" ColumnSpacing="2" Padding="5" Grid.Row="1" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<local1:EditorWithAutoSize x:Name="txtMessage" Text="{Binding SendingText}" TextChanged="EnableSend"/>
<Frame x:Name="SendButton" Grid.Column="1" Margin= "0" Padding="0" HasShadow="false" HeightRequest="25"
BackgroundColor="Transparent" HorizontalOptions="FillAndExpand">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="SendMessage_Click" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
<Label Text="Send" x:Name="sendButton" HeightRequest="20"
HorizontalOptions="Center" VerticalOptions="Center"/>
</Frame>
</Grid>
</Grid>
</local1:WrapperStackLayout>
</ContentPage.Content>
EditorWithAutoSize
public class EditorWithAutoSize : Editor
{
public EditorWithAutoSize()
{
this.TextChanged += (sender, e) => {
this.InvalidateMeasure();
};
}
}
WrapperStackLayout
public class WrapperStackLayout : StackLayout
{
}
WrapperStackLayoutRenderer
public class WrapperStackLayoutRenderer : VisualElementRenderer<StackLayout>
{
public WrapperStackLayoutRenderer()
{
UIKeyboard.Notifications.ObserveWillShow((sender, args) =>
{
if (Element != null)
{
Element.Margin = new Thickness(0, 0, 0, (args.FrameEnd.Height));
}
});
UIKeyboard.Notifications.ObserveWillHide((sender, args) =>
{
if (Element != null)
{
Element.Margin = new Thickness(0); //set the margins to zero when keyboard is dismissed
}
});
}
}
You have to add RowDefinition Height="auto" in your second Grid, then the editor will auto group with the text you entered:
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
The complete code should be:
<Grid RowSpacing="1" ColumnSpacing="2" Padding="5" Grid.Row="1" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<local:EditorWithAutoSize x:Name="txtMessage" Text="Binding SendingText" />
<Frame x:Name="SendButton" Grid.Column="1" Margin= "0" Padding="0" HasShadow="false" HeightRequest="25"
BackgroundColor="Transparent" HorizontalOptions="FillAndExpand">
<Label Text="Send" x:Name="sendButton" HeightRequest="20"
HorizontalOptions="Center" VerticalOptions="Center"/>
</Frame>
</Grid>
I uploaded my test sample here and you can check it: editor-xamarin.forms
BTW, there is a sample in github that you can refer: ChatUIXForms, you can use the editor and custom renderer code in his project. There are also blogs the author wrote you can read.

Only capture tap event from button contained in ListViewItem without triggering item click - UWP Windows 10

In my UWP app which uses MVVMLight, I have a button contained in my ListViewItem and when clicked I want to display a flyout and provide additional actions for the specific ListViewItem but whenever I tap on the button, I get an error i.e.
System.InvalidCastException: Unable to cast object of
type 'Windows.UI.Xaml.Input.TappedRoutedEventArgs' to
type 'MyApp.ViewModels.ItemViewModel'.
at GalaSoft.MvvmLight.Command.RelayCommand`1.Execute(Object parameter)
at Microsoft.Xaml.Interactions.Core.InvokeCommandAction.Execute(Object
sender, Object parameter) at
Microsoft.Xaml.Interactivity.Interaction.ExecuteActions(Object sender,
ActionCollection actions, Object parameter)
at Microsoft.Xaml.Interactions.Core.EventTr
I understand to some extend why it's happening but how I can I fix this? The button contained in my ListViewItem data template is obviously being passed to the parent which is the listview and the DataTrigger that's defined in the Listview is capturing it.
All I want to do is display a flyout when this button is clicked to provide additional options.
<ListView.ItemTemplate>
<DataTemplate>
<Grid Background="{StaticResource SystemControlBackgroundAccentBrush5}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="4"
Width="90"
Height="90"
VerticalAlignment="Center"
Margin="5,5,0,5">
<Image Width="90"
Height="90"
Source="{Binding Logo}" />
</Border>
<Grid Grid.Row="0" Grid.Column="1" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal"
Grid.Row="1" VerticalAlignment="Bottom">
<TextBlock Text="Id:" FontWeight="SemiBold" Foreground="White" VerticalAlignment="Center"/>
<TextBlock Text="{Binding Subject}" Margin="10,0,0,0" Foreground="White" VerticalAlignment="Center"/>
</StackPanel>
<Button Width="30" Height="30"
Command="{Binding AdditionalInfoCommand}"
Grid.RowSpan="4"
Grid.Column="1"
Margin="0,0,12,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Stroke="{ThemeResource SystemControlBackgroundAccentBrush}"
Fill="{ThemeResource SystemControlBackgroundAccentBrush}"
StrokeThickness="2">
</Ellipse>
<Image Source="ms-appx:///Assets/Information.png" Width="30" Height="30" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
and my ListView has the following code:
<ListView ItemsSource="{Binding MyList}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
SelectionMode="Single">
<ListView.ItemTemplate>
.... as defined above
</ListView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction Command="{Binding ItemClickCommand}"
CommandParameter="{Binding SelectedItem}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</ListView>
Any ideas on how I can resolve this?
UPDATE 1:
I'll re-phrase my question slightly. I've managed to bind the button displayed on the ListViewItem to a specific click event by introducing a RelayCommand (AdditionalInfoCommand) in the item's ViewModel. So now my main problem is the actual error mentioned above which is triggered after AdditionalInfoCommand and I assume it's because it is being captured by the ItemClickCommand. Strange as you would assume that it is using the same ViewModel.
Is there a way to no trigger the itemclick when this button is tapped?
Thanks.
Thierry
I figured it out.
When I tap the button inside my ListView DataTemplate, the button is being passed the Item's ViewModel which is correct but then the tap event is bubbled up back to the parent which is captured by:
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction Command="{Binding ItemClickCommand}"
CommandParameter="{Binding SelectedItem}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
While there may be a solution to stop the event bubbling, to circumvent the problem, I changed my ItemClickCommand.
It was defined as follows:
private RelayCommand<MyItemViewModel> _itemClickCommand;
public RelayCommand<MyItemViewModel> ItemClickCommand
{
get { return this._itemClickCommand ?? (this._itemClickCommand =
new RelayCommand<MyItemViewModel>((viewModel) =>
ItemClickCommandAction(viewModel))); }
}
I simply changed it to:
private RelayCommand<object> _itemClickCommand;
public RelayCommand<object> ItemClickCommand
{
get { return this._itemClickCommand ?? (this._itemClickCommand =
new RelayCommand<object>((viewModel) =>
ItemClickCommandAction(viewModel))); }
}
I then changed the ItemClickCommandAction to take in an object instead of MyItemViewModel and now, within the method, I check the type of the ViewModel being passed:
private void ItemClickCommandAction(object currentObject)
{
if (currentObject is MyItemViewModel)
{
//go to next page
}
}

Textbox not losing focus when tapping anywhere inside Popup control

I have a Popup with a Textbox and a Button control in it.
When I click/tap anywhere inside the Popup, the Textbox doesn't lose focus.
The only way to make the Textbox lose focus is to set focus on the Button.
I want to be able to remove focus from the Textbox without having to close the Popup or clicking the button.
This issue only occurs in a Popup.
I used to have the controls in a Flyout, and the behavior there is when a user clicks outside the Textbox and anywhere inside the Flyout, the Textbox loses focus. Also when the Flyout opens, the Textbox would automatically get focus on Flyout opening.
I tested the different behaviors for how Textboxes losing focus in a new blank UWP project, and it's the same. Also tested behavior of Textbox directly in root-grid. This is the XAML from MainPage:
<Page x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:App1"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Margin="0,40"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Orientation="Horizontal">
<Button Margin="20,0"
Content="Popup button"
Tapped="Button_Tapped" />
<Button Margin="20,0" Content="Flyout button">
<Button.Flyout>
<Flyout>
<Grid Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox VerticalAlignment="Center" />
<Button Grid.Column="1" Content="Test" />
</Grid>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
<Popup x:Name="MyPopup"
Width="320"
Height="60"
IsLightDismissEnabled="True">
<Grid Width="320"
Height="60"
Background="WhiteSmoke"
Padding="12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox VerticalAlignment="Center" />
<Button Grid.Column="1" Content="Test" />
</Grid>
</Popup>
<TextBox Grid.Row="1"
MinWidth="64"
MaxWidth="300"
Margin="0,40"
VerticalAlignment="Center" />
</Grid>
</Page>
And the event to open the Popup:
private void Button_Tapped(object sender, TappedRoutedEventArgs e)
{
MyPopup.IsOpen = true;
}
The problem is that Grid is not "focusable" because it does not derive from Control. One way is that you place your Grid inside a ContentControl or ContentPresenter.
The other way is a bit of a hack but you can set the focus programatically on the button when the Grid inside the Popup is tapped:
<Popup
x:Name="MyPopup"
Width="320"
Height="60"
IsLightDismissEnabled="True">
<Grid
x:Name="Grid"
Width="320"
Height="60"
Background="WhiteSmoke"
Tapped="Grid_OnTapped"
Padding="12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox VerticalAlignment="Center" />
<Button
Grid.Column="1"
Content="Test" />
</Grid>
</Popup>
And the Tapped handler in which you generally search for any focusable control that is not a TextBox. If you don't have any you can place an invisible ContentControl with Opacity=0.01 for example and this will then be the focus element:
private void Grid_OnTapped(object sender, TappedRoutedEventArgs e)
{
var grid = sender as Grid;
if(grid == null) return;
var controlToFocus = FindChild<Button>(grid);
controlToFocus.Focus(FocusState.Programmatic);
}
private static T FindChild<T>(DependencyObject parent) where T : DependencyObject
{
var childCount = VisualTreeHelper.GetChildrenCount(parent);
for (var i = 0; i < childCount; i++)
{
var elt = VisualTreeHelper.GetChild(parent, i);
if (elt is T) return (T)elt;
var result = FindChild<T>(elt);
if (result != null) return result;
}
return null;
}

UWP - adding items to ListView dynamically cause crash

I have a listview defined like this:
<ListView
x:Name="phonesListView"
Grid.Row="5"
Background="Black"
IsItemClickEnabled="True"
Foreground="Gray" >
<ListView.ItemTemplate>
<DataTemplate>
<Grid Width="auto" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid
Grid.Row="0">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ComboBox
Grid.Column="0"
VerticalAlignment="Center"
Background="Black"
Foreground="White">
<ComboBoxItem Content="Home" IsSelected="True"/>
<ComboBoxItem Content="{Binding Type}"/>
<ComboBoxItem Content="Office"/>
<ComboBoxItem Content="Fax"/>
</ComboBox>
<Button
Grid.Column="1"
Height="30"
Width="30"
Foreground="Black"
Margin="0, 5, 0, 5"
HorizontalAlignment="Center" Click="RemovePhone">
<Button.Background>
<ImageBrush Stretch="Fill" ImageSource="Assets/appbar.close.png" />
</Button.Background>
</Button>
</Grid>
<TextBox
Grid.Row="1"
Background="White"
Foreground="Black"
FontSize="20"
InputScope="TelephoneNumber"
Text="{Binding Number}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have an private ObservableCollection<Phone> numbers = new ObservableCollection<Phone>();
In constructor I call phonesListView.ItemSource = numbers;
And on some button click I want to add new item to the listView so I call a method:
private void AddPhone(object sender, RoutedEventArgs e) {
Phone phone = new Phone("", Types.HOME);
numbers.Add(phone);
}
But after button click to add a item the app crashes and App.g.i.cs is called and global::System.Diagnostics.Debugger.Break(); is highlighted
#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException += (sender, e) =>
{
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
};
#endif
I'm really new to Universal Windows App, and I read that this is called when something is wrong with XAML code. Could you help me with that? Thanks.
I tried to use ItemsSource="{x:Bind Mode=TwoWay}"
The only way (but not the best, I think) where I could dynamically update a listview was making a method that handle a button event where I add a new element (calling the addmethod) and updating the ItemsSource property of the list view.
private void AnadeDoctorAppBarButton_Click(object sender, RoutedEventArgs e)
{
Doctor A = new Doctor("Mapache", "dentista", "La calle", "La vida", "Lo que sea", "Direccion", "olos");
ViewModel.AnadeDoctor = A;
ListaDePrueba.ItemsSource = ViewModel.ColeccionDoctores;
}
It Works, but I think that is not true Databinding.

XAML: Binding scrollviewer with 2 sources

Trying to learn xaml designing. I got this picture from internet and use it as a model to practice. There is a problem: When I click one of day buttons, a scrollviewer with a list of day tasks appears. Each task has a list of hours in day, from start time to end time. I don't know whether they are from one source or 2 source (one describes day task and the other one is a list of hours of this task).
I tried with this
public async void ShowTasks()
{
ObservableCollection<DayTask> Data = await App.DataSource.GetData();
DateListBox.ItemsSource = Data;
DayTask daytask = Data.Where(x => x.Day.Date == App.Day.Date).FirstOrDefault();
TasksListView.ItemsSource = daytask.Tasks;
List<HoursModel> HoursList = new List<HoursModel>();
foreach (var simpletask in daytask.Tasks)
{
HoursList.Add(new HoursModel(simpletask.StartTimeHour, simpletask.EndTimeHour));
}
HoursListView.ItemSource = HoursList;
}
This is my xaml code:
<ScrollViewer Height="730" Width="300" >
<ListView
x:Name="TasksListView" Height="730" Width="300"
HorizontalAlignment="Right">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="7*"/>
</Grid.ColumnDefinitions>
<ListView
Grid.Column="0"
x:Name="HoursListView">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock
x:Name="ShowedHours"
Text="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Grid Grid.Column="1">
<Rectangle
Fill="Pink"
Height="75"
Width="150"
Margin="60,20,0,0"/>
<TextBlock
Text="{Binding Description}"
FontSize="17"
TextWrapping="Wrap"
Margin="80,20,0,0"/>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
I got an error with HoursListView.ItemSource = HoursList;. The detail of this error is
The name 'HoursListView' does not exist in the current context. Does anyone have any suggestions how I can do this ?
You can't access control in DataTemplate directly by it's name. That makes sense because DataTemplate in this case is generated repeatedly for each item within TasksListView.
According to XAML markup posted, you want to have different HoursList for each DayTask. That can be achieved by adding an HoursList property in DayTask class. I'd suggest to use ObservableCollection instead of List because the former has built-in feature to notify bound UI to refresh whenever item added to or removed from collection :
public class DayTask
{
public ObservableCollection<HoursModel> HoursList { get; set; }
.....
}
Then bind HoursListView's ItemsSource to above property :
.....
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="7*"/>
</Grid.ColumnDefinitions>
<ListView
Grid.Column="0"
ItemsSource="{Binding HoursList}"
x:Name="HoursListView">
.....
</ListView>
</Grid>
</DataTemplate>
.....
Don't forget to populate all HoursList properties before setting DateListBox.ItemsSource.