将共享弹出窗口绑定到UWP Windows 10中Listview的DataTemplate中的2个控件

时间:2016-04-24 22:28:58

标签: xaml win-universal-app dependency-properties windows-10-universal

我的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错误,所以我使用了本文中的代码(Using Windows 8.1 Flyout control with 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}"

我已经在我的setter和getter上为IsOpen属性添加了断点,当页面被加载时,它会进入getter,但每当我通过FlyoutHolding打开或关闭private static void OnIsOpenPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) as defined in the FlyoutHelper class. 时通过按“i”按钮,它不会触发下面的方法,因此它不会更改IsOpen属性。

ElementName

我将ListViewItem设置为MyListView的原因是我想要将所有ListViewItem绑定到一个属性,即IsOpen,因为我需要检测每当弹出菜单打开时无关紧要它属于<Flyout x:Name="InfoFlyout" helpers:FlyoutHelpers.Parent="{Binding ElementName=MyListView}" helpers:FlyoutHelpers.IsOpen="{Binding IsOpen, Mode=TwoWay}">

我如何实现或解决这个问题?

更新 - 1

使用以下方法解决了访问共享菜单的问题:

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

并将按钮设置为

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

这很好,正如@ElvisXia所提到的,你可以注释掉OnIsOpenPropertyChanged中的代码,因为定位已经由我的ListViewItem中的按钮确定。

然而,有一个突出的问题。一个小的顺便说一句,但如果它可以解决好。共享的弹出窗口,它附加在DataTemplate中的网格本身,即

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

基于ListViewItem的定位在技术上是正确的,因为我正在为那个代码调用另一段代码,即

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的定义如下:

OpenFlyoutAction

我可以以某种方式停止使用Flyout并使用文章中提供的相同代码打开我的ListViewItem,无论用户在相关的ListViewItem上握住他/她的手指而不是在实际var id = 81; var categories = [1, 2, 3, 4, 5]; var arr = []; for (var i = 0; i < categories.length; i++) { arr.push({id: id, category: categories[i]}); } 之上或之下?

我理解这是原始问题的一个侧面轨道,即分享Flyout by到控件,但也可以完成它,因为它与问题有某种关系。

感谢。

2 个答案:

答案 0 :(得分:0)

通过Using Windows 8.1 Flyout control with 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)让flyout显示在父元素上。但是在您的代码中,您已使用以下命令将弹出窗口绑定到按钮:

<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();
        //}
    }

然后你会看到弹出窗口显示在正确的位置。

答案 1 :(得分:0)

将父类型从Button更改为ListView。要打开弹出特别是X,在WP中无法进行Y位置。您可以选择PopUp控件。这是我得到open the pop up in tapped position的链接。您可以使用VisualTreeHelper来获取Tapped ListViewItem的PopUp控件