Nano Hash - криптовалюты, майнинг, программирование

Привязка общего всплывающего меню к 2 элементам управления в DataTemplate Listview в UWP Windows 10

У меня есть общий Flyout, определенный в моем <Page.Resources> следующим образом:

<Flyout x:Name="InfoFlyout" Opened="{Binding IsOpen,
        ElementName=MyListView, Mode=TwoWay}">
    <Grid>
        <Button Foreground="White" Margin="5">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Help"/>
            </StackPanel>
        </Button>
    </Grid>
</Flyout>

Но при компиляции получаю ошибку An object reference not set, поэтому использовал код из этой статьи (Использование Windows 8.1 Flyout control с MVVM).

Кажется, это позволяет обойти проблему, с которой я столкнулся в приведенном выше коде. Теперь мой общий код Flyout выглядит так:

<Flyout x:Name="InfoFlyout"
        helpers:FlyoutHelpers.Parent="{Binding ElementName=MyListView}"
        helpers:FlyoutHelpers.IsOpen="{Binding IsOpen, Mode=TwoWay}">
    <Grid>
    <Button Foreground="White" Margin="5">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Help"/>
        </StackPanel>
    </Button>
    </Grid>
</Flyout>

Мой элемент управления ListView (т.е. x:Name="MyListView") привязан к ViewModel страницы, т.е. MainPageViewModel. Свойство IsOpen определено в MainViewModel.

Теперь в моем ListView DataTemplate я хочу, чтобы мой Flyout открывался, когда я нажимаю и удерживаю ListViewItem или при нажатии кнопки в ListViewItem:

<DataTemplate>
    <Grid FlyoutBase.AttachedFlyout="{StaticResource InfoFlyout}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Image Grid.Column="0" Source={Binding MyImage} />
        <Grid Grid.Column="1" Margin="5">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Button Width="30" Height="30"
                    Flyout="{StaticResource InfoFlyout}"
                    content="i">
            </Button>
        </Grid>
        <interactivity:Interaction.Behaviors>
            <core:EventTriggerBehavior EventName="Holding">
                <actions:OpenFlyoutAction />
            </core:EventTriggerBehavior>
        </interactivity:Interaction.Behaviors>
    </Grid>
</DataTemplate>

Как видите, у меня есть Flyout, "привязанный" к Grid через:

FlyoutBase.AttachedFlyout="{StaticResource InfoFlyout}"

и у меня есть тот же Flyout, прикрепленный к кнопке внутри самого ListViewItem через:

Flyout="{StaticResource InfoFlyout}"

Я поставил точки останова как на мой установщик, так и на геттер для свойства IsOpen, и когда страница загружается, она переходит в геттер, но всякий раз, когда я открываю или закрываю свой Flyout либо через Holding, либо нажатием кнопки «i», это не t запускает описанный ниже метод и, следовательно, не изменяет свойство IsOpen.

private static void OnIsOpenPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e) as defined in the FlyoutHelper class.

Причина, по которой я установил свой ElementName в MyListView, заключается в том, что я хочу, чтобы все мои ListViewItem были привязаны к одному свойству, то есть IsOpen, поскольку мне нужно обнаруживать, когда открывается всплывающее меню, независимо от того, к какому ListViewItem оно принадлежит.

Как я могу достичь или решить это?

ОБНОВЛЕНИЕ – 1

Проблема доступа к общему меню была решена с помощью следующего:

<Flyout x:Name="InfoFlyout"
        helpers:FlyoutHelpers.Parent="{Binding ElementName=MyListView}"
        helpers:FlyoutHelpers.IsOpen="{Binding IsOpen, Mode=TwoWay}">

и установка кнопки на

<Button Width="30" Height="30"
Command="{Binding InformationCommand}"
CommandParameter="{Binding}"
Flyout="{StaticResource InfoFlyout}">

Это нормально, и, как упомянул @ElvisXia, вы можете закомментировать код в OnIsOpenPropertyChanged, поскольку позиционирование уже определено кнопкой, расположенной внутри моего ListViewItem.

