0

要素を StackPanel (または Listbox / Listview を簡単にする場合) に追加し、ボタン (「...」など) を自動的に追加して、スペースよりも多くの子があることを示したいと思います。毎日予定項目があるカレンダーを考えてみましょう。表示しきれないほどの予定がある場合は、その日の詳細ビューに移動するためのボタンが表示されます。

これは自動的に実行できますか、またはスタックパネルとそのア​​イテムの位置をどのように計算しますか?

これは、C# での Windows ストア開発用です。

4

2 に答える 2

0

Behavior を使用できます (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については、こちらをご覧ください

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

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 が意図したとおりに機能するかどうかはわかりませんが、なぜ機能しないのでしょうか ;) また、WinRtBehaviors ライブラリを使用するなど、Windows ストアに対していくつかの変更を行う必要があります。すべてグーグルで解決します。

于 2012-11-07T15:38:32.490 に答える