2013-02-25 48 views
1

顯示的控件的大小我做的一個工具欄類控制布點一些,並需要隱藏按鈕的文本時,沒有足夠的空間。我已經成功地在Windows Forms中完成了這個工作,現在我已經將這個邏輯移植到了WPF中。但是這裏存在一個巨大的問題:爲了讓我的算法正常工作,我需要知道容器控件的期望寬度(要知道如果一切都可見,將需要多大)以及控件的實際寬度(要知道如何寬度的確是這樣,並且是否有足夠的空間用於所需的寬度)。第一個是可用的,儘管有時候有點倒退。 (如果有更多的空間可用,DesiredSize會增加以填充所有內容,儘管更少可以。)後者完全不可用!找出真正的(!)在WPF

我試着ActualWidth的,但如果電網是比窗口寬,ActualWidth的超過實際上是可見的。所以這一定是錯誤的。然後我嘗試了RenderSize,但它是一樣的。在我的測量呼叫後使用排列會導致更多怪異。

我需要知道的控制真的有多寬,而不是有多寬就認爲自己是。我如何確定這個尺寸?

更新:好吧,這裏的一些代碼。這個問題已經很長了,而且還不完整。這是來自Window的代碼隱藏。

private void ToolGrid_LayoutUpdated(object sender, EventArgs e) 
{ 
    AutoCollapseItems(); 
} 

private void AutoCollapseItems() 
{ 
    if (collapsingItems) return; 
    if (ToolGrid.ActualWidth < 10) return; // Something is wrong 
    try 
    { 
     collapsingItems = true; 

     // Collapse toolbar items in their specified priority to save space until all items 
     // fit in the toolbar. When collapsing, the item's display style is reduced from 
     // image and text to image-only. This is only applied to items with a specified 
     // collapse priority. 

     Dictionary<ICollapsableToolbarItem, int> collapsePriorities = new Dictionary<ICollapsableToolbarItem, int>(); 

     // Restore the display style of all items that have a collpase priority. 
     var items = new List<ICollapsableToolbarItem>(); 
     EnumCollapsableItems(ToolGrid, items); 
     foreach (var item in items) 
     { 
      if (item.CollapsePriority > 0) 
      { 
       item.ContentVisibility = Visibility.Visible; 
       collapsePriorities[item] = item.CollapsePriority; 
      } 
     } 

     // Group all items by their descending collapse priority and set their display style 
     // to image-only as long as all items don't fit in the toolbar. 
     var itemGroups = from kvp in collapsePriorities 
         where kvp.Value > 0 
         group kvp by kvp.Value into g 
         orderby g.Key descending 
         select g; 
     foreach (var grp in itemGroups) 
     { 
      //ToolGrid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
      //ToolGrid.Arrange(new Rect(ToolGrid.DesiredSize)); 
      //ToolGrid.UpdateLayout(); 
      System.Diagnostics.Debug.WriteLine("Desired=" + ToolGrid.DesiredSize.Width + ", Actual=" + ToolGrid.ActualWidth); 
      if (ToolGrid.DesiredSize.Width <= ToolGrid.ActualWidth) break; 
      foreach (var kvp in grp) 
      { 
       kvp.Key.ContentVisibility = Visibility.Collapsed; 
      } 
     } 
     //ToolGrid.UpdateLayout(); 
    } 
    finally 
    { 
     collapsingItems = false; 
    } 
} 

更多的代碼:這裏的窗口XAML的一部分:

<Window> 
    <DockPanel> 
     <Grid Name="ToolGrid" DockPanel.Dock="Top" LayoutUpdated="ToolGrid_LayoutUpdated"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto"/> 
      </Grid.RowDefinitions> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="Auto"/> 
       <ColumnDefinition Width="Auto"/> 
       ... 
       <ColumnDefinition Width="*"/> 
      </Grid.ColumnDefinitions> 
     </Grid> 
+0

這是使用在安排/措施期間?或者你是否通過綁定來做這件事? – user7116 2013-02-25 19:47:15

+0

它在代碼隱藏中在LayoutUpdated事件(但不是遞歸)上調用。我也發現所需寬度總是小於實際寬度。如果沒有足夠的空間,則Desired是可見尺寸和實際需要的。如果有足夠的空間,則Desired是所需的大小和Actual可見。所以這兩個屬性的含義就轉過來了,我不知道哪個屬性是哪個。無用。 – ygoe 2013-02-25 19:57:12

