2016-11-13 59 views
0

在UWP項目的固定數量的佈局問題,我有一個綁定到PersonObservableCollection<T>對象ListView。我使用DataTemplateListView內顯示Person對象。收藏(人物)最多隻能包含由_maxPeopleCount設置的特定人數。試圖讓ListView控件顯示項目

我想發生這樣對於ListView到:

  1. 一點也不滾動。
  2. 顯示由_maxPeopleCount作爲定義的所有Person對象。
  3. 完全顯示每個Person對象,而不是部分顯示。也就是說,顯示每個項目,以便ListViewItem.Height =(可從ItemsPanel得到的高度)/ _maxPeopleCount
  4. 當存在小於_maxPeopleCount項開始仍然顯示如(3)中定義的有高度的添加的條目。
  5. 顯示每個人的名字和姓氏儘可能大。

目前,我不能讓我的項目做到這一點。

任何人都可以在這方面幫助,請或建議另一種方法?

下面是示例代碼顯示的問題。只需按下按鈕7次以上,因爲這是代碼中的_maxPeopleCount。你會看到7個人沒有看到。對可怕的用戶界面抱歉。它使用最小的XAML顯示問題,但與我的真實項目類似。

許多在此先感謝您的幫助。

後面的代碼:

public sealed partial class MainPage : Page 
{ 
    ObservableCollection<Person> _people = new ObservableCollection<Person>(); 
    int _personCount = 0; 
    int _maxPeopleCount = 7; 
    public MainPage() 
    { 
     this.InitializeComponent(); 
     this.DataContext = _people; 

    } 

    private void btnAddPerson_Click(object sender, RoutedEventArgs e) 
    { 
     if (_people.Count == _maxPeopleCount) 
     { 
      _people.RemoveAt(_people.Count - 1); 
     } 
     _personCount += 1; 
     _people.Insert(0, new Person($"FirstName {_personCount}", $"LastName {_personCount}")); 
    } 

XAML:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="*"/> 
    </Grid.ColumnDefinitions> 

    <Grid.RowDefinitions> 
     <RowDefinition Height="*"/> 
     <RowDefinition Height="*"/> 
    </Grid.RowDefinitions> 

    <Button Grid.Row="0" Grid.Column="0" x:Name="btnAddPerson" Click="btnAddPerson_Click" Content="Add Person" VerticalAlignment="Center" HorizontalAlignment="Center"/> 

    <ListView BorderBrush="Black" BorderThickness="5" Margin="10" Grid.Row="1" Grid.Column="0" ItemsSource="{Binding}" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollMode="Disabled" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"> 
     <ListView.ItemContainerStyle> 
      <Style TargetType="ListViewItem"> 
       <Setter Property="HorizontalContentAlignment" Value="Stretch"/> 
      </Style> 
     </ListView.ItemContainerStyle> 
     <ListView.ItemsPanel> 
      <ItemsPanelTemplate> 
       <ItemsStackPanel HorizontalAlignment="Stretch"/> 
      </ItemsPanelTemplate> 
     </ListView.ItemsPanel> 
     <ListView.ItemTemplate> 
      <DataTemplate> 
       <Grid x:Name="grdPerson"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
        </Grid.ColumnDefinitions> 
        <Border Grid.Column="0" Background="Green" HorizontalAlignment="Stretch"> 
         <Viewbox> 
          <TextBlock Text="{Binding FirstName}" HorizontalAlignment="Stretch"/> 
         </Viewbox> 
        </Border> 
        <Border Grid.Column="1" Background="Yellow" HorizontalAlignment="Stretch"> 
         <Viewbox> 
          <TextBlock Text="{Binding LastName}" HorizontalAlignment="Stretch" /> 
         </Viewbox> 
        </Border> 
       </Grid> 
      </DataTemplate> 
     </ListView.ItemTemplate> 
    </ListView> 
</Grid> 

Person類:

public class Person : INotifyPropertyChanged 
{ 

    public Person(string firstName, string lastName) 
    { 
     FirstName = firstName; 
     LastName = lastName; 
    } 


    private string _firstName = string.Empty; 
    public string FirstName 
    { 
     get { return _firstName; } 
     set 
     { 
      _firstName = value; 
      OnPropertyChanged(); 
     } 
    } 


    private string _lastName = string.Empty; 
    public string LastName 
    { 
     get { return _lastName; } 
     set 
     { 
      _lastName = value; 
      OnPropertyChanged(); 
     } 
    } 

