我正在尝试在WPF中创建一个无限居中的走马灯,就像这个概念图。我想出的当前解决方案是使用一个ListBox,将所有图像加载到ObservableCollection中,然后修改它以创建移动的假象。
我对这个解决方案有两个问题。首先,我似乎无法将其置于中心位置。 ListBox被对齐到左侧,没有办法让它溢出到两侧。无论我的窗口大小如何,它都应该始终在中间显示一个控制台,每侧一个,还应显示半个控制台以指示仍有更多可供选择。
第二个问题并不那么重要,但我正在寻找一种适当的方法,可以在以后的选择中允许更流畅的过渡。
这是我的现有代码:
XAML:
第二个问题并不那么重要,但我正在寻找一种适当的方法,可以在以后的选择中允许更流畅的过渡。
这是我的现有代码:
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);
}
}