2009-08-13 7 views
21

Tôi đang cố viết một dự án học tập WPF đơn giản, tạo ra một bộ nút bên trong cửa sổ chính có thể định lại. Có một số Button cho mỗi mục nhập trong bộ sưu tập và nội dung của bộ sưu tập đó có thể thay đổi trong thời gian chạy. Tôi muốn các nút để lấp đầy toàn bộ cửa sổ (ví dụ: 1 nút @ 100% chiều rộng, 2 nút @ 50% chiều rộng, 3 nút @ 33% chiều rộng, v.v ... ở độ cao 100%). Một phiên bản đơn giản của những gì tôi đã viết cho đến nay là:Điều khiển kéo dài để điền vào ItemsControl

<ItemsControl x:Name="itemscontrolButtons" ItemsSource="{Binding}"> 
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <Button Tag="{Binding}"> 
     <TextBlock Text="{Binding}" /> 
     </Button> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
    <ItemsControl.ItemsPanel> 
    <ItemsPanelTemplate> 
     <StackPanel Orientation="Horizontal" /> 
    </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 
...  
List<string> listButtonTexts = new List<string>() { "Button1", "Button2" }; 
... 
itemscontrolButtons.DataContext = listButtonTexts; 

Điều này dẫn đến điều này:

alt text

tôi đã không thể làm cho các nút căng để phù hợp với chiều rộng và nỗ lực của tôi để sử dụng Grid thay vì StackPanel là không kết quả. Sau đó, như là một cải tiến tùy chọn, tôi sẽ đánh giá cao các đề xuất về cách điều chỉnh sao cho nếu có quá nhiều nút mà chúng không thể vừa với một đường thẳng hoặc hẹp hơn ngưỡng, nó sẽ quấn lên một dòng mới (do đó giảm một nửa chiều cao của nút nếu đi từ 1 đến 2 hàng).

Tôi muốn nhấn mạnh rằng tôi muốn biết cách thực hiện điều này theo cách WPF. Tôi nhận ra tôi có thể tiêu thụ các thông báo thay đổi kích thước cửa sổ và thay đổi kích thước các điều khiển một cách rõ ràng, và đó là cách tôi đã làm nó với MFC hoặc WinForms, nhưng từ những gì tôi đã đọc đó không phải là những điều như vậy nên được thực hiện với WPF.

Trả lời

48

Thay thế bảng điều khiển mục với một UniformGrid, ý chí kích thước này tất cả trẻ em để mọi thứ phù hợp chính xác:

<ItemsControl> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <UniformGrid Rows="1"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 
+0

Đó chỉ là những gì tôi cần cho mục tiêu chính của tôi, cảm ơn bạn. – Gregyski

+0

Nhờ câu trả lời của Nir, tôi đã có thể đáp ứng các tiêu chí tùy chọn. Chi tiết nằm trong câu trả lời tôi đã đăng cho câu hỏi này. Nó được đề nghị trên Meta mà tôi xử lý tình huống này theo cách này. http://meta.stackexchange.com/questions/14306/my-improved-answer-based-on-anothers-accepted-answer-for-my-own-question – Gregyski

+0

Cảm ơn! Đây chỉ là những gì tôi đã mất tích cho khoảng cách các mục và bảng điều khiển của họ đồng đều trong một ListBox. –

0
<!-- width must be explicitly set for this example --> 
<StackPanel 
    Name="MyStack" 
    Orientation="Horizontal" 
    Width="250" 
    Load="Window_Loaded"> 
    <Button/> 
    <Button/> 
    <Button/> 
</StackPanel> 

public void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    UIElementCollection elements = MyStack.Children; 
    int count = elements.Count; 

    foreach (UIElement element in elements) 
    { 
     if (element is Button) 
      ((Button)element).Width = MyStack.Width/count; 
    } 
} 
+0

Tôi đã chỉnh sửa bài đăng của mình chỉ 20 phút trước khi bạn trả lời giải thích rằng tôi muốn tránh đặt độ rộng một cách rõ ràng. Tôi xin lỗi tôi nên nghĩ đến việc đưa yêu cầu đó ban đầu. Quản lý rõ ràng các kích thước như thế này (và bằng cách xử lý các thông báo thay đổi kích thước) có thể cần thiết cho yêu cầu thứ cấp của tôi, nếu WrapPanel được sử dụng. Cảm ơn. – Gregyski

2

tôi đã có thể xây dựng trên câu trả lời Nir để thực hiện đầy đủ của tôi tiêu chí tùy chọn cho phép WPF quản lý kéo dài với nhiều hàng.

Trước tiên, bạn phải có khả năng thay đổi các thuộc tính của mẫu UniformGrid. Để làm điều đó bạn cần lưu trữ một tham chiếu đến nó. Có multiple methods for accomplishing this. Tôi đã chọn xử lý sự kiện được tải cho UniformGrid và lưu trữ tham chiếu tại thời điểm đó.

<ItemsControl ItemsSource="{Binding}"> 
    <ItemsControl.ItemsPanel> 
    <ItemsPanelTemplate> 
     <UniformGrid Rows="1" Loaded="UniformGrid_Loaded" /> 
    </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 

Và trong các mã sau:

UniformGrid uniformgridButtons; 
private void UniformGrid_Loaded(object sender, RoutedEventArgs e) 
{ 
    uniformgridButtons = sender as UniformGrid; 
} 

Sau đó, xử lý các SizeChanged kiện và điều chỉnh các thông số hàng bằng đường thư theo tiêu chí mà bạn muốn.

private void Window_SizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    if ((uniformgridButtons != null) && (this.Width > 0)) 
    { 
    // Set row count according to your requirements 
    uniformgridButtons.Rows = (int)(1 + ((this.MinWidth * iButtonCount)/this.Width)); 
    } 
} 

Vì vậy, điều này cho phép WPF quản lý việc kéo giãn như trong câu trả lời của Nir, nhưng cho phép bạn điều chỉnh một cách rõ ràng số hàng.Đoạn mã trên cho kết quả này:

alt text

(Animated mẫu here)


Cập nhật 2009/08/28:

tôi đã điều chỉnh ứng dụng học tập của tôi để các ItemsControl đã ở trong một DataTemplate trong một riêng biệt ResourceDictionary. Tuy nhiên, các sự kiện như Loaded không thể được xử lý trong tệp XAML bên ngoài ResourceDictionary vì nó không có mã (thường). Do đó, tôi cần lưu vào bộ nhớ cache tham chiếu đến UniformGrid bằng cách sử dụng một kỹ thuật khác.

Tôi thay vì sử dụng Alan Haigh's FindItemsPanel method (10th reply). Trước tiên, tôi thay thế ItemsControl với:

<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" /> 

Sau đó, trong ResourceDictionary của tôi, tôi đặt ItemsControl trong DataTemplate:

<DataTemplate DataType="{x:Type local:Buttons}"> 
    <ItemsControl ... 
</DataTemplate> 

Cuối cùng, tôi lưu trữ các tài liệu tham khảo cho templated UniformGrid như vậy:

private void Window_Loaded(object sender, RoutedEventArgs e) { 
    uniformgridButtons = FindItemsPanel<UniformGrid>(contentpresenterButtons); 
    // Also call the code in Window_SizeChanged which I put in another method 
} 

Điều này hoạt động giống như giải pháp trước đây của tôi nhưng không yêu cầu trình xử lý sự kiện trong ResourceDictionary.