Однако есть одна нерешенная проблема. Кстати, небольшая, но хорошо, если ее можно решить. Общий всплывающий элемент, прикрепленный к самой сетке в DataTemplate, т.е.

<DataTemplate>
    <Grid FlyoutBase.AttachedFlyout="{StaticResource InfoFlyout}">

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

<interactivity:Interaction.Behaviors>
    <core:EventTriggerBehavior EventName="Holding">
        <actions:OpenFlyoutAction />
    </core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>

И OpenFlyoutAction определяется следующим образом:

public class OpenFlyoutAction : DependencyObject, IAction
{
    public object Execute(object sender, object parameter)
    {
        FrameworkElement senderElement = sender as FrameworkElement;
        FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(senderElement);

        flyoutBase.ShowAt(senderElement);

        return null;
    }
}

Могу ли я каким-то образом перестать использовать OpenFlyoutAction и использовать тот же код, что и в статье, чтобы открыть мой Flyout везде, где пользователь держит палец на соответствующем ListViewItem, а не над или под фактическим ListViewItem?

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

Спасибо.


  • OnIsOpenPropertyChanged будет срабатывать при изменении IsOpen. Поскольку вы привязали пользовательское свойство IsOpen, вы должны изменить его на true при открытии всплывающего окна. Вы делаете это? 25.04.2016
  • Нет я не. Я думал, что идея заключалась в том, чтобы он автоматически менялся при открытии через OnIsOpenPropertyChanged. Я проверю статью еще раз и вернусь немного позже. В идеале я хотел бы, чтобы встроенное событие Opened было привязано и соответствующим образом изменено. 25.04.2016
  • На данный момент OnIsOpenPropertyChanged ограничен событием изменения свойства? Это относится к вашему пользовательскому свойству IsOpen? Если да, то при открытии всплывающего окна сделайте свойство IsOpen для вашей модели представления истинным. Поскольку его двусторонняя привязка вызовет событие OnIsOpenPropertyChanged. 25.04.2016
  • Только что проверил статью. Просто проверьте, регистрируется ли он в событии открытия и закрытия всплывающего окна в событии OnParentPropertyChanged. 25.04.2016
  • Изменили ли вы тип родительского объекта attachProperty в FlyoutHelpers.cs с Button на ListView? Я сделал эту ошибку сначала. После исправления все работает нормально. 25.04.2016
  • Это не так, и в этом проблема. Это та часть, которую я полностью пропустил: она регистрировала открытие и закрытие, когда родитель был установлен, но, сказав это, я до сих пор не знаю, почему он не регистрирует родителя, когда вы можете видеть из вышеизложенного, что он устанавливается через FlyoutHelpers.Parent={Binding ElementName=CloudcardGrid} 25.04.2016
  • Уточните, пожалуйста, вы изменили тип с Button на ListView? 25.04.2016
  • К сожалению, ноутбук только что умер. Придется работать над другим и посмотреть на это позже, когда я его восстановлю. Вернется как можно скорее. Извиняюсь 25.04.2016
  • @LovetoCode Снова в деле :). В любом случае, хорошо подмечено, вы были на правильном пути. Я изменил всю кнопку на Listview, и код теперь работает, как и ожидалось, но у меня все еще есть проблема. Поскольку это просмотр списка, а не элемент списка, теперь он отображает мое всплывающее окно не в том месте, то есть поверх списка. Как я могу привязать его к фактическому элементу списка? Вместо этого я изменил его на Control, чтобы увидеть, могу ли я увидеть фактический передаваемый тип объекта, но он не привязан, так как я изменил свой FlyoutHelpers.Parent={Binding}, так как я не уверен, на что его установить. Любые идеи? 25.04.2016
  • Да, я заметил эту проблему, я свяжусь с вами, если найду решение 25.04.2016
  • То же самое. Еще раз спасибо всем за помощь! 25.04.2016
  • Пожалуйста, проверьте этот код, соответствует ли он вашим требованиям. private void Grid_Tapped (отправитель объекта, TappedRoutedEventArgs e) { ListViewItem item = (ListViewItem) MyListView.ContainerFromItem ((отправитель как Grid).DataContext); FlyoutHelpers.SetParent(FlyoutBase.GetAttachedFlyout(отправитель как Grid), элемент); FlyoutBase.ShowAttachedFlyout (отправитель в виде сетки); }. И я удалил настройку родителя в xaml 25.04.2016
  • @LovetoCode - Можете ли вы на самом деле опубликовать свой комментарий в качестве ответа, поскольку, чем больше я об этом думаю, это был ваш ответ, который решил проблему. Позиционирование хорошо, если оно каким-то образом решено, но вопрос был об использовании общего всплывающего окна между двумя элементами управления, которые вы разрешили. 26.04.2016
  • Вы имеете в виду последний комментарий? 26.04.2016
  • Нет, я имел в виду «Изменили ли вы тип родительского объекта attachProperty в FlyoutHelpers.cs с Button на ListView», поскольку это была исходная проблема. В итоге я изменил его на элемент управления, но это помогло мне использовать общий всплывающий элемент на основе предоставленного кода. 26.04.2016
  • Я думаю, это не возможно.. 26.04.2016
  • хорошо, достаточно справедливо. Это не конец света. Главное, что теперь у меня есть работающий общий Flyout. Как уже упоминалось, опубликуйте то, что я упомянул выше, и я приму это как ответ. Спасибо. 26.04.2016
  • Вместо этого вы можете использовать элемент управления PopUp. Он имеет свойство HorizontalOffset,VerticalOffset. Если вы заинтересованы в использовании, я могу поделиться подробностями 26.04.2016

Ответы:


1

Измените тип Parent с Button на ListView. Открыть всплывающее окно в определенной позиции X, Y невозможно в WP. Вместо этого вы можете выбрать элемент управления PopUp. Вот ссылка, которую я получил открыть всплывающее окно в нажатой позиции. Вы можете использовать VisualTreeHelper, чтобы получить управление всплывающим окном для элемента управления ListViewItem.

26.04.2016

2

Автор при использовании Windows 8.1 Управление всплывающим меню с помощью MVVM , автор использует родителя для управления тем, где появляется всплывающее окно. Итак, у автора есть коды, подобные приведенным ниже (FlyoutHelpers.cs):

private static void OnIsOpenPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var flyout = d as Flyout;
        var parent = (ListView)d.GetValue(ParentProperty);

        if (flyout != null && parent != null)
        {
            var newValue = (bool)e.NewValue;

            if (newValue)
              flyout.ShowAt(parent);
            else
              flyout.Hide();
        }
    }

Он использует flyout.ShowAt(parent), чтобы всплывающее окно отображалось на родительском элементе. Но в ваших кодах вы привязали всплывающее окно к кнопке, используя:

<Button Width="30" Height="30"
        Flyout="{StaticResource InfoFlyout}" content="i">
</Button>

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

private static void OnIsOpenPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        //var flyout = d as Flyout;
        //var parent = (ListView)d.GetValue(ParentProperty);

        //if (flyout != null && parent != null)
        //{
        //    var newValue = (bool)e.NewValue;

        //    if (newValue)
        //      flyout.ShowAt(parent);
        //    else
        //      flyout.Hide();
        //}
    }

Затем вы увидите всплывающие окна в нужном месте.

26.04.2016
  • Извините, но я одобрил это слишком быстро! Это позаботится о позиционировании при вызове с кнопки, но как насчет нажатия и удержания? Это запускает еще один фрагмент кода, который я добавлю в качестве обновления к моему вопросу, но могу ли я избавиться от него и использовать тот же метод, что и выше, если да, то как? Спасибо 26.04.2016
  • а как же тап и держи? В чем проблема? 26.04.2016
  • @LovetoCode Проверьте обновленный ответ. Я объясняю проблему там. Спасибо 26.04.2016
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..