在wpf中创建无限中心轮播控件

时间:2015-08-16 08:31:00

标签: c# wpf

我试图在WPF中创建一个无尽的,居中的旋转木马,就像在这个概念图像中一样。我提出的当前解决方案是使用列表框,将所有图像加载到ObservableCollection中,然后修改它以创建移动的幻觉。

enter image description here

我对此解决方案有两个问题。首先,我无法将其置于中心位置。列表框与左侧对齐,无法让它在两侧溢出。无论我的窗户大小如何,它应该总是在中间显示一个控制台,每侧一个控制台和一个半控制台,以表明还有更多选择。

第二个问题并不重要,但我正在寻找一种正确的方法来实现这一目标,这可能会让以后的选择之间更加流畅的过渡。

这是我目前的代码:

XAML:

<Window x:Class="SystemMenu.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

<DockPanel>
    <Button Content="left" Height="20" Click="Left_Click" DockPanel.Dock="Top" />
    <Button Content="right" Height="20" Click="Right_Click" DockPanel.Dock="Top" />

    <ListBox x:Name="LoopPanel" ItemsSource="{Binding Path=SampleData}" SelectedIndex="3" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.CanContentScroll="False">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                    <Image Source="{Binding}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</DockPanel>

代码背后:

    public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    ObservableCollection<string> sampleData = new ObservableCollection<string>();
    public ObservableCollection<string> SampleData
    {
        get
        {
            if (sampleData.Count <= 0)
            {
                sampleData.Add(@"Nintendo 64.png");
                sampleData.Add(@"Nintendo Famicom.png");
                sampleData.Add(@"Super Nintendo Entertainment System.png");
                sampleData.Add(@"Nintendo Entertainment System.png");
                sampleData.Add(@"Sony PlayStation.png");
            }
            return sampleData;
        }
    }

    private void Right_Click(object sender, RoutedEventArgs e)
    {
        var firstItem = SampleData.First();
        SampleData.Remove(firstItem);
        SampleData.Insert(SampleData.Count, firstItem);
    }

    private void Left_Click(object sender, RoutedEventArgs e)
    {
        var lastItem = SampleData.Last();
        SampleData.Remove(lastItem);
        SampleData.Insert(0, lastItem);
    }
}

修改 我发现以下扩展解决了我对列表框居中的问题。调用LoopPanel.ScrollToCenterOfView(sampleData [2]);似乎是以图像为中心的诀窍......现在有关于如何设置过渡动画的想法吗? :)

 public static class ItemsControlExtensions
    {
        public static void ScrollToCenterOfView(this ItemsControl itemsControl, object item)
        {
            // Scroll immediately if possible
            if (!itemsControl.TryScrollToCenterOfView(item))
            {
                // Otherwise wait until everything is loaded, then scroll
                if (itemsControl is ListBox) ((ListBox)itemsControl).ScrollIntoView(item);
                itemsControl.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
                {
                    itemsControl.TryScrollToCenterOfView(item);
                }));
            }
        }

        private static bool TryScrollToCenterOfView(this ItemsControl itemsControl, object item)
        {
            // Find the container
            var container = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
            if (container == null) return false;

            // Find the ScrollContentPresenter
            ScrollContentPresenter presenter = null;
            for (Visual vis = container; vis != null && vis != itemsControl; vis = VisualTreeHelper.GetParent(vis) as Visual)
                if ((presenter = vis as ScrollContentPresenter) != null)
                    break;
            if (presenter == null) return false;

            // Find the IScrollInfo
            var scrollInfo =
                !presenter.CanContentScroll ? presenter :
                presenter.Content as IScrollInfo ??
                FirstVisualChild(presenter.Content as ItemsPresenter) as IScrollInfo ??
                presenter;

            // Compute the center point of the container relative to the scrollInfo
            Size size = container.RenderSize;
            Point center = container.TransformToAncestor((Visual)scrollInfo).Transform(new Point(size.Width / 2, size.Height / 2));
            center.Y += scrollInfo.VerticalOffset;
            center.X += scrollInfo.HorizontalOffset;

            // Adjust for logical scrolling
            if (scrollInfo is StackPanel || scrollInfo is VirtualizingStackPanel)
            {
                double logicalCenter = itemsControl.ItemContainerGenerator.IndexFromContainer(container) + 0.5;
                Orientation orientation = scrollInfo is StackPanel ? ((StackPanel)scrollInfo).Orientation : ((VirtualizingStackPanel)scrollInfo).Orientation;
                if (orientation == Orientation.Horizontal)
                    center.X = logicalCenter;
                else
                    center.Y = logicalCenter;
            }

            // Scroll the center of the container to the center of the viewport
            if (scrollInfo.CanVerticallyScroll) scrollInfo.SetVerticalOffset(CenteringOffset(center.Y, scrollInfo.ViewportHeight, scrollInfo.ExtentHeight));
            if (scrollInfo.CanHorizontallyScroll) scrollInfo.SetHorizontalOffset(CenteringOffset(center.X, scrollInfo.ViewportWidth, scrollInfo.ExtentWidth));
            return true;
        }

        private static double CenteringOffset(double center, double viewport, double extent)
        {
            return Math.Min(extent - viewport, Math.Max(0, center - viewport / 2));
        }
        private static DependencyObject FirstVisualChild(Visual visual)
        {
            if (visual == null) return null;
            if (VisualTreeHelper.GetChildrenCount(visual) == 0) return null;
            return VisualTreeHelper.GetChild(visual, 0);
        }
    }

1 个答案:

答案 0 :(得分:1)

我不认为我会这样做你怎么做的。即添加和删​​除ListBox中的项目。没有给你足够的控制定位,你不能通过那种UI进行旋转的平滑动画,我认为这有点预期:)。

我可能有一个Canvas而不是ClipToBounds = true。然后只计算位置,你不做圆形旋转木马,所以位置是微不足道的,没有缩放。

让我们说你的图像都是100 x 100.所以item0将是@ -50,0,item1 @ 50,0(好吧,技术上可能是75,0或者其他什么因为你想要它们之间有一些间距,但是你得到了这个想法),等等。因为你正在计算位置并且它们对Canvas是绝对的,所以ClipToBound = true将在两端剪切两个,你将能够为旋转设置动画。