0

我想将元素添加到 StackPanel(或 Listbox / Listview,如果它可以更容易的话)并自动添加一个 Button(如“...”)以指示有更多的孩子而不是空间。考虑一个每天都有约会项目的日历。如果约会的数量超过了可以显示的数量,则会显示一个按钮以转到当天的详细视图。

这可以自动完成,或者我如何计算堆栈面板及其项目的位置。

它用于 c# 中的 windows 商店开发。

4

2 回答 2

0

您可以使用行为(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>
于 2012-11-06T09:13:55.707 回答
0

由于我页面的几乎所有元素都是自动调整大小的,因此对上述解决方案的以下更改有所帮助。包含堆栈面板网格的页面:

    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 库,可以都可以通过谷歌搜索解决。

于 2012-11-07T15:38:32.490 回答