+0

有些代碼會有幫助,你是繼承'UserControl'還是'Control'? – user7116 2013-02-25 19:58:14

回答

0

它原來,WPF不會給我一個包含所有在他們的按鈕元素自動調整大小列網格的尺寸可預見的。但是這個Grid的父元素,無論它是什麼以及如何佈置,都提供了有用的信息。所以我的解決方案基本上是在已經存在的網格容器和我的實際工具欄佈局網格之間插入另一個網格容器級別,並比較兩者的不同大小。中央測試,找出電網是否適合在給定的空間,現在是這樣的:

foreach (var grp in itemGroups) 
{ 
    InnerToolGrid.UpdateLayout(); 
    if (InnerToolGrid.RenderSize.Width - extentWidth <= ToolGrid.ActualWidth) break; 
    foreach (var kvp in grp) 
    { 
     kvp.Key.ContentVisibility = Visibility.Collapsed; 
    } 
} 

它通過可以收攏在一起的元素,以所有的優先級(徘徊無論它們位於電網)和崩潰迭代類(組)中的所有元素。然後更新內部網格的佈局以反映按鈕的變化,並將內部網格的RenderSize與外部網格的ActualWidth進行比較。如果它更小,則適合並且不需要摺疊更多項目。

所有這些都是從內部網格的LayoutUpdated事件調用的,仍然阻止通過鎖定變量遞歸。這允許我對工具欄上任何按鈕的大小更改作出反應,例如更新文本時。

由於LayoutCompleted事件似乎異步觸發,鎖變量必須保持設置,直到下一個佈局來看已經完成,而不能在LayoutUpdated處理程序結束時再次復位:

private bool collapsingItems; 
private void InnerToolGrid_LayoutUpdated(object sender, EventArgs e) 
{ 
    if (collapsingItems) return; 
    // Prevent further calls before the layouting is completely finished 
    collapsingItems = true; 
    Dispatcher.BeginInvoke(
     (Action) (() => { collapsingItems = false; }), 
     System.Windows.Threading.DispatcherPriority.Loaded); 
    // ... 
} 
1

從你使用的網格我的理解,但你設置列寬爲Auto,你怎麼樣使用*對的寬度你的Grid.Column不是Auto。如果自動,那麼網格拉伸其寬度和高度以適應其內容,因此爲什麼你的Grid.Width大於窗口寬度。當你使用*列不會關心內容,但它會一直在窗口邊界內。

現在實施後*,您使用column.width /高度,這是窗口邊界之內爲您的最終寬度/高度和網格內,你可以衡量你的嵌套的腸子控制的退漿大小。那就是你如何得到控件的最終尺寸和縮小尺寸。

顯示更多代碼/ xaml,我們將能夠幫助您。

編輯:

<Window> 
<DockPanel x:Name="dockyPanel> 
    <Grid Name="ToolGrid" DockPanel.Dock="Top" LayoutUpdated="ToolGrid_LayoutUpdated"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="Auto"/> 
      <ColumnDefinition Width="Auto"/> 
      ... 
      <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 
    </Grid> 


var itemGroups = from kvp in collapsePriorities 
        where kvp.Value > 0 
        group kvp by kvp.Value into g 
        orderby g.Key descending 
        select g; 
    double x = 0.0; 
    foreach (var grp in itemGroups) 
    { 
     // x will be increased by the sum of all widths of items 
     x += grp.SumOfAllWidthOfGroup; 

     // if x greater than available space then this group needs to collaps its items 
     if(x > this.dockyPanel.ActualWidth) 
     { 
      foreach (var kvp in grp) 
      { 
      kvp.Key.ContentVisibility = Visibility.Collapsed; 
      } 
     } 
    } 

這個怎麼樣?我的僞碼能幫助你嗎?

+0

網格使用自動寬度的列和行,正確。但它必須是這樣的,因爲工具欄項目之間不能有空格。自動是正確的設置,*導致錯誤的佈局。 – ygoe 2013-02-25 20:02:26

+0

好吧,你有一個根網格和一個網格工具欄項目。然後告訴你的根網格不關心內容。 – 2013-02-25 20:04:03

+0

在問題中添加了更多代碼。 「不關心內容」是什麼意思?沒有根網格,它是一個DockPanel。 – ygoe 2013-02-25 20:09:19