Reputation: 316
Here is my XAML:
<ItemsControl Margin="0 0 0 0" Name="CtrlOrderDetails" AlternationCount="2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="Foobar">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="0 5 0 5" FontSize="16" Text="{Binding DrugName}"></TextBlock>
<TextBox Grid.Column="2" FontSize="10" Width="100" Height="20" HorizontalContentAlignment="Center" HorizontalAlignment="Center" VerticalContentAlignment="Center" VerticalAlignment="Center" Tag="{Binding BarCode}"
Text="Enter Barcode.." LostFocus="BarcodeTextBox_OnLostFocus"></TextBox>
<CheckBox x:Name="IsGoodCheckBox" Grid.Column="4" IsEnabled="False" VerticalAlignment="Center"></CheckBox>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="LightGray" TargetName="Foobar"></Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
What I want to happen is that when the user enters the barcode in the textbox, if it matches the value in the Tag property then the checkbox should be set to checked.
Here is my code behind:
private void BarcodeTextBox_OnLostFocus(object sender, RoutedEventArgs e)
{
var tb = sender as TextBox;
ContentPresenter contentPresenter = FindVisualChild<ContentPresenter>(CtrlOrderDetails);
DataTemplate yourDataTemplate = contentPresenter.ContentTemplate;
CheckBox thisCheckBox = yourDataTemplate.FindName("IsGoodCheckBox", contentPresenter) as CheckBox;
if (tb.Text == tb.Tag.ToString())
{
thisCheckBox.IsChecked = true;
}
else
{
thisCheckBox.IsChecked = false;
}
}
public TChildItem FindVisualChild<TChildItem>(DependencyObject obj) where TChildItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
var child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is TChildItem)
return (TChildItem)child;
var childOfChild = FindVisualChild<TChildItem>(child);
if (childOfChild != null)
return childOfChild;
}
return null;
}
If I try it on the first row in my list, it works great. But, If I try it on the second row, it effects the checkbox in the first row again.
Obviously, my code does not which row I am on. How could I do that?
Thanks
Upvotes: 1
Views: 485
Reputation: 37059
This would be a more conventional XAML way of doing it. No code behind, just bindings and a converter.
<ItemsControl Margin="0 0 0 0" Name="CtrlOrderDetails" AlternationCount="2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<local:EqualityMultiConverter
x:Key="EqualityConverter"
/>
</DataTemplate.Resources>
<Grid x:Name="Foobar">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="0 5 0 5" FontSize="16" Text="{Binding DrugName}"></TextBlock>
<TextBox
x:Name="BarCodeTextBox"
Grid.Column="2"
FontSize="10"
Width="100"
Height="20"
HorizontalContentAlignment="Center"
HorizontalAlignment="Center"
VerticalContentAlignment="Center"
VerticalAlignment="Center"
Tag="{Binding BarCode}"
Text="Enter Barcode.."
LostFocus="BarcodeTextBox_OnLostFocus"
/>
<CheckBox
x:Name="IsGoodCheckBox"
Grid.Column="4"
IsEnabled="False"
VerticalAlignment="Center"
>
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource EqualityConverter}">
<Binding Path="BarCode" />
<Binding Path="Text" ElementName="BarCodeTextBox"/>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="LightGray" TargetName="Foobar"></Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Multiconverter class:
public class EqualityMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// Return true if we have fewer than two values,
// or if we have at least two, and they're all equal.
return values.Length < 2 || values.Skip(1).All(v => values[0] == v);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Upvotes: 1
Reputation: 169200
Try this:
private void BarcodeTextBox_OnLostFocus(object sender, RoutedEventArgs e)
{
var tb = sender as TextBox;
Panel grid = tb.Parent as Panel;
if (grid != null)
{
CheckBox checkBox = grid.Children.OfType<CheckBox>().FirstOrDefault(x => x.Name == "IsGoodCheckBox");
if (checkBox != null)
{
//set the IsChecked property based on your logic here...
checkBox.IsChecked = tb.Text == tb.Tag.ToString();
}
}
}
Upvotes: 1
Reputation: 975
Your code is finding the same CheckBox everytime because you define it by name. Instead you should look by a control type.
According to answer from another question, you could try something like this:
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
Upvotes: 0