C# 在wpf中创建无限中心旋转木马控件
我试图在WPF中创建一个无休止的、以中心为中心的旋转木马,就像在这个概念图中一样。我目前提出的解决方案是使用一个列表框,将所有图像加载到一个ObservableCollection中,然后修改它以创建运动的错觉 这个解决方案有两个问题。首先,我似乎无法将它居中。列表框向左对齐,无法使其两侧溢出。无论我的窗口大小如何,都应该在中间显示一个控制台,每一侧显示一个控制台,一半显示一个控制台。 第二个问题没有那么重要,但我正在寻找一种合适的方法来实现这一点,以便以后在选择之间进行更流畅的转换 这是我当前的代码: XAML:C# 在wpf中创建无限中心旋转木马控件,c#,wpf,C#,Wpf,我试图在WPF中创建一个无休止的、以中心为中心的旋转木马,就像在这个概念图中一样。我目前提出的解决方案是使用一个列表框,将所有图像加载到一个ObservableCollection中,然后修改它以创建运动的错觉 这个解决方案有两个问题。首先,我似乎无法将它居中。列表框向左对齐,无法使其两侧溢出。无论我的窗口大小如何,都应该在中间显示一个控制台,每一侧显示一个控制台,一半显示一个控制台。 第二个问题没有那么重要,但我正在寻找一种合适的方法来实现这一点,以便以后在选择之间进行更流畅的转换 这是我当
我不认为我会像你那样做。即在列表框中添加和删除项目。没有给你足够的位置控制,你将无法做它旋转的平滑动画,这种UI,我认为这将是一种预期:) 我可能会用cliptobunds=true来代替画布。然后只计算位置,你没有做一个圆形旋转木马,所以位置很小,没有缩放
假设您的图像都是100 x 100。所以item0将是@-50,0,item1@50,0(技术上可能是75,0或其他什么,因为你希望它们之间有一些间距,但你知道了),等等,因为你在计算位置,并让它们绝对地靠在画布上,cliptobund=true将在任意一端剪辑这两个对象,您将能够设置旋转的动画。我对这个答案感到困惑。图形化更好,但是如果没有某种预先制作的可滚动/可选择/可加载的集合容器,您将失去很多功能—ItemsSource、SelectedItem、SelectedIndex等。您对如何使用您的方法实现这些功能有何建议?但正是这些功能阻碍了您的工作。一个预构建的滚动条,如列表框或任何期望项目彼此保持在相同位置的东西。它也将是一个愚蠢的工作包装作为一个滚动期望你从0滚动到X和从X滚动到0。不是以循环的方式。你将不得不重新实现滚动,以使酷的动画去无论如何。如果您想在侧面滚动箭头,可以在重复按钮上制作一些箭头。不要认为你需要选择索引。SelectedItem将只是您单击的图像。第2部分。。。使每个图像位于透明网格的顶部,这样您就不必单击实际图像本身,而是单击周围的正方形。也就是说,如果你有一个圆,除非你有透明的网格背景,你必须点击实际的圆,你将无法点击角落。您可以相当容易地将所有内容封装在自定义控件中。我认为围绕所有内置功能进行工作要比实现动画滚动、包装等并将其放入列表框要困难得多。第3部分:哈哈。。最后,我认为让ListBox在左侧显示部分项是不可行的,因为它希望项0从像素0开始。您可以尝试将一个列表框放置在ClipToBounds=True的网格中,并将列表框的边距设置为-50,然后查看这是否符合您的喜好。这将把左边的项目一分为二,但你永远不会在左边有一个完整的项目,滚动条也会被剪掉。就我个人而言,对于这个UI,我无论如何都会做一个覆盖滚动箭头。一个标准的滚动条看起来很奇怪。你的意思和这个例子相似吗?我会尝试一下,但如果我没有使用列表框或类似的。。。然后如何获取当前选定的项目?我将查看PivotControl的源代码,类似于Windows Phone中的无休止滚动控件,以了解它们是如何做到这一点的
<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);
}
}
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);
}
}