2017-08-17 1 views
1

Ich verwende eine Combobox, die es Breite von breitesten Elemente beschrieben in fester Händen Verhalten Antwort (derzeit 46 upvotes) in How can I make a WPF combo box have the width of its widest element in XAML?Wie behandelt man falsch ComboBox.ItemContainerGenerator.Status in EventHandler?

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(); 
} 

wird jedoch die Lösung funktioniert nicht, wenn im laufenden Betrieb in win10 Textgröße zu skalieren. Das Problem ist, dass, obwohl die Bedingung

comboBox.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated 

wahr ist, der Ruf nach

comboBox.ItemContainerGenerator.ContainerFromItem(item); 

kehrt null aus scheinbar ok Element.

Also meine Frage ist: Wie soll ich den Code ändern, dass die Breite korrekt berechnet wird? Ich frage das, weil ich win10 nicht habe und nicht reproduzieren und herumspielen kann. Ich muss einen Kollegen bitten, es zu testen.

Ich versuchte, Linie entfernen

comboBox.ItemContainerGenerator.StatusChanged -= eventHandler; 

dies in der richtigen Breite geführt gemessen wird, wenn die schmale Combobox mit der Maus geklickt wurde. Eine Antwort wäre also, das Ereignis "StatusChanged" irgendwo zu erzwingen. Seine nur ein worka rund

Antwort

0

kam ich mit einer Lösung, die bei weitem nicht perfekt ist. Die Messung muss nur einmal durchgeführt werden, da ich keine Elemente zur ComboBox hinzufüge, nachdem sie fertig sind. So halte ich Aufzeichnung gemessen Comboboxen:

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); 
     } 
    } 

Wenn comboBox.ItemContainerGenerator.ContainerFromItem (Punkt) gibt null wir nicht die Breite se und fügen Sie nicht die ComboBox Namen Satz gemessener Comboboxen:

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(); 
    } 
Verwandte Themen