Изменение размера окна и привязки ведут себя не так, как ожидалось

У меня есть приложение wpf, использующее подход mvvm. Главное окно содержит элемент управления вкладками.

Каждый элемент в элементе управления вкладками имеет свою собственную модель представления, и каждый элемент вкладки содержит панель переноса. Я создал прикрепленное свойство, чтобы позволить мне привязываться к свойствам ActualHeight и ActualWidth панели. (Я не использовал свойства высоты/ширины, так как мне нужна панель, чтобы заполнить доступное пространство.)

При изменении размера окна размер панели на активной вкладке изменяется, однако все панели на других вкладках не обновляются. При просмотре привязок уведомляется только об одном изменении.

Это ожидаемое поведение при использовании WPF? Если нет, что не так с моим подходом, или если да, то есть ли способ принудительно обновить все вкладки?


person seanzi    schedule 14.11.2011    source источник


Ответы (1)


Каждый TabItem звучит так, как будто он рисуется отдельно. Обычно WPF выгружает невидимые элементы TabItem, поэтому в момент изменения размера окна существует только одна панель WrapPanel. Когда вы повторно загружаете TabItem, переключая вкладки, если что-то не привязано (например, ActualHeight), оно перезагрузится до исходных значений, определенных в вашем XAML.

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

Конвертер, который я обычно использую, приведен ниже. Я создал это, когда впервые начал работать с WPF, и я не знал, что в то время существовали MultiConverters. Я уверен, что его можно было бы переписать, чтобы сделать его мультиконвертерным, однако я еще не удосужился сделать это.

Чтобы использовать его, добавьте свой конвертер в свои ресурсы

<local:PercentOfParentConverter x:Key="PanelHeightConverter" />
<local:PercentOfParentConverter x:Key="PanelWidthConverter" />

Установите свои привязки на основе конвертера

<Setter Property="Height" Value="{Binding Path=PanelHeight, 
            Converter={StaticResource PanelHeightConverter}}" />
<Setter Property="Width" Value="{Binding Path=PanelWidth, 
            Converter={StaticResource PanelWidthConverter}}" />

И в Code-Behind обязательно подключитесь к событию SizeChanged, чтобы обновлять ParentSize преобразователя при каждом изменении размера.

// If workarea size changes, reposition/resize panels within it to keep the same layout
private void PanelSizeChanged(object sender, SizeChangedEventArgs e)
{
    Panel c = sender as Panel;
    if (c != null)
    {
        // Set the parent's height/width on the converter
        PercentOfParentConverter sizeConverter = (PercentOfParentConverter)c.FindResource("PanelHeightConverter");
        if (sizeConverter != null) sizeConverter.ParentSize = c.ActualHeight;

        sizeConverter = (PercentOfParentConverter)c.FindResource("PanelWidthConverter");
        if (sizeConverter != null) sizeConverter.ParentSize = c.ActualWidth;

        foreach (UIElement child in c.Children)
        {
            RebindPanelSizeAndPosition(child);
        }
    }
}

// Refreshes the Panel.Height/Width bindings of the UIElement passed to it
private void RebindPanelSizeAndPosition(UIElement element)
{
    BindingOperations.GetBindingExpressionBase(element, Panel.HeightProperty).UpdateTarget();
    BindingOperations.GetBindingExpressionBase(element, Panel.WidthProperty).UpdateTarget();
}

Фактический код конвертера выглядит так:

// Converts a percent to a double value based on the parent size set
public class PercentOfParentConverter : IValueConverter
{
    public double ParentSize { get; set; }

    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var percent = (double) value;
        return percent*ParentSize;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (ParentSize != 0)
        {
            return (double) value/ParentSize;
        }
        else
        {
            return 0;
        }
    }

    #endregion
}
person Rachel    schedule 14.11.2011