    protected void OnPropertyChanged([CallerMemberName] string caller = "") 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 


} 
+0

你需要的ListViewItems可以進行選擇?你需要處理ItemClick事件嗎? –

+0

@DecadeMoon,不需要ListViewItems是可選的,我不需要處理ItemClick事件。 ListView純粹是隻讀的。 – Cleve

回答

0

好吧,我想我已經破解了!我將ItemsPanelTemplate更改爲UniformGrid面板,我從here獲得。它是一個WPF版本的UWP版本,因此您可以設置行數和列數。對於我的例子以上,行= 7,列= 1

所有我改變之後是添加下列附加SetterItemContainerStyle

<Setter Property="VerticalContentAlignment" Value="Stretch"/> 

其固定在ListViewItems內容的問題沒有被最大化。

希望這可以幫助別人,併爲那些在幫助下回復的人歡呼。

+0

只有這個,我在我的答覆中也提到過你的要求,你不能保證你的第三個要求,你可以根據我的答案進行測試。 –

+0

@ Sunteen-MSFT,使用UniformGrid確實給了我第三個要求。 – Cleve

1

不滾動的。

對此,您已通過ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden"完成。

顯示所有由_maxPeopleCount定義的Person對象。

其實你已經綁定_maxPeopleCount人員記錄到ListView,但僅限由窗口的大小,你不能看到他們。無形記錄確實存在於那裏。如果你伸展應用程序窗口的大小,讓高度是通過手動拖動你會看到剩餘的記錄大。如果你想保留的所有記錄始終顯示可見你可能需要自己計算ListViewItem高度。

顯示每個人充分的對象,而不是部分。也就是說,顯示每個項目,以便ListViewItem.Height =(從ItemsPanel可用的高度)/ _maxPeopleCount。

在您的場景中,ListViewItem的高度會自動計算,因爲您沒有爲其設置修復高度。按照您在這裏展示的公式,我們可以在後面的代碼中動態綁定ListViewItem,ViewTreeHelper類的高度。請注意窗口大小的變化會影響ListView的實際大小,所以當應用窗口大小發生變化時,我們還需要調整ListViewItem的大小。當ListViewItem的高度設置爲小於44時,它將不起作用,因爲ListViewItem styles and templates的默認MinHeight44,需要重置。更多實施此要求的設置請參考下面的演示。

當存在小於_maxPeopleCount項開始仍然顯示如(3)中定義的有高度的添加的條目。

經過計算後,所有的ListViewItem都會有相同的高度。

顯示每個人的名字和姓氏儘可能大。

爲此,您有<Setter Property="HorizontalContentAlignment" Value="Stretch"/>來拉伸水平內容,也請拉伸垂直內容<Setter Property="VerticalContentAlignment" Value="Stretch"/>ListviewItempadding需要設置爲0

更新的代碼如下,可以滿足您的所有上述要求。

XAML

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" x:Name="gridroot"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="*"/> 
    </Grid.ColumnDefinitions> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*"/> 
     <RowDefinition Height="*"/> 
    </Grid.RowDefinitions> 
    <Button Grid.Row="0" Grid.Column="0" x:Name="btnAddPerson" Click="btnAddPerson_Click" Content="Add Person" VerticalAlignment="Center" HorizontalAlignment="Center"/> 
    <ListView x:Name="listperson" BorderBrush="Black" BorderThickness="5" Margin="10" Grid.Row="1" Grid.Column="0" ItemsSource="{Binding}" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollMode="Disabled" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"> 
     <ListView.ItemContainerStyle> 
      <Style TargetType="ListViewItem"> 
       <Setter Property="HorizontalContentAlignment" Value="Stretch"/> 
       <Setter Property="VerticalContentAlignment" Value="Stretch"/> 
       <Setter Property="MinHeight" Value="20"/> 
       <Setter Property="Padding" Value="0"/> 
      </Style> 
     </ListView.ItemContainerStyle> 
     <ListView.ItemsPanel> 
      <ItemsPanelTemplate> 
       <ItemsStackPanel HorizontalAlignment="Stretch"/> 
      </ItemsPanelTemplate> 
     </ListView.ItemsPanel> 
     <ListView.ItemTemplate> 
      <DataTemplate> 
       <Grid x:Name="grdPerson" Loaded="grdPerson_Loaded" > 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
        </Grid.ColumnDefinitions> 
        <Border Grid.Column="0" Background="Green" HorizontalAlignment="Stretch" > 
         <Viewbox> 
          <TextBlock Text="{Binding FirstName}" HorizontalAlignment="Stretch" /> 
         </Viewbox> 
        </Border> 
        <Border Grid.Column="1" Background="Yellow" HorizontalAlignment="Stretch"> 
         <Viewbox> 
          <TextBlock Text="{Binding LastName}" HorizontalAlignment="Stretch" /> 
         </Viewbox> 
        </Border> 
       </Grid> 
      </DataTemplate> 
     </ListView.ItemTemplate> 
    </ListView> 
</Grid> 

背後

代碼
public sealed partial class MainPage : Page 
{ 
    ObservableCollection<Person> _people = new ObservableCollection<Person>(); 
    int _personCount = 0; 
    int _maxPeopleCount = 7; 
    public MainPage() 
    { 
     this.InitializeComponent(); 
     this.DataContext = _people; 
     Window.Current.SizeChanged += Current_SizeChanged; 
    } 
    public void resize() 
    { 
     var listpersonheight = listperson.ActualHeight; 
     IEnumerable<ListViewItem> items = FindVisualChildren<ListViewItem>(listperson); 
     for (int i = 0; i < items.Count(); i++) 
     { 
      foreach (ListViewItem item in items) 
      { 
       item.Height = (listpersonheight - 10)/_maxPeopleCount;// BorderThickness size need to be minus. 
       item.Width = listperson.ActualWidth - 10; //Width also need resize. 
      } 
     } 
    } 
    private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e) 
    { 
     resize(); 
    } 
    private void grdPerson_Loaded(object sender, RoutedEventArgs e) 
    { 
     resize(); 
    } 
    private void btnAddPerson_Click(object sender, RoutedEventArgs e) 
    { 
     if (_people.Count == _maxPeopleCount) 
     { 
      _people.RemoveAt(_people.Count - 1); 
     } 
     _personCount += 1; 
     _people.Insert(0, new Person($"FirstName {_personCount}", $"LastName {_personCount}")); 
    } 

    private static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj != null) 
     { 
      for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
      { 
       DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
       if (child != null && child is T) 
       { 
        yield return (T)child; 
       } 

       foreach (T childOfChild in FindVisualChildren<T>(child)) 
       { 
        yield return childOfChild; 
       } 
      } 
     } 
    } 
} 
+0

嗨,謝謝您的回覆。與此同時,我發現了一個可供選擇的解決方案,可以在下面發佈。 – Cleve

1

你可以隨時編寫自己的面板,這很容易做到。這是一個我寫的UniformStackPanel,它像StackPanel一樣工作,除了它將伸展每個項目以填充可用空間(不管它有多少項)。

public class UniformStackPanel : StackPanel 
{ 
    protected override Size MeasureOverride(Size availableSize) 
    { 
     var childSize = Orientation == Orientation.Horizontal ? 
      new Size(availableSize.Width/Children.Count, availableSize.Height) : 
      new Size(availableSize.Width, availableSize.Height/Children.Count); 

     double alongAxis = 0; 
     double crossAxis = 0; 

     foreach (var child in Children) 
     { 
      child.Measure(childSize); 

      if (Orientation == Orientation.Horizontal) 
      { 
       alongAxis += child.DesiredSize.Width; 
       crossAxis = Math.Max(crossAxis, child.DesiredSize.Height); 
      } 
      else 
      { 
       alongAxis += child.DesiredSize.Height; 
       crossAxis = Math.Max(crossAxis, child.DesiredSize.Width); 
      } 
     } 

     return Orientation == Orientation.Horizontal ? 
      new Size(alongAxis, crossAxis) : 
      new Size(crossAxis, alongAxis); 
    } 

    protected override Size ArrangeOverride(Size finalSize) 
    { 
     var childSize = Orientation == Orientation.Horizontal ? 
      new Size(finalSize.Width/Children.Count, finalSize.Height) : 
      new Size(finalSize.Width, finalSize.Height/Children.Count); 

     double alongAxis = 0; 

     foreach (var child in Children) 
     { 
      if (Orientation == Orientation.Horizontal) 
      { 
       child.Arrange(new Rect(alongAxis, 0, childSize.Width, childSize.Height)); 
       alongAxis += childSize.Width; 
      } 
      else 
      { 
       child.Arrange(new Rect(0, alongAxis, childSize.Width, childSize.Height)); 
       alongAxis += childSize.Height; 
      } 
     } 

     return finalSize; 
    } 
} 

有這樣一個ItemsControl使用它:

<ItemsControl BorderBrush="Black" BorderThickness="5" Margin="10" Grid.Row="1" ItemsSource="{Binding}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <local:UniformStackPanel/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition/> 
        <ColumnDefinition/> 
       </Grid.ColumnDefinitions> 
       <Border Grid.Column="0" Background="RoyalBlue" HorizontalAlignment="Stretch"> 
        <Viewbox> 
         <TextBlock Text="{Binding FirstName}"/> 
        </Viewbox> 
       </Border> 
       <Border Grid.Column="1" Background="Crimson" HorizontalAlignment="Stretch"> 
        <Viewbox> 
         <TextBlock Text="{Binding LastName}"/> 
        </Viewbox> 
       </Border> 
      </Grid> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

Screenshot

+0

嗨@Decade Moon,感謝您的建議。我最終以類似的思路思考,但使用了UniformGrid面板。看我的回答帖子。感謝幫助。 – Cleve