WPF旋转轮播元素

3
我正在开发一款使用相机自动拍照的软件。我希望用户能够设置拍照间隔时间。我想让它看起来和工作起来像某种旋转木马。
这就是它应该看起来的样子:
当我滑动(或用鼠标拖动)时,它应该向给定方向移动:
所选项目应始终位于中间,如果是最后一个,则第一个应向右旋转(反之亦然)。
我已经添加了基本的滑动/拖动功能,它会识别何时已经采取行动以及方向。然而,我不知道如何实际移动物品。
目前,这些条目是这样定义的:
<StackPanel x:Name="countdownContainer" Background="{StaticResource GuiSideBarBackgroundColor}" Orientation="Horizontal" HorizontalAlignment="Center">
    <TextBlock Style="{StaticResource CountdownElement}" Text="3s"/>
    <TextBlock Style="{StaticResource CountdownElementSelected}" Text="5s"/>
    <TextBlock Style="{StaticResource CountdownElement}" Text="10s"/>
</StackPanel>

我了解一些有关动画的基础知识,但不知道如何按照需要进行动画制作。 是否使用其他控件替代StackPanel和TextBlock元素会更好呢?


你有没有检查过那些现成的走马灯控件?这可能会为你节省一些麻烦。 - Chris W.
1
是的,我已经查看了那个。但我想自己创建它,因为我想在此过程中学习一些东西。 - Davide De Santis
1个回答

2
我基于您上面声明的样式,但没有包含在代码中。您可以在纯xaml和视图模型中实现此操作。这将是一个非常简单和粗糙的示例。或者,您可以实现一个自定义控件,该控件继承了某个类,该类在层次结构中的某个位置具有Selector类,而不是默认提供的默认cust控件模板中的控件。我建议您查看MVVM模式和Galasoft MVVM Light。在此示例中,我排除了触摸手势,它们很容易实现,并且使用EventToCommand,您可以直接在vm或custcontrol中使用它们。
<ItemsPanelTemplate x:Key="YourItemsPanelTemplate">
   <VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>

<DataTemplate x:Key="YourDataTemplate">
    <TextBlock Style="{StaticResource CountdownElement}" Text="{Binding .}" x:Name="PART_TextBlock"/>
    <DataTemplate.Triggers>
        <DataTrigger
        Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType= {x:Type ListViewItem}},Path=IsSelected}" Value="True"> 
            <!-- Here I'm just changing your fontsize, do whatever you want here :) -->                                       
            <Setter Property="FontSize" Value="34" TargetName="PART_TextBlock"/>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

<Style x:Key="YourContainerStyle" TargetType="ListViewItem">
    <Setter Property="HorizontalContentAlignment" Value="Center" />
    <Setter Property="VerticalContentAlignment" Value="Bottom" />
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="Margin" Value="10,0,10,0" />
    <Setter Property="Padding" Value="0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <ContentPresenter x:Name="PART_ContentPresenter"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                Margin="{TemplateBinding Padding}"
                                Content="{TemplateBinding Content}"
                                ContentTemplate="{StaticResource YourDataTemplate}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="YourListBoxStyle" TargetType="ListBox">
    <Setter Property="ItemContainerStyle" Value="{StaticResource YourContainerStyle}"/>
    <Setter Property="ItemTemplate" Value="{StaticResource YourDataTemplate}"/>
    <Setter Property="ItemsPanel" Value="{StaticResource YourItemsPanelTemplate}"/>
</Style>

这是您的样式,现在来看XAML代码,注意我在此绑定了您的项目,并使用上述描述的样式。
XAML
<Grid>
    <ListView Background="{StaticResource  GuiSideBarBackgroundColor}" 
        Style="{StaticResource YourListBoxStyle}"
        ItemsSource="{Binding CountDownElements}"
        SelectedItem="{Binding SelectedItem, Mode=TwoWay}"/>
<Grid>

视图模型 记得将其设置为视图的数据上下文,或将代码复制到您的代码后台。
public class YourViewModel : INotifyPropertyChanged
{
    private ObservableCollection<string> countDownElements = new ObservableCollection<string> { "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s", "10s" };
    private string selectedItem;

    public ObservableCollection<string> CountDownElements
    {
        get { return countDownElements; }
        set
        {
            if (Equals(value, countDownElements)) return;
            countDownElements = value;
            OnPropertyChanged();
        }
    }

    public string SelectedItem
    {
        get { return selectedItem; }
        set
        {
            if (value == selectedItem) return;
            selectedItem = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator] // remove if you don't have R#
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

输出

Very simple stuff

希望这有所帮助,或者至少能让你朝着正确的方向迈进!:)
祝福您
Stian

3
谢谢Stian :) 我其实考虑过使用ListView,但由于我还有一个问题:如何让ListView无限循环。我的目标是始终将选定的项目显示在中心,其他元素围绕其周围循环。如我的两个图像所示,当选择“10s”时,“3s”向右移动。 我需要只是重新排序集合中的元素,并每次重新绘制ListView,还是有更好的方法? - Davide De Santis
2
@DavideDeSantis,为此,您可能需要创建自己的项面板。我在第一代Microsoft Surface(大桌子)上编写了我的学士论文代码。实际上,这与您的问题几乎完全相同,但我无法分享此代码,因为它属于我为之撰写论文的公司。基本上,您需要创建一个面板,并在控件模板中将ItemsHost设置为true。此示例已过时,因为Dr.WPF在2010年停止了WPF编码,但它可能会指引您朝着正确的方向前进。您需要实现IScrollInfo接口。 - Stígandr
@DavideDeSantis 没问题!这有点有趣,因为这实际上是我论文的关键控制之一,在我的初始回答后,我才记起/意识到它 :) 那时我正在学习C#和WPF。你很可能会在某些情况下感到非常困惑,但至少现在触摸已经成为主流,并且是普通Windows和WPF的一部分。 - Stígandr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接