Измените размер TextBlock на кнопку, которая динамически меняет ширину

У меня есть TextBlock, который находится поверх Button в Grid. Я хотел бы, чтобы затем отображалось так:

"some very long text" <-- text
"that doesn't fit" <-- text wrapped
[my button text size] <-- button

Однако то, что у меня есть, это:

"some very long text that doesn't fit" <-- text
[my button text size] <-- button

Моя проблема в том, что текст в Button динамически устанавливается через локализованный ресурс, и поэтому ширина кнопки изменяется динамически.

Статическое решение, которое работает для нединамического изменения размера Button:

                <TextBlock
                    Margin="5"
                    TextWrapping="Wrap"
                    Width="{Binding ElementName=requestDemoButton, Path=RenderSize.Width}"
                    Text="{Binding Path=Resource.Text, Source={StaticResource LocalizedStrings }}"
                    />
                <Button 
                    x:Name="requestDemoButton"
                    Margin="5" 
                    Height="Auto" 
                    Width="Auto" 
                    HorizontalAlignment="Right"
                    Content="{Binding Path=Resource.Button, Source={StaticResource LocalizedStrings }}" />

Идеи, кто-нибудь? В настоящее время я думаю о том, чтобы прикрепить класс Behavior к TextBlock, который прослушивает событие SizeChanged на Button. Я хотел бы иметь встроенное решение, если оно существует.


person R4cOOn    schedule 18.11.2009    source источник


Ответы (1)


Если кому-то интересно, вот как я поступил в поведении. Я передаю Height или Width в зависимости от свойства, которое я хочу связать.

Вот класс:

public static class DynamicControlResizeBehavior
{
    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.RegisterAttached("Target", typeof(FrameworkElement), typeof(DynamicControlResizeBehavior), new PropertyMetadata(OnTargetSetCallback));

    public static readonly DependencyProperty PropertyNameProperty =
        DependencyProperty.RegisterAttached("PropertyName", typeof(string), typeof(DynamicControlResizeBehavior), new PropertyMetadata(OnPropertyNameSetCallback));


    public static string GetPropertyName(DependencyObject obj)
    {
        return (string)obj.GetValue(PropertyNameProperty);
    }

    public static void SetPropertyName(DependencyObject obj, string value)
    {
        obj.SetValue(PropertyNameProperty, value);
    }

    public static FrameworkElement GetTarget(DependencyObject obj)
    {
        return (FrameworkElement)obj.GetValue(TargetProperty);
    }

    public static void SetTarget(DependencyObject obj, FrameworkElement value)
    {
        obj.SetValue(TargetProperty, value);
    }

    private static void SynchronizeProperty(DependencyObject dependencyObject)
    {
        var target = GetTarget(dependencyObject);
        if (target != null)
        {
            var propertyName = GetPropertyName(dependencyObject);

            DependencyProperty dependencyToRead;
            DependencyProperty dependencyToWrite;
            if (string.Equals(propertyName, "Width", StringComparison.InvariantCulture))
            {
                dependencyToRead = FrameworkElement.ActualWidthProperty;
                dependencyToWrite = FrameworkElement.WidthProperty;
            }
            else if (string.Equals(propertyName, "Height", StringComparison.InvariantCulture))
            {
                dependencyToRead = FrameworkElement.ActualHeightProperty;
                dependencyToWrite = FrameworkElement.HeightProperty;
            }
            else
            {
                return;
            }

            var propertySize = (double)target.GetValue(dependencyToRead);
            dependencyObject.SetValue(dependencyToWrite, propertySize);
        }
    }

    private static void OnTargetSetCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var oldElement = e.OldValue as FrameworkElement;
        if (oldElement != null)
        {
            oldElement.SizeChanged -= (o, s) => SynchronizeProperty(d);
        }

        var newElement = e.NewValue as FrameworkElement;
        if (newElement != null)
        {
            newElement.SizeChanged += (o, s) => SynchronizeProperty(d);
        }
    }

    private static void OnPropertyNameSetCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SynchronizeProperty(d);
    }
}

И вот как это используется:

            <TextBlock
                Behaviors:DynamicControlResizeBehavior.Target="{Binding ElementName=submitButton}"
                Behaviors:DynamicControlResizeBehavior.PropertyName="Width"
                HorizontalAlignment="Right"
                Margin="5,20,5,5"
                TextWrapping="Wrap"
                Text="{Binding Path=Resource.RequestDemoLoginText, Source={StaticResource LocalizedStrings }}"
                />
            <Button 
                x:Name="submitButton"
                Margin="5" 
                Height="Auto" 
                Width="Auto" 
                HorizontalAlignment="Right"
                HorizontalContentAlignment="Left"
                Content="{Binding Path=Resource.RequestDemoLogin, Source={StaticResource LocalizedStrings }}" />

Надеюсь, что это может помочь кому-то еще.

person R4cOOn    schedule 18.11.2009
comment
Хорошо, но его нужно использовать осторожно. Если вы привязываете целевой элемент к элементу более высокого уровня. Высота всегда больше, чем собственный элемент, вы получаете катастрофический сбой (исключение из HRESULT: 0x8000FFFF (E_UNEXPECTED)). С некоторыми проверками это работает хорошо. Благодарность - person Davut Gürbüz; 20.04.2012