如何从代码隐藏更改 DataTemplate 中特定元素的 属性?

How to change a property of a specific element in a DataTemplate from code behind?

我的代码中有一个错误。 FindChild<T>() 正在搜索一个名为“PasswordTextBox”的元素,但因为“PasswordTextBox”在 DataTemplate 中,所以有很多文本框。如果我单击第二行或第三行中的眼睛(mah:FontIcon)或其他任何内容,它甚至会更改 DataTemplate 中第一个 TextBox 的 FontFamily。

如何更改 DataTemplate 中单击眼睛所在行的元素的 TextBox.FontFamily?

也就是xaml代码:

<HeaderedItemsControl Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="1">
    <ItemsControl x:Name="ListViewItems">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border Margin="1 10 0 10" Height="60">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="50" />
                            <ColumnDefinition Width="100" />
                        </Grid.ColumnDefinitions>
                        <TextBox Grid.Column="1" 
                                 x:Name="PasswordTextBox"
                                 Text="{Binding Password, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                 Height="40" 
                                 VerticalAlignment="Center"
                                 VerticalContentAlignment="Center" 
                                 HorizontalContentAlignment="Left"
                                 HorizontalAlignment="Stretch" 
                                 FontFamily="pack://application:,,,/Fonts/#password"
                                 Margin="-25 0 100 0"
                                 Padding="6, 4, 45, 0">
                        </TextBox>
                        <mah:FontIcon Grid.Column="1" 
                                      FontFamily="Segoe MDL2 Assets"
                                      HorizontalAlignment="Right"
                                      VerticalAlignment="Center"
                                      FontSize="28"
                                      Glyph="&#xF78D;"
                                      Margin="0, 0, 110, 0"
                                      Foreground="#cfcfcf"
                                      MouseLeftButtonUp="OnEyeClicked" />
                    </Grid>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</HeaderedItemsControl>

那是我背后的 C# 代码:

   private void OnEyeClicked(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        TextBox foundTextBox = FindChild<TextBox>(Application.Current.MainWindow, "PasswordTextBox");
        if (ShowPassword)
        {
            foundTextBox.FontFamily = new FontFamily("Segoe MDL2");
            foundTextBox.Padding = new Thickness(6, 4, 45, 0);
            ShowPassword = false;
        }
        else
        {
            foundTextBox.FontFamily = new FontFamily(new Uri("pack://application:,,,/"), "./Fonts/#password");
            foundTextBox.Padding = new Thickness(6, 0, 45, 0);
            ShowPassword = true;
        }
    }
    
    public static T FindChild<T>(DependencyObject parent, string childName)
        where T : DependencyObject
    {
        // Confirm parent and childName are valid. 
        if (parent == null) return null;
    
        T foundChild = null;
    
        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);
            // If the child is not of the request child type child
            T childType = child as T;
            if (childType == null)
            {
                // recursively drill down the tree
                foundChild = FindChild<T>(child, childName);
    
                // If the child is found, break so we do not overwrite the found child. 
                if (foundChild != null) break;
            }
            else if (!string.IsNullOrEmpty(childName))
            {
                var frameworkElement = child as FrameworkElement;
                // If the child's name is set for search
                if (frameworkElement != null && frameworkElement.Name == childName)
                {
                    // if the child's name is of the request name
                    foundChild = (T)child;
                    break;
                }
            }
            else
            {
                // child element found.
                foundChild = (T)child;
                break;
            }
        }
        return foundChild;
    }

您可以在模板范围内搜索,相对于 sender 元素:

private void OnEyeClicked(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    var ico = (FontIcon)sender;
    var grid = (Grid)ico.Parent;
    TextBox foundTextBox = FindChild<TextBox>(grid, "PasswordTextBox");
    if (ShowPassword)
    {
        foundTextBox.FontFamily = new FontFamily("Segoe MDL2");
        foundTextBox.Padding = new Thickness(6, 4, 45, 0);
        ShowPassword = false;
    }
    else
    {
        foundTextBox.FontFamily = new FontFamily(new Uri("pack://application:,,,/"), "./Fonts/#password");
        foundTextBox.Padding = new Thickness(6, 0, 45, 0);
        ShowPassword = true;
    }
}

顺便说一句,ShowPassword 也应该是相对于每个密码框的,不是吗?