【问题标题】:Using VisualStateGroup inside Binded ListView在 Binded ListView 中使用 VisualStateGroup
【发布时间】:2016-10-01 17:39:12
【问题描述】:

我在 UWP 中有一个绑定的列表视图,我想根据一些属性在 ItemTemplate 中显示或隐藏一些控件

我使用的 XAML 在这里用于绑定 ObservableCollection

   <ListView x:Name="lvwMovieWatchlist"  ItemsSource="{x:Bind Books}" Margin="10">
            <ListView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ListView.ItemsPanel>
            <ListView.ItemTemplate>              
                <DataTemplate x:DataType="data:BookModel">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Border Width="156" Height="200">
                            <Image Source="{Binding CoverImage}" Stretch="UniformToFill"/>
                        </Border>
                        <StackPanel Grid.Column="1" Orientation="Vertical">
                            <TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap" Margin="9.6,0"/>
                            <TextBlock Text="{Binding Name}" Style="{StaticResource SubtitleTextBlockStyle}" TextWrapping="NoWrap" Margin="9.6,0"/>
                            <StackPanel Orientation="Horizontal" Margin="10">
                                <Button Name="Btn_Download" Tag="{Binding}" Click="Btn_Download_Click"> DOWNLOAD</Button>                                
                                <Button Name="Btn_Read" Tag="{Binding}" Click="Btn_Read_Click"> READ</Button>                                
                            </StackPanel>
                        </StackPanel>
                    </Grid>
                </DataTemplate>             
            </ListView.ItemTemplate>
        </ListView>

这里有两个按钮 Btn_Download 和 Btn_Read 如果 Status 属性是“读取”,那么我想将 Btn_Read 的可见性设置为可见,否则显示 Btn_Download 按钮

在 WPF 中,我有触发器来实现类似的效果

        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Status}" Value="read">                   
                <Setter TargetName="Btn_Read" Property="Visibility" Value="Visible"/>
                <Setter TargetName="Btn_Download" Property="Visibility" Value="Collapsed"/>                 
            </DataTrigger>                                              
        </DataTemplate.Triggers>

但在 UWP 中没有触发器,只有 VisualStateManager.VisualStateGroups 可用。 那么如何在 ItemTemplate 中使用 VisualStateGroup 来实现它

【问题讨论】:

    标签: c# xaml win-universal-app uwp


    【解决方案1】:

    一个可能的想法是使用转换器而不是 VisualStateManager:

    <StackPanel Orientation="Horizontal" Margin="10">
                                            <Button Name="Btn_Download" Tag="{Binding}" Click="Btn_Download_Click" Visibility={Binding Status, Converter={StaticResource StatusToDownloadVisibilityConverter}}> DOWNLOAD</Button>                                
                                            <Button Name="Btn_Read" Tag="{Binding}" Click="Btn_Read_Click"  Visibility={Binding Status, Converter={StaticResource StatusToReadVisibilityConverter}}> READ</Button>                                
        </StackPanel>
    

    根据 Status 属性的值,只需创建 2 个转换器(StatusToDownloadVisibilityConverter 和 StatusToReadVisibilityConverter),它们接受一个 Status in 参数并返回一个 Visibility。

    也许不是 100% 理想的解决方案,但应该可行!

    【讨论】:

    • 是的,这种方式可行,但我喜欢用 VisualState 来实现,因为它可以完全控制 xaml 本身,所以也想学习 VisualState 概念
    【解决方案2】:

    如果您想完全在 XAML 中完成,您可以使用 Interactivity behaviors 扩展名来完成。使用视觉状态和数据触发操作的示例可能如下所示 - XAML:

    <Grid xmlns:i="using:Microsoft.Xaml.Interactivity" xmlns:ic="using:Microsoft.Xaml.Interactions.Core" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ReadOrNot">
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="Read">
                    <Storyboard BeginTime="0:0:0" Duration="0:0:1">
                        <FadeOutThemeAnimation TargetName="BtnDownload"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <i:Interaction.Behaviors>
            <i:BehaviorCollection>
                <ic:DataTriggerBehavior Binding="{Binding Status}" Value="read">
                    <ic:GoToStateAction StateName="Read"/>
                </ic:DataTriggerBehavior>
            </i:BehaviorCollection>
        </i:Interaction.Behaviors>
        <Button Name="BtnDownload" HorizontalAlignment="Left" Content="Download" FontSize="20" Foreground="Red"/>
        <Button HorizontalAlignment="Center" Content="Change property" FontSize="20" Foreground="Orange" Click="Button_Click"/>
        <Button Name="BtnRead" HorizontalAlignment="Right" Content="Read" FontSize="20" Foreground="Green"/>
    </Grid>
    

    背后的代码:

    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    
        private string status = "notRead";
        public string Status
        {
            get { return status; }
            set { status = value; RaiseProperty(nameof(Status)); }
        }
    
        public MainPage()
        {
            this.InitializeComponent();
            DataContext = this;
        }
    
        private void Button_Click(object sender, RoutedEventArgs e) => Status = "read";
    }
    

    按钮单击更改状态以读取并通过行为触发视觉状态更改。您可以为您的项目模板做类似的事情。作为旁注,您还可以使用其他操作,根据您想要实现的目标,可能会更容易一些 - 例如 ChangePropertyAction

    当然,要使其正常工作,您必须在项目中添加对行为的引用(添加引用 -> 通用窗口 -> 扩展)或通过 NuGet,例如 igrali has mentioned,是一个更好的选择(开源和定位 UWP)。

    【讨论】:

    【解决方案3】:

    将您的模板包装在用户控件中并添加可视状态管理器。

    <ListView x:Name="lvwMovieWatchlist" ItemsSource="{x:Bind ViewModel.Books}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:BookModel">
                <local:BookControl />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    
    <UserControl
        x:Class="App2.BookControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App2"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
            <Grid>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="ButtonsVisibility">
                        <VisualState x:Name="ButtonsVisible">
                        </VisualState>
                        <VisualState x:Name="ButtonsHidden">
                            <VisualState.StateTriggers>
                                <StateTrigger IsActive="{Binding Status, Mode=OneWay}" />
                            </VisualState.StateTriggers>
                            <VisualState.Setters>
                                <Setter Target="Btn_Download.Visibility" Value="Collapsed" />
                                <Setter Target="Btn_Read.Visibility" Value="Collapsed" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="{Binding Title}" />
                    <TextBlock Text="{Binding Subtitle}" />
                    <StackPanel Orientation="Horizontal">
                        <Button Name="Btn_Download" Tag="{Binding}" Click="Btn_Download_Click">DOWNLOAD</Button>
                        <Button Name="Btn_Read" Tag="{Binding}" Click="Btn_Read_Click">READ</Button>
                    </StackPanel>
                </StackPanel>
            </Grid>
    </UserControl>
    

    此示例在布尔属性上使用内置 StateTrigger。要将属性与某个值进行比较,请使用出色的 WindowsStateTriggers 库 (https://github.com/dotMorten/WindowsStateTriggers) 中的 EqualsStateTrigger。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多