Вопрос

У меня есть UserControl с помощью Grid который подписан на Holding событие.Проблема в том, что Holding событие срабатывает для элемента, на который я нацелился, а также для некоторых других элементов в ListView.Кстати, я использую элемент управления в качестве DataTemplate.

<ListView ItemsSource="{Binding ...}" Margin="0, 0, 0, 0">
    ...
    <ListView.ItemTemplate>
        <DataTemplate>
            <local:MyUserControl/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Код пользовательского управления, скрытый за:

    private bool isDescriptionVisible = false;

    private void Grid_Holding(object sender, HoldingRoutedEventArgs e)
    {
        if (!isDescriptionVisible)
        {
            DescriptionFadeIn.Begin();
            isDescriptionVisible = true;
        }
    }

    private void Grid_Tapped(object sender, TappedRoutedEventArgs e)
    {
        if (isDescriptionVisible)
        {
            DescriptionFadeOut.Begin();
            isDescriptionVisible = false;
        }
    }

Содержимое пользовательского элемента управления:

<Grid.Resources>
    <Storyboard x:Name="FadeIn">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DescriptionLayer"
                             Duration="0:0:0.3" To=".8"/>
        </Storyboard>

        <Storyboard x:Name="FadeOut">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DescriptionLayer"
                             Duration="0:0:0.3" To="0"/>
        </Storyboard>
</Grid.Resources>

<Grid Margin="0, 0, 0, 48" Holding="Grid_Holding" Tapped="Grid_Tapped">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="1*"/>
    </Grid.RowDefinitions>
    <Image Source="{Binding Img}" Stretch="UniformToFill" Height="240" Width="450"/>
    <Grid x:Name="DescriptionLayer" Background="Black" Opacity="0">
        <TextBlock Text="{Binding Description}" FontSize="16" TextWrapping="Wrap" Margin="0, 9, 0, 0" MaxHeight="170" TextTrimming="CharacterEllipsis"/>
    </Grid>
    <StackPanel Grid.Row="1" Margin="12">
        <TextBlock Text="{Binding Author}" FontSize="16"/>
        <TextBlock Text="{Binding Title}" FontSize="18"/>
    </StackPanel>
</Grid>

Я не смог использовать раскадровки для элементов, содержащихся в DataTemplate, так что это вынудило меня использовать переместить его содержимое в UserControl.

Связана ли эта проблема с виртуализацией?Как я могу это исправить?

Подойдут альтернативные варианты.

Обновить:

В некоторых сообщениях SO предполагалось, что режим утилизации приводит к повторному использованию предметов.Я добавил VirtualizingStackPanel.VirtualizationMode="Standard" в мой ListView, но проблема, на удивление, сохраняется.

Итак, теперь мне нужно найти способ предотвратить повторение другими элементами одного и того же значения непрозрачности (которое не привязано к базе данных, поскольку оно задается через раскадровку).

ОБНОВЛЕНИЕ 2:

Теперь описание, которое исчезает при удержании отображаемого элемента, полностью исчезает, когда он выходит из поля зрения:

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <VirtualizingStackPanel/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Это было полезно?

Решение

Мне нравится, как вы пытаетесь это сделать.Для устройств с сенсорным экраном у нас нет MouseOver итак, это один из способов, когда вы хотите показать некоторую дополнительную информацию, не портя пользовательский интерфейс.

Однако гораздо более чистым решением было бы создать многоразовый Behavior это инкапсулирует всю логику пользовательского интерфейса и анимацию.

Чтобы сделать это, вам сначала нужно будет включить ссылку Behaviors SDK (XAML).

Тот самый Behavior реализация происходит прямолинейно.Тот самый AssociatedObject было бы самым Grid который получает события касания, а затем вам нужно создать DependencyProperty TextBlockName чтобы получить описание TextBlock пример.Как только у вас будет экземпляр, вам просто нужно написать анимацию для него на C #.

