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

Time:05-06

I have a bug in my code. FindChild() is searching a Element wich is named "PasswordTextBox" but because "PasswordTextBox" is in the DataTemplate there are many TextBoxes. And if I will click on the eye (the mah:FontIcon) in the second row or third row or whatever it even changes the FontFamily of the first TextBox in the DataTemplate.

How can I change the TextBox.FontFamily of the element in the row of the DataTemplate where the eye is clicked?

That is the xaml code:

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

And that is my c# code behind:

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

CodePudding user response:

you can search within template bounds, relative to sender element:

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

btw, ShowPassword should also be relative to each password box, shouldn't it?

CodePudding user response:

Maybe Triggers will help?

    <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.Style>
           <Style TargetType="TextBox">
               <Style.Triggers>
                   <Trigger Property="IsEyeClicked" Value="True">
                       <Setter Property="FontFamily" Value="WhateverFontFamily"/>
                   </Trigger>
               </Style.Triggers>
           </Style>
       </TextBox.Style>
   </TextBox>

That's just a rough example, more info here: https://wpf-tutorial.com/styles/trigger-datatrigger-event-trigger/

  • Related