Stackpanel数据触发器,用于根据子宽度设置方向

时间:2018-03-21 13:09:35

标签: c# wpf xaml

我知道我可以在这种情况下使用WrapPanel但是有什么方法可以实现我正在寻找的东西。我想使用StackPanel作为ListBox的项目面板,其中方向设置为水平。我可以得到StackPanel的子项超出父控件/容器宽度的情况。因此,例如,如果我有一个StackPanel,其中5个文本块设置为水平方向,然后我将窗口拖动宽度使其变小,在某个时刻,第5 TextBox将延伸到屏幕外(隐藏)。在这一点上,我想要某种数据触发器将方向设置为垂直,几乎就像一个响应式设计。有没有办法做到这一点?

1 个答案:

答案 0 :(得分:1)

  

有办法做到这一点吗?

您可以处理SizeChanged事件。以下代码示例应该为您提供想法。如果最后一个元素(Orientation)被隐藏,它会将Horizontal设置为TextBox,并在宽度增加时将其设置回Vertical

private void ListBox_SizeChanged(object sender, SizeChangedEventArgs e)
{
    ListBox lb = sender as ListBox;
    ItemsPresenter ip = FindVisualChild<ItemsPresenter>(lb);
    StackPanel sp = FindVisualChild<StackPanel>(ip);
    UIElement lastElement = sp.Children[sp.Children.Count - 1];
    bool isLastElementVisible = IsElementVisible(lastElement);

    if (e.NewSize.Width < e.PreviousSize.Width && !isLastElementVisible)
        sp.Orientation = Orientation.Vertical;
    else if (e.NewSize.Width > e.PreviousSize.Width && isLastElementVisible)
        sp.Orientation = Orientation.Horizontal;
}

private static T FindVisualChild<T>(DependencyObject parent, string childName = null) where T : DependencyObject
{
    int count = VisualTreeHelper.GetChildrenCount(parent);

    for (int i = 0; i < count; i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        var childElement = child as FrameworkElement;
        if (child is T && (childName == null || (childElement != null && childElement.Name == childName)))
        {
            return child as T;
        }
        else
        {
            var grandchild = FindVisualChild<T>(child, childName);
            if (grandchild is T)
            {
                return grandchild;
            }
        }
    }
    return null;
}

private static bool IsElementVisible(UIElement element)
{
    if (!element.IsVisible)
        return false;
    var container = VisualTreeHelper.GetParent(element) as FrameworkElement;
    if (container == null) throw new ArgumentNullException("container");

    Rect bounds = element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.RenderSize.Width, element.RenderSize.Height));
    Rect rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);
    return rect.IntersectsWith(bounds);
}

<强> XAML:

<ListBox SizeChanged="ListBox_SizeChanged">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <TextBox Width="100" Text="1" />
    <TextBox Width="100" Text="2" />
    <TextBox Width="100" Text="3" />
    <TextBox Width="100" Text="4" />
    <TextBox Width="100" Text="5" />
</ListBox>