Я знаю, как это сделать в коде, но можно ли это сделать в XAML?
Window1.xaml:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<ComboBox Name="ComboBox1" HorizontalAlignment="Left" VerticalAlignment="Top">
<ComboBoxItem>ComboBoxItem1</ComboBoxItem>
<ComboBoxItem>ComboBoxItem2</ComboBoxItem>
</ComboBox>
</Grid>
</Window>
Window1.xaml.cs:
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
double width = 0;
foreach (ComboBoxItem item in ComboBox1.Items)
{
item.Measure(new Size(
double.PositiveInfinity, double.PositiveInfinity));
if (item.DesiredSize.Width > width)
width = item.DesiredSize.Width;
}
ComboBox1.Measure(new Size(
double.PositiveInfinity, double.PositiveInfinity));
ComboBox1.Width = ComboBox1.DesiredSize.Width + width;
}
}
}
Ответы:
Это не может быть в XAML без:
Причина этого в том, что стандартные шаблоны элементов управления ComboBox, с которыми я сталкивался (Aero, Luna и т. Д.), Все вкладывают ItemsPresenter во всплывающее окно. Это означает, что макет этих элементов откладывается до тех пор, пока они не станут видимыми.
Простой способ проверить это - изменить ControlTemplate по умолчанию, чтобы привязать MinWidth самого внешнего контейнера (это Grid для Aero и Luna) к ActualWidth PART_Popup. Вы сможете настроить автоматическую синхронизацию ширины ComboBox при нажатии кнопки перетаскивания, но не раньше.
Поэтому, если вы не можете принудительно выполнить операцию измерения в системе макета (что можно сделать, добавив второй элемент управления), я не думаю, что это можно сделать.
Как всегда, я открыт для короткого, элегантного решения, но в этом случае хаки кода программной части или двойное управление / ControlTemplate - единственные решения, которые я видел.
источник
Вы не можете сделать это напрямую в Xaml, но можете использовать это Attached Behavior. (Ширина будет видна в Дизайнере)
Прикрепленное поведение ComboBoxWidthFromItemsProperty
Что он делает, так это то, что он вызывает метод расширения для ComboBox, называемый SetWidthFromItems, который (невидимо) расширяется и сворачивается, а затем вычисляет ширину на основе сгенерированных ComboBoxItems. (IExpandCollapseProvider требует ссылки на UIAutomationProvider.dll)
Затем метод расширения SetWidthFromItems
Этот метод расширения также обеспечивает возможность вызова
в коде позади (например, в событии ComboBox.Loaded)
источник
SetWidthFromItems
асинхронным, используя действие / делегат и BeginInvoke с приоритетом Idle (как это сделано в событии Loaded). Таким образом, никакие измерения не будут выполняться, пока насос сообщений не пуст, и, следовательно, не будет чередования сообщенийdouble comboBoxWidth = 19;
в вашем коде сSystemParameters.VerticalScrollBarWidth
?Да, это немного неприятно.
Раньше я добавлял в ControlTemplate скрытый список (с его itemscontainerpanel, установленным в сетку), показывающий все элементы одновременно, но с их скрытой видимостью.
Я был бы рад услышать о любых лучших идеях, которые не полагаются на ужасный код программной части или ваше представление, которое должно понимать, что ему необходимо использовать другой элемент управления, чтобы обеспечить ширину для поддержки визуальных эффектов (фу!).
источник
Основываясь на других ответах выше, вот моя версия:
HorizontalAlignment = "Left" останавливает элементы управления, используя всю ширину содержащего элемента управления. Высота = "0" скрывает элемент управления элементами.
Margin = "15,0" позволяет добавить дополнительный хром вокруг элементов поля со списком (боюсь, не зависит от хрома).
источник
В итоге я нашел «достаточно хорошее» решение этой проблемы: сделать так, чтобы поле со списком никогда не сжималось ниже максимального размера, который он имел, аналогично старому WinForms AutoSizeMode = GrowOnly.
Я сделал это с помощью специального преобразователя значений:
Затем я настраиваю поле со списком в XAML следующим образом:
Обратите внимание, что для этого вам понадобится отдельный экземпляр GrowConverter для каждого поля со списком, если, конечно, вы не хотите, чтобы их набор совпадал по размеру, аналогично функции SharedSizeScope Grid.
источник
Продолжение ответа Малеака: мне так понравилась эта реализация, я написал для нее настоящее поведение. Очевидно, вам понадобится Blend SDK, чтобы вы могли ссылаться на System.Windows.Interactivity.
XAML:
Код:
источник
provider.Expand()
бросаетElementNotEnabledException
. Когда ComboBox не включен из-за того, что родитель отключен, тогда невозможно даже временно включить ComboBox до завершения измерения.Поместите список, содержащий то же содержимое, за Dropbox. Затем установите правильную высоту с помощью такой привязки:
источник
В моем случае, казалось, более простой способ сработал, я просто использовал дополнительный stackPanel, чтобы обернуть поле со списком.
(работал в visual studio 2008)
источник
Альтернативным решением основного ответа является измерение самого всплывающего окна , а не измерения всех элементов. Даем немного более простую
SetWidthFromItems()
реализацию:работает и с инвалидами
ComboBox
.источник
Я сам искал ответ, когда наткнулся на
UpdateLayout()
метод, который каждыйUIElement
есть у .К счастью, теперь это очень просто!
Просто позвоните
ComboBox1.Updatelayout();
после того, как вы установите или изменитеItemSource
.источник
Подход Алуна Харфорда на практике:
источник
Это сохраняет ширину самого широкого элемента, но только после открытия поля со списком один раз.
источник