我正在使用一个组合框,它从How can I make a WPF combo box have the width of its widest element in XAML?
中附加行为答案(目前有46个赞成票)中描述的最宽元素获取宽度public static void SetWidthFromItems(this ComboBox comboBox)
{
double comboBoxWidth = 19;// comboBox.DesiredSize.Width;
// Create the peer and provider to expand the comboBox in code behind.
ComboBoxAutomationPeer peer = new ComboBoxAutomationPeer(comboBox);
IExpandCollapseProvider provider = (IExpandCollapseProvider)peer.GetPattern(PatternInterface.ExpandCollapse);
EventHandler eventHandler = null;
eventHandler = new EventHandler(delegate
{
if (comboBox.IsDropDownOpen &&
comboBox.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
double width = 0;
foreach (var item in comboBox.Items)
{
var container = comboBox.ItemContainerGenerator.ContainerFromItem(item);
if (container is ComboBoxItem)
{
var comboBoxItem = (ComboBoxItem) container;
comboBoxItem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
if (comboBoxItem.DesiredSize.Width > width)
{
width = comboBoxItem.DesiredSize.Width;
}
}
else
{
/* FIXME: coming here means that for some reason ComboBoxItems */
/* are not generated even if comboBox.ItemContainerGenerator.Status seems to be OK */
return;
}
}
comboBox.Width = comboBoxWidth + width;
// Remove the event handler.
comboBox.ItemContainerGenerator.StatusChanged -= eventHandler;
comboBox.DropDownOpened -= eventHandler;
provider.Collapse();
}
});
comboBox.ItemContainerGenerator.StatusChanged += eventHandler;
comboBox.DropDownOpened += eventHandler;
// Expand the comboBox to generate all its ComboBoxItem's.
provider.Expand();
}
但是,在win10中动态缩放文本大小时,解决方案不起作用。问题是即使条件
comboBox.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated
是真的,要求
comboBox.ItemContainerGenerator.ContainerFromItem(item);
从看似正常的项目返回null。
所以我的问题是:我应该如何更改正确计算宽度的代码?我问这个是因为我没有win10而且无法重现和玩耍。我得请一位同事测试一下。
我尝试删除行
comboBox.ItemContainerGenerator.StatusChanged -= eventHandler;
这导致在用鼠标点击窄组合框时测量正确的宽度。所以一个答案就是强迫StatusChanged事件以某种方式在某处提升。
答案 0 :(得分:0)
我想出了一个解决方案远非完美 只是一个工作轮。测量只需要进行一次,因为我准备好后不会向ComboBox添加项目。所以我记录了测量的ComboBoxes:
private static HashSet<string> _measuredWidthNamesSet = new HashSet<string>();
private static void OnComboBoxLoaded(object sender, RoutedEventArgs e)
{
ComboBox comboBox = sender as ComboBox;
if (!_measuredWidthNamesSet.Contains(comboBox.Name))
{
Action action = () => { comboBox.SetWidthFromItems(_measuredWidthNamesSet); };
comboBox.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
}
}
如果comboBox.ItemContainerGenerator.ContainerFromItem(item)返回null,我们不会显示宽度,也不会将ComboBox名称添加到测量的ComboBoxes集合中:
public static void SetWidthFromItems(this ComboBox comboBox, HashSet<string> measuredWidthNamesSet)
{
double comboBoxWidth = 19;// comboBox.DesiredSize.Width;
// Create the peer and provider to expand the comboBox in code behind.
ComboBoxAutomationPeer peer = new ComboBoxAutomationPeer(comboBox);
IExpandCollapseProvider provider = (IExpandCollapseProvider)peer.GetPattern(PatternInterface.ExpandCollapse);
EventHandler eventHandler = null;
eventHandler = new EventHandler(delegate
{
if (comboBox.IsDropDownOpen &&
comboBox.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
bool isSuccess = true;
double width = 0;
foreach (var item in comboBox.Items)
{
var container = comboBox.ItemContainerGenerator.ContainerFromItem(item);
if (container is ComboBoxItem)
{
var comboBoxItem = (ComboBoxItem) container;
comboBoxItem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
if (comboBoxItem.DesiredSize.Width > width)
{
width = comboBoxItem.DesiredSize.Width;
}
}
else
{
/* coming here means that for some reason ComboBoxItems are not generated even if
* comboBox.ItemContainerGenerator.Status seems to be OK */
isSuccess = false;
break;
}
}
if (isSuccess)
{
comboBox.Width = comboBoxWidth + width;
measuredWidthNamesSet.Add(comboBox.Name);
}
// Remove the event handler.
comboBox.ItemContainerGenerator.StatusChanged -= eventHandler;
comboBox.DropDownOpened -= eventHandler;
provider.Collapse();
}
});
comboBox.ItemContainerGenerator.StatusChanged += eventHandler;
comboBox.DropDownOpened += eventHandler;
// Expand the comboBox to generate all its ComboBoxItem's.
provider.Expand();
}