public class ShowHideDescriptionBehavior : DependencyObject, IBehavior
{
    public string TextBlockName
    {
        get { return (string)GetValue(TextBlockNameProperty); }
        set { SetValue(TextBlockNameProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TextBlockName.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TextBlockNameProperty =
        DependencyProperty.Register("TextBlockName", typeof(string), typeof(ShowHideDescriptionBehavior), new PropertyMetadata(string.Empty));

    public DependencyObject AssociatedObject { get; set; }

    public void Attach(DependencyObject associatedObject)
    {
        this.AssociatedObject = associatedObject;
        var panel = (Panel)this.AssociatedObject;

        panel.Holding += AssociatedObject_Holding;
        panel.Tapped += AssociatedObject_Tapped;
    }

    private void AssociatedObject_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
    {
        var animation = new DoubleAnimation
        {
            Duration = TimeSpan.FromMilliseconds(300),
            To = 0
        };
        Storyboard.SetTarget(animation, this.DescriptionTextBlock);
        Storyboard.SetTargetProperty(animation, "Opacity");

        var storyboard = new Storyboard();
        storyboard.Children.Add(animation);
        storyboard.Begin();
    }

    private void AssociatedObject_Holding(object sender, Windows.UI.Xaml.Input.HoldingRoutedEventArgs e)
    {
        var animation = new DoubleAnimation
        {
            Duration = TimeSpan.FromMilliseconds(300),
            To = 0.8
        };
        Storyboard.SetTarget(animation, this.DescriptionTextBlock);
        Storyboard.SetTargetProperty(animation, "Opacity");

        var storyboard = new Storyboard();
        storyboard.Children.Add(animation);
        storyboard.Begin();
    }

    private TextBlock _descriptionTextBlock;
    private TextBlock DescriptionTextBlock
    {
        get
        {
            if (_descriptionTextBlock == null)
            {
                var panel = (Panel)this.AssociatedObject;
                // todo: add validation
                _descriptionTextBlock = (TextBlock)panel.FindName(this.TextBlockName);
            }

            return _descriptionTextBlock;
        }
    }

    public void Detach()
    {
        var panel = (Panel)this.AssociatedObject;

        panel.Holding -= AssociatedObject_Holding;
        panel.Tapped -= AssociatedObject_Tapped;
    }
}

Это Behavior затем может быть присоединен к вашему DataTemplateвысший уровень Grid.Обратите внимание, что вам не нужен UserControl заворачивать его больше нельзя.

Кроме того, убедитесь, что у вас есть цвет фона для Grid таким образом, он может получать события касания.Последнее, что я сделал, это изменил ListView's ItemContainerStyle's HorizontalContentAlignment Для Stretch таким образом , Grid растягивается до упора вправо.

<Page.Resources>
    <DataTemplate x:Key="GroupTemplate">
        <Grid Background="Transparent" Margin="12">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Interactivity:Interaction.Behaviors>
                <local:ShowHideDescriptionBehavior TextBlockName="Description" />
            </Interactivity:Interaction.Behaviors>
            <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="110" Height="110">
                <Image Source="{Binding Img}" Height="110" Width="110"/>
            </Border>
            <StackPanel Grid.Column="1" Margin="10,0,0,0">
                <TextBlock Text="{Binding Author}" Style="{StaticResource TitleTextBlockStyle}"/>
                <TextBlock x:Name="Description" Opacity="0" Text="{Binding Description}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
            </StackPanel>
        </Grid>
    </DataTemplate>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" DataContext="{Binding Source={StaticResource SampleDataSource}}">
    <ListView ItemTemplate="{StaticResource GroupTemplate}" ItemsSource="{Binding Groups}">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            </Style>
        </ListView.ItemContainerStyle>
    </ListView>
</Grid>

Другие советы

Я нашел обходной путь;Я добавил свойство под названием DescriptionLayerOpacity к моей модели и установите для нее значение по умолчанию 0 когда я добавляю новый элемент в свой ObservableCollection в моей модели просмотра.

Я также добавил двустороннюю привязку для изменения исходного свойства (DescriptionLayerOpacity), поэтому представление обновляется с учетом изменений, внесенных раскадровками:

<Grid ... Opacity="{Binding DescriptionLayerOpacity, Mode=TwoWay}">
    <TextBlock .../>
</Grid>

Короче говоря, все данные UserControl должны были быть привязаны к данным, чтобы избежать повторения в других элементах ListView.

Это действительно не элегантное решение, и оно не было полностью протестировано.Пока я не найду настоящего решения, этого будет достаточно.

Обновлять:Не полностью работает

Недавно я обнаружил, что некоторые элементы не реагируют на выбор других элементов.Чтобы эти элементы ответили, мне нужно нажать до события касания + удержания (кстати, оба события являются взаимоисключающими).

Обновление 2:

После удаления вроде все работает нормально if операторы в коде.Но привязка к свойству непрозрачности модели, чтобы заставить ее работать, по-прежнему является неприятным решением.

Посмотрите решение здесь: http://social.msdn.microsoft.com/Forums/windowsapps/en-US/95f49050-368e-4ddb-962e-6be62e7e3d57/context-menus-in-listview-windows-phone-81?forum=wpdevelop

Я не уверен, что это именно ваша проблема, но похоже на UserControl не получает событие удержания, поскольку оно поглощается ListView?Решение выше описывает необходимость обернуть DataTemplates Grid в ListViewItem, и прикрепив к нему событие Hold.Может быть, это поможет?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top