如何从代码隐藏中引用我的项目控件中的另一个控件?

How to reference another control in my Items Control from Code Behind?

这是我的 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>

我想要发生的是,当用户在文本框中输入条形码时,如果它与标记中的值匹配 属性,则应将复选框设置为选中。

下面是我的代码:

  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;
    }

如果我在列表的第一行尝试它,效果很好。但是,如果我在第二行尝试它,它会再次影响第一行中的复选框。

很明显,我的代码并不知道我在哪一行。我怎么能那样做?

谢谢

您的代码每次都找到相同的 CheckBox,因为您是按名称定义它的。相反,您应该按控件类型查看。

根据 another question 的回答,您可以尝试这样的操作:

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;
            }
        }
    }
}

试试这个:

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();
        }
    }
}

这将是一种更传统的 XAML 方法。没有代码隐藏,只有绑定和转换器。

<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>

多转换器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();
    }
}