Reputation: 93
How do I get a reference to a object bound to a control displayed as part of ItemsRepeater?
XAML:
<Grid>
<controls:ItemsRepeater ItemsSource="{x:Bind cars}">
<controls:ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="local:Car">
<Button Content="{x:Bind Brand}" Tapped="Button_Tapped"/>
</DataTemplate>
</controls:ItemsRepeater.ItemTemplate>
</controls:ItemsRepeater>
</Grid>
C#:
private ObservableCollection<Car> cars = new ObservableCollection<Car>()
{
new Car()
{
Brand = "Audi",
Model = "123",
Color = "Red",
Price = "100 000 $"
},
new Car()
{
Brand = "BMW",
Model = "456",
Color = "Black",
Price = "150 000 $"
},
};
private void Button_Tapped(object sender, TappedRoutedEventArgs e)
{
// Warning: The code line bellow does not work. The problem is here.
Car selectedCar = (sender as FrameworkElement).DataContext as Car;
Debug.WriteLine("Brand: " + selectedCar.Brand);
Debug.WriteLine("Model: " + selectedCar.Model);
Debug.WriteLine("Color: " + selectedCar.Color);
Debug.WriteLine("Price: " + selectedCar.Price);
// Expected result (if Audi button is tapped):
// Brand: Audi
// Model: 123
// Color: Red
// Price: 100 000 $
// Actual result:
// System.NullReferenceException: 'Object reference not set to an instance of an object.'
}
EDIT: Updated the example code to be better illustrate the issue.
It looks like your post is mostly code; please add some more details.
Upvotes: 1
Views: 420
Reputation: 859
Updated due to update of the original question.
While trying my previously used method for this I found an even easier solution which should enable you to just use your original code.
Just add
DataContext="{x:Bind}"
to your
<Button Content="{x:Bind Brand}" Tapped="Button_Tapped"/>
line.
This solution is similar to above stated solution, however for this I introduce an extra DependencyProperty
to a custom Button
class:
public class CustomButton : Button
{
public static readonly DependencyProperty BoundCarProperty =
DependencyProperty.Register("BoundCar", typeof(Car), typeof(CustomButton), new PropertyMetadata(new Car(), new PropertyChangedCallback(BoundCarValueChanged)));
private static void BoundCarValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SpecialButton s = d as SpecialButton;
Car c = d.GetValue(BoundCarProperty) as Car;
}
public Car BoundCar
{
get => (Car)GetValue(BoundCarProperty);
set => SetValue(BoundCarProperty, value);
}
}
Now I change the XAML to:
<local:SpecialButton BoundCar="{x:Bind Mode=OneWay}" Content="{x:Bind Brand}" Tapped="Button_Tapped"/>
As an added benefit to the first solution, this enables you to catch changes to the bound property, which you can handle in the BoundCarValueChanged
event.
Upvotes: 1