将扩展按钮添加到Stackpanel

时间:2012-11-05 22:57:53

标签: c# xaml stackpanel windows-store-apps

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

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

用于c#中的windows store开发。

2 个答案:

答案 0 :(得分: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,请查看here

的Xaml:

<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>

答案 1 :(得分:0)

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

    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()
    }

MyStackPanel:

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