Создание шкалы Viewbox по вертикали, но растяжение по горизонтали
Я хочу создать Viewbox (или нечто подобное), которое масштабирует только его высоту, а затем растягивает его содержимое по горизонтали.
Если я это сделаю:
то я получаю это:
- Обнаружение ошибок проверки WPF
- Нет Main () в WPF?
- Force TextBlock для переноса в WPF ListBox
- Как связать команду в WPF с обработчиком события двойного щелчка элемента управления?
- WPF VirtualizingStackPanel для повышения производительности
http://sofru.miximages.com/wpf/viewbox-center.png
Он действует так, как будто обе кнопки имеют HorizontalAlignment = «Центр», а затем масштабирует результат. Но я не хочу, чтобы HorizontalAlignment = «Центр»; Я хочу HorizontalAlignment = “Stretch”, вот так:
http://sofru.miximages.com/wpf/viewbox-stretch.png
Поэтому я хочу, чтобы он считывал нужную высоту своего содержимого, вычислял коэффициент масштабирования, основанный только на высоте, а затем позволял масштабируемому контенту растягиваться горизонтально.
Есть ли способ сделать это с помощью windows «Просмотр» и / или сторонней панели?
- Один ViewModel для UserControl и Window или отдельные ViewModels
- Установите надстрочный индекс и индекс в форматированном тексте в wpf
- Как я могу уменьшить код привязки RadioButton?
- BitmapImage в WPF блокирует файл
- WPF TreeView: как стилизовать выбранные элементы с закругленными углами, как в Explorer
- ItemPropertyChanged не работает на наблюдаемомколлекции.Почему?
- Какова самая простая функция C # для синтаксического анализа строки JSON в объект?
- Замена точки входа WPF
Нет такого контроля с WPF, но вы можете написать его самостоятельно без особых проблем. Вот пользовательский ViewboxPanel, который имеет ваши характеристики:
public class ViewboxPanel : Panel { private double scale; protected override Size MeasureOverride(Size availableSize) { double height = 0; Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity); foreach (UIElement child in Children) { child.Measure(unlimitedSize); height += child.DesiredSize.Height; } scale = availableSize.Height / height; return availableSize; } protected override Size ArrangeOverride(Size finalSize) { Transform scaleTransform = new ScaleTransform(scale, scale); double height = 0; foreach (UIElement child in Children) { child.RenderTransform = scaleTransform; child.Arrange(new Rect(new Point(0, scale * height), new Size(finalSize.Width / scale, child.DesiredSize.Height))); height += child.DesiredSize.Height; } return finalSize; } }
и вы используете его вот так:
Это определенно нуждается в некоторой работе, но это может заставить вас начать.
Для правильной работы ширины:
protected override Size MeasureOverride(Size availableSize) { double height = 0; Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity); foreach (UIElement child in Children) { child.Measure(unlimitedSize); height += child.DesiredSize.Height; } scale = availableSize.Height / height; foreach (UIElement child in Children) { unlimitedSize.Width = availableSize.Width / scale; child.Measure(unlimitedSize); } return availableSize; }
Я уверен, что ответ «нелегко».
Вот идея, которая, похоже, работает, но это неловко:
-
Бросьте свой StackPanel в UserControl (
UserControl1
в примере ниже). -
Поместите две копии этого UserControl в контейнер (grid в примере ниже).
а. Выровняйте первую верхнюю / верхнюю копию, чтобы она оставалась по умолчанию. Эта копия предназначена исключительно для целей измерения и должна иметь значение «Видимость» для «Скрыто».
б. Поместите вторую копию в поле «Просмотр». Эта копия является той, которую пользователь действительно увидит.
-
Используйте MultiBinding с MultiValueConverter, чтобы настроить ширину второго UserControl так, чтобы он имел правильное соотношение сторон, прежде чем он будет расширяться в Viewbox.
Вот разметка:
Вот MultiValueConverter
public class WidthAdjuster : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { var rawHeight = (double)values[0]; var containerWidth = (double)values[1]; var containerHeight = (double)values[2]; var ratio = containerWidth / containerHeight; return rawHeight * ratio; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
Результат для контейнера 525 x 350
У меня была почти такая же проблема. Моя панель должна была приспосабливать всех своих детей, помещая их в ряд и растягивая их, равномерно заполняя панель. Алгоритм выше использует преобразование рендеринга для элементов шкалы. Проблема заключается в том, что преобразование рендеринга растягивает самих детей, но игнорирует маржу. Если маржа высока, а масштабный коэффициент ниже 1, элементы выпадают из панели. Вы должны скорректировать масштаб для RenderTransform в соответствии с маржой на этой оси и использовать тот же масштабный коэффициент для организации. MeasureOverride, который я использовал, был
protected override Size MeasureOverride(Size availableSize) { double width = 0; double maxHeight = 0; double mY=0; double mX=0; Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity); foreach (UIElement child in Children) { child.Measure(unlimitedSize); width += child.DesiredSize.Width; maxHeight = Math.Max(maxHeight, child.DesiredSize.Height); FrameworkElement cld = child as FrameworkElement; mY = cld.Margin.Top + cld.Margin.Bottom; mX = cld.Margin.Left + cld.Margin.Right; } double scaleX = availableSize.Width / width; double scaleY = availableSize.Height / maxHeight; //That is scale for arranging positionScaling = Math.Min(scaleX, scaleY); try { // Let FrameworkElement hight be Xn. mY = Element.Margin.Top + Element.Margin.bottom. // DesiredSize includes margin therefore: // (Yn + mY) * scaleY = availableSize.Height // But render transform doesn't scales margin. Actual render height with margin will be // Yn * RenderScaleY + mY = availableSize.Height; // We must find render transform scale coeff like this: double yn = availableSize.Height / scaleY - mY; scaleY = (availableSize.Height - mY) / yn; double xn = availableSize.Width / scaleX - mX; scaleX = (availableSize.Width - mX) / xn; scale = Math.Min(scaleX, scaleY); //scale to use in RenderTransform // In my project all children are similar in size and margin, algorithm BREAKS otherwise!!! } catch { scale = 1; } return availableSize; }
Еще раз: в моем проекте все дети похожи по размеру и маржи, алгоритм BREAKS в противном случае.