Изменение свойства другого элемента управления в триггере некоторого элемента управления с «динамическим» именем - PullRequest
0 голосов
/ 18 декабря 2011

Я пытаюсь динамически изменить стиль меток в моих формах. Мне нужно следующее поведение: каждый раз, когда текстовое поле с именем 'txtName', например, становится Focused, оно должно искать элемент управления Label с именем 'lblName' и изменять его свойство FontWeight на "Bold".

То же самое для текстового поля с именем «txtBirthday» и метки с именем «lblBirthday», где «txt» обозначает TextBox, а lbl - «Label».

Каждое текстовое поле имеет ИМЯ, префикс «txt» и префикс «lbl» для соответствующей метки, но если текстовое поле не находит метку соответствующей расшифровки, оно ничего не должно делать.

Другими словами, каждый раз, когда текстовое поле фокусируется на форме, оно должно искать ярлык «ответственно» для своего описания и выделять его (изменяя вес шрифта на жирный), чтобы форма была более удобной для пользователя. Таким образом, пользователь не будет смущен тем, в какое текстовое поле он печатает.

У меня есть код, который может быть хорошей отправной точкой, но я не знаю, как работать с нестатическими именами элементов управления.

    <Style TargetType="{x:Type Label}">

    <Style.Triggers>
        <!-- Here is how we bind to another control's property -->
        <DataTrigger Binding="{Binding IsFocused, ElementName=txtUser}" Value="True">
            <Setter Property="FontWeight" Value="Bold" />
            <!-- Here is the 'override' content -->
        </DataTrigger>

    </Style.Triggers>

</Style>

Ответы [ 2 ]

0 голосов
/ 18 декабря 2011

Вы можете сделать так, чтобы все получили фокус на одно и то же событие. Отправитель передается на событие, чтобы вы могли получить имя отправителя. В коде позади вы можете использовать переменную и логику, которых нет в XAML.

0 голосов
/ 18 декабря 2011

Как уже упоминалось в комментариях выше, методика поиска и сопоставления имен элементов в качестве основы для применения визуального поведения не является надежной.Например, что происходит, когда вы делаете опечатку и используете «lbel» вместо «lbl»?Или что произойдет, если вы позже решите заменить все Labels на TextBlocks - вы все еще аннотируете их имена префиксом "lbl", чтобы сохранить поведение?Еще один недостаток использования кода для изменения визуальных элементов - теперь понимание поведения вашего пользовательского интерфейса при чтении только XAML становится намного сложнее, поскольку свойства изменяются негласно.WPF имеет много встроенных способов, которые должны быть предпочтительнее этого подхода.Если вы заинтересованы в альтернативных реализациях, просто попросите нас помочь:)

При этом, если должен использовать этот подход, вот как будет выглядеть ваше прикрепленное поведение:

C #

public static class FontWeightFocusedHelper
{
    private static readonly List<Label> Labels = new List<Label>();

    public static void SetChangeFontWeightOnTextBoxFocused(Label label, bool value)
    {
        label.SetValue(ChangeFontWeightOnTextBoxFocusedProperty, value);
    }

    public static bool GetChangeFontWeightOnTextBoxFocused(Label label)
    {
        return (bool) label.GetValue(ChangeFontWeightOnTextBoxFocusedProperty);
    }

    public static readonly DependencyProperty ChangeFontWeightOnTextBoxFocusedProperty =
        DependencyProperty.RegisterAttached("ChangeFontWeightOnTextBoxFocused", typeof (bool),
                                            typeof (FontWeightFocusedHelper),
                                            new FrameworkPropertyMetadata(OnChangeFontWeightOnTextBoxFocusedPropertyChanged));

    private static void OnChangeFontWeightOnTextBoxFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is TextBox)
        {
            var textBox = (TextBox) d;
            // Make sure to use a WeakEventManager here otherwise you will leak ...
            textBox.GotFocus += OnTextBoxGotFocusChanged;
            textBox.LostFocus += OnTextBoxLostFocusChanged;
            return;
        }

        if (d is Label)
        {
            // Make sure to store WeakReferences here otherwise you will leak ...
            Labels.Add((Label)d);
            return;
        }

        throw new InvalidOperationException("ChangeFontWeightOnTextBoxFocused can only be set on TextBox and Label types.");
    }

    private static void OnTextBoxLostFocusChanged(object sender, RoutedEventArgs e)
    {
        SetMatchingLabelFontWeight(sender as TextBox, FontWeights.Regular);
    }

    private static void OnTextBoxGotFocusChanged(object sender, RoutedEventArgs e)
    {
        SetMatchingLabelFontWeight(sender as TextBox, FontWeights.Bold);
    }

    private static void SetMatchingLabelFontWeight(TextBox textBox, FontWeight fontWeight)
    {
        if (textBox != null)
        {
            // Suggest adding a property for LabelPrefix and TextBoxPrefix too, use them here
            var label = Labels.Where(l => !String.IsNullOrEmpty(l.Name))
                              .Where(l => l.Name.Replace("lbl", "txt") == textBox.Name)
                              .FirstOrDefault();

            if (label != null)
            {
                label.FontWeight = fontWeight;
            }
        }
    }
}

XAML

    <StackPanel >
        <StackPanel.Resources>
            <Style TargetType="{x:Type TextBox}">
                <Setter Property="l:FontWeightFocusedHelper.ChangeFontWeightOnTextBoxFocused" Value="True" />
            </Style>
            <Style TargetType="{x:Type Label}">
                <Setter Property="l:FontWeightFocusedHelper.ChangeFontWeightOnTextBoxFocused" Value="True" />
            </Style>
        </StackPanel.Resources>
        <StackPanel Orientation="Horizontal">                
            <Label x:Name="lblOne" VerticalAlignment="Center" Content="First Name"/>
            <TextBox x:Name="txtOne" Width="300" VerticalAlignment="Center"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Label x:Name="lblTwo" VerticalAlignment="Center" Content="Last Name" />
            <TextBox x:Name="txtTwo" Width="300" VerticalAlignment="Center" />
        </StackPanel>
    </StackPanel>

Надеюсь, это поможет!

...