我想将元素添加到 StackPanel(或 Listbox / Listview,如果它可以更容易的话)并自动添加一个 Button(如“...”)以指示有更多的孩子而不是空间。考虑一个每天都有约会项目的日历。如果约会的数量超过了可以显示的数量,则会显示一个按钮以转到当天的详细视图。
这可以自动完成,或者我如何计算堆栈面板及其项目的位置。
它用于 c# 中的 windows 商店开发。
我想将元素添加到 StackPanel(或 Listbox / Listview,如果它可以更容易的话)并自动添加一个 Button(如“...”)以指示有更多的孩子而不是空间。考虑一个每天都有约会项目的日历。如果约会的数量超过了可以显示的数量,则会显示一个按钮以转到当天的详细视图。
这可以自动完成,或者我如何计算堆栈面板及其项目的位置。
它用于 c# 中的 windows 商店开发。
您可以使用行为(System.Windows.Interactivity
需要参考)。
我抓住了你的想法来计算堆栈面板及其子项的高度(或宽度,如果堆栈面板具有水平方向),并在必要时显示“更多项目”/详细信息按钮
public class ChildSpaceBehavior : Behavior<StackPanel>
{
public static readonly DependencyProperty ShowDetailsCommandProperty = DependencyProperty.Register("ShowDetailsCommand", typeof(RelayCommand), typeof(ChildSpaceBehavior), new PropertyMetadata());
public RelayCommand ShowDetailsCommand
{
get { return (RelayCommand)GetValue(ShowDetailsCommandProperty); }
set { SetValue(ShowDetailsCommandProperty, value); }
}
private bool _isMoreChildrenItemVisible;
protected override void OnAttached()
{
AssociatedObject.LayoutUpdated += OnLayoutUpdated;
}
protected override void OnDetaching()
{
AssociatedObject.LayoutUpdated -= OnLayoutUpdated;
}
private void OnLayoutUpdated(object sender, EventArgs e)
{
var height = AssociatedObject.Height;
var children = AssociatedObject.Children;
double childHeighSum = 0;
var childList = new List<FrameworkElement>();
foreach (FrameworkElement child in children)
{
if (childHeighSum > height)
{
ShowMoreChildrenItem(childList);
break;
}
if (childHeighSum + child.ActualHeight > height)
{
ShowMoreChildrenItem(childList);
break;
}
childHeighSum += child.ActualHeight;
childList.Add(child);
}
}
private void ShowMoreChildrenItem(List<FrameworkElement> childList)
{
if (_isMoreChildrenItemVisible) return;
var moreItem = new Button{ Content = "..." };
moreItem.Command = ShowDetailsCommand;
var itemsToRemove = new List<FrameworkElement>();
foreach (FrameworkElement child in AssociatedObject.Children)
{
if(childList.Contains(child) == false) itemsToRemove.Add(child);
}
foreach (var element in itemsToRemove)
{
AssociatedObject.Children.Remove(element);
}
AssociatedObject.Children.Add(moreItem);
_isMoreChildrenItemVisible = true;
}
}
对于 RelayCommand 看这里
xml:
<Grid>
<StackPanel Height="200" Orientation="Vertical">
<Border BorderBrush="Gray" BorderThickness="1">
<Label Height="50" Content="Item 1" />
</Border>
<Border BorderBrush="Gray" BorderThickness="1">
<Label Height="50" Content="Item 2" />
</Border>
<Border BorderBrush="Gray" BorderThickness="1">
<Label Height="50" Content="Item 3" />
</Border>
<Border BorderBrush="Gray" BorderThickness="1">
<Label Height="50" Content="Item 4" />
</Border>
<Border BorderBrush="Gray" BorderThickness="1">
<Label Height="50" Content="Item 5" />
</Border>
<i:Interaction.Behaviors>
<StackPanelBehavior:ChildSpaceBehavior ShowDetailsCommand="{Binding ShowDetailsCommand}" />
</i:Interaction.Behaviors>
</StackPanel>
</Grid>
由于我页面的几乎所有元素都是自动调整大小的,因此对上述解决方案的以下更改有所帮助。包含堆栈面板网格的页面:
public MainPage()
{
InitializeComponent();
}
private void FillGridWithItems()
{
//Row and ColumnDefinitions
for (int row = 0; row < 5; row++)
{
for (int col = 0; col < 7; col++)
{
var item = new MyStackPanel(children)
Grid.SetColumn(item, col);
Grid.SetRow(item, row);
grid.Children.Add(item);
}
}
Loaded+=PageLoaded;
}
/// When page is loaded, ActualHeight of elements are calculated for sure.
private void PageLoaded(object sender, RoutedEventArgs e)
{
foreach (var child in grid.Children)
{
var item = child as MyStackPanel;
if (item != null)
{
item.FillInData();
}
}
}
/// Used instead of constructor, cause a parameter is sent to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
FillGridWithItems()
}
我的堆栈面板:
private readonly List<string> _items;
public MyStackPanel(List<string> items)
{
_items = items;
var behavior = new MyBehavior();
behavior.SetBinding(MyBehavior.ShowDetailsCommandProperty, new Binding
{
Path = new PropertyPath("ShowDetailsCommand")
});
Interaction.GetBehaviors(this).Add(behavior);
}
public void FillInData()
{
foreach (string item in _items)
{
var block = new Button();
block.Click += ItemClick;
this.Children.Add(block);
}
}
MyBehaviour(只是更改的部分)
...
private void OnLayoutUpdated(object sender, object o)
{
var container = (Grid) AssociatedObject.Parent;
if (container == null) return;
var height = container.RowDefinitions[Grid.GetRow(AssociatedObject)].ActualHeight;
// ... The same as above
}
....
我还没有实现 ShowDetailsCommand,所以我不能说 RelayCommand 是否按预期工作,但为什么不能;)还需要对 Windows 商店进行一些修改,例如使用 WinRtBehaviors 库,可以都可以通过谷歌搜索解决。