ListView绑定到一个集合,如何访问父类中的事件?

Posted

技术标签:

【中文标题】ListView绑定到一个集合,如何访问父类中的事件?【英文标题】:ListView binds to a collection, how to access an event in a parent class? 【发布时间】:2017-07-01 15:40:57 【问题描述】:

在我的 WinRT 项目中,我有一个 ListView,如下所示;

<ListView Grid.Row="1"
    ItemsSource="Binding Path=Survey.SelectedSection.QuestionsAndNavigation, Mode=TwoWay"
    IsSwipeEnabled="False"
    SelectionMode="None"
    ScrollViewer.VerticalScrollBarVisibility="Auto"
    Background="White"
    ItemTemplateSelector="StaticResource ResourceKey=QuestionDisplay"
    ItemContainerStyle=
        "StaticResource ResourceKey=QuestionListViewItemContainerStyle">
</ListView>

注意这一行; ItemsSource="绑定路径=Survey.SelectedSection.QuestionsAndNavigation" 集合 QuestionsAndNavigation 以 UserControl 中的一些导航按钮结尾;

<StackPanel Orientation="Horizontal" >
    <Button Margin="0,40,40,0"
        IsEnabled="Binding Path=PreviousSectionId, Converter=StaticResource ResourceKey=IntBooleanConverter"
        Command="Binding Path=NavigateToPreviousSectionCommand">&lt;&lt; Save and Previous Section</Button>
    <Button Margin="0,40,0,0"
            IsEnabled="Binding Path=NextSectionId, Converter=StaticResource ResourceKey=IntBooleanConverter"
            Command="Binding Path=NavigateToNextSectionCommand">Save and Next Section &gt;&gt;</Button>
</StackPanel>

并显示如下;

现在的问题是在绑定路径中:Survey.SelectedSection.QuestionsAndNavigation 我希望该命令位于伟大的 GrandParent 类 SurveyPageViewModel(其中包含调查对象)中,而不是嵌入集合类 QuestionsAndNavigation 中。默认情况下,数据上下文在错误的类中查找。 重要的是要认识到这不是继承。此处的“Survey”映射到 SurveyPageViewModel 类,该类包含映射到 SurveyViewModel 类的 Survey,映射到 SectionViewModel 类的 SelectedSection,并且包含 QuestionsAndNavigation,它是 QuestionViewModel 类的集合。

所以 QuestionViewModel 中的代码:

private void NavigateToNextSection()

    NavigateToSection(this.NextSectionId);


private void NavigateToPreviousSection()

    NavigateToSection(this.PreviousSectionId);


private void NavigateToSection(int sectionId)

    NavService.Navigate("NewSection", sectionId);

没有转到 SurveyPageViewModel,我无法在 QuestionViewModel 类中设置 NavService,因为它不存在,而是 SurveyPageViewModel 中的一个属性。

编辑。 所以感谢 Eric 的回答,我的 ListView 包含一个 x:Name = "ListResponses"。我在按钮的路径中使用它:

<StackPanel Orientation="Horizontal" >
    <Button Margin="0,40,40,0"
        IsEnabled="Binding Path=PreviousSectionId, 
            Converter=StaticResource ResourceKey=IntBooleanConverter"
        Command="Binding 
            Path=DataContext.SaveThenPreviousSectionCommand,
            ElementName=ListResponses">&lt;&lt; Previous Section</Button>
    <Button Margin="0,40,0,0"
            IsEnabled="Binding Path=NextSectionId, 
                Converter=StaticResource ResourceKey=IntBooleanConverter"
            Command="Binding  
                Path=DataContext.SaveThenNextSectionCommand,
                ElementName=ListResponses">Next Section &gt;&gt;</Button>
</StackPanel>

我已将事件连接放在 SurveyPageViewModel 中,但由于某种我想知道答案的原因,它们没有连接起来;

public ICommand SaveThenPreviousSectionCommand  get; private set; 
public ICommand SaveThenNextSectionCommand  get; private set; 

... (在构造函数中)

SaveThenPreviousSectionCommand = new DelegateCommand(DoSaveThenPreviousSection);
        SaveThenNextSectionCommand = new DelegateCommand(DoSaveThenNextSection);

...

   private async void DoSaveThenPreviousSection()
    
        var i = 1;
    

    private async void DoSaveThenNextSection()
    
        var i = 0;
    

编辑:这是页面的完整 XAML 文件

<prism:VisualStateAwarePage x:Class="M.Survey.Views.SurveyPage"

                            x:Name="pageRoot"
                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                            xmlns:views="using:M.Survey.Views"
                            xmlns:local="using:M.Survey"
                            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                            xmlns:prism="using:Microsoft.Practices.Prism.StoreApps"
                            xmlns:mvvm="using:Microsoft.Practices.Prism.Mvvm"
                            mvvm:ViewModelLocator.AutoWireViewModel="true"
                            xmlns:userControls="using:M.Survey.UserControls"
                            mc:Ignorable="d"
                            xmlns:converters="using:M.Survey.Converters"
                            Loaded="pageRoot_Loaded"
                            Unloaded="pageRoot_Unloaded"
                            xmlns:templateSelectors="using:M.Survey.TemplateSelectors">

    <prism:VisualStateAwarePage.Resources>

        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Themes/AllQuestionDataTemplates.xaml" />
                <ResourceDictionary Source="/Themes/Styles.xaml" />
                <ResourceDictionary Source="/Themes/DataTemplates.xaml" />
            </ResourceDictionary.MergedDictionaries>

            <templateSelectors:QuestionTemplateSelector x:Key="QuestionDisplay"
                TextEntry="StaticResource TextEntry"
                DateTimeEntry="StaticResource DateTimeEntry"
                BoolEntry="StaticResource BoolEntry"
                IntEntry="StaticResource IntEntry"
                SelectEntry="StaticResource SelectEntry"
                DecimalEntry="StaticResource DecimalEntry"
                LargeTextArea="StaticResource LargeTextArea"
                SorEntry="StaticResource SorEntry"
                Additional="StaticResource AdditionalEntry"
                Miscellaneous="StaticResource Miscellaneous"
                Dim="StaticResource Dim"
                Signature="StaticResource Signature"
                SectionNavigation="StaticResource SectionNavigation"/>

            <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
            <converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />

        </ResourceDictionary>

    </prism:VisualStateAwarePage.Resources>

    <Grid>
        <Grid.Background>
            <SolidColorBrush Color="StaticResource ResourceKey=AppBackgroundColor" />
        </Grid.Background>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="80" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>

            <Grid Grid.Row="0" Background="StaticResource ResourceKey=MulalleyBlueBrush">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>

                <StackPanel Orientation="Horizontal" Margin="20, 0, 0, 5">
                    <Button Margin="0, 0, 15, 0" Command="Binding Path=TryGoHomeCommand" Style="StaticResource BackButtonStyle" />
                    <TextBlock Style="StaticResource ResourceKey=MediumHeaderTextBlockStyle" Text="Binding Path=Job.ShortDisplayAddress" VerticalAlignment="Bottom" />

                    <StackPanel Margin="40, 0, 0, 6" Width="30" VerticalAlignment="Bottom" Height="30">
                        <ProgressRing Height="30" Width="30" Foreground="White" IsActive="Binding Path=WorkInProgress" Visibility="Binding Path=WorkInProgress, Converter=StaticResource ResourceKey=BooleanToVisibilityConverter" />
                    </StackPanel>
                    <TextBlock Margin="10, 0, 0, 10" VerticalAlignment="Bottom" Text="Binding Path=FeedbackMsg" Style="StaticResource ResourceKey=SmallHeaderTextBlockStyle" />

                </StackPanel>

                <Grid Margin="0, 0, 15, 5" Grid.Column="1" VerticalAlignment="Bottom">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>

                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>

                        <TextBlock VerticalAlignment="Bottom" Text="Internet" Style="StaticResource ResourceKey=MediumHeaderTextBlockStyle" />
                        <TextBlock Margin="10, 0, 15, 6" VerticalAlignment="Bottom" Grid.Column="1" Text="Binding Path=ConnectionStatus" Style="StaticResource ResourceKey=SmallHeaderStyle" />

                        <TextBlock VerticalAlignment="Bottom" Text="Server" Style="StaticResource ResourceKey=MediumHeaderTextBlockStyle" Grid.Column="2" />
                        <TextBlock Margin="10, 0, 15, 6" VerticalAlignment="Bottom" Grid.Column="3" Text="Binding Path=***Status" Style="StaticResource ResourceKey=SmallHeaderStyle" />

                        <TextBlock VerticalAlignment="Bottom" Text="User" Style="StaticResource ResourceKey=MediumHeaderTextBlockStyle" Grid.Column="4" />
                        <TextBlock Margin="10, 0, 0, 6" VerticalAlignment="Bottom" Grid.Column="5" Text="Binding Path=User.DisplayName" Style="StaticResource ResourceKey=SmallHeaderStyle" />
                    </Grid>

                    <TextBlock Width="80" Margin="100, 0, 30, 0" Text="Binding Path=AnswersCompleteDisplay" Grid.Column="1" Style="StaticResource ResourceKey=MediumHeaderTextBlockStyle"/>

                    <Button Style="StaticResource ResourceKey=SaveButtonStyle" Content="Save" Grid.Column="2" Command="Binding Path=SaveCommand"  />
                </Grid>
            </Grid>

            <Grid Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="2*" />
                </Grid.ColumnDefinitions>

                <Grid>
                    <Grid.Background>
                        <SolidColorBrush Color="StaticResource ResourceKey=MulalleyBlue" Opacity=".2" />
                    </Grid.Background>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <ListView
                        ItemsSource="Binding Path=Survey.Sections, Mode=TwoWay"
                            SelectedItem="Binding Path=Survey.SelectedSection, Mode=TwoWay"
                            IsSwipeEnabled="False"
                            SelectionMode="Single"
                            ItemContainerStyle="StaticResource ResourceKey=ListViewItemContainerStyle"
                            ItemTemplate="StaticResource ResourceKey=SurveySectionDataTemplate"
                            ScrollViewer.HorizontalScrollBarVisibility="Hidden"
                            ScrollViewer.VerticalScrollBarVisibility="Auto"
                            />
                </Grid>

                <Grid Grid.Column="1" Margin="30, 30, 15, 20">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <StackPanel Grid.Row="0" Orientation="Horizontal">
                            <TextBlock Text="*" FontSize="40" FontWeight="Bold" Foreground="Red"/>
                            <TextBlock Text=" = Required " FontSize="20"/>
                        </StackPanel>
                        <ListView 
                            x:Name="ListResponses"
                            Grid.Row="1"
                            ItemsSource="Binding Path=Survey.SelectedSection.QuestionsAndNavigation, Mode=TwoWay"
                            IsSwipeEnabled="False"
                            SelectionMode="None"
                            ScrollViewer.VerticalScrollBarVisibility="Auto"
                            Background="White"
                            ItemTemplateSelector="StaticResource ResourceKey=QuestionDisplay"
                            ItemContainerStyle=
                                "StaticResource ResourceKey=QuestionListViewItemContainerStyle">
                        </ListView>
                    </Grid>
                </Grid>
            </Grid>
        </Grid>

        <userControls:SurveyDialogUserControl />
        <userControls:SurveyReassignedDialogUserControl />
        <userControls:CopyFromUserControl />

    </Grid>

    <prism:VisualStateAwarePage.BottomAppBar>
        <CommandBar Name="commandBar">
            <CommandBar.SecondaryCommands>
                <AppBarButton Label="Settings" Icon="Setting" Click="AppBarButton_Click" />
                <AppBarButton Label="Log" Icon="Admin" Click="LogButton_Click" />
                <AppBarButton Label="Refresh" Icon="Refresh" Command="Binding Path=RefershAllDataCommand" IsEnabled="Binding Path=WorkInProgress, Converter=StaticResource ResourceKey=InverseBooleanConverter" Visibility="Binding Path=***Online, Converter=StaticResource ResourceKey=BooleanToVisibilityConverter" />
                <AppBarButton Label="Copy From" Icon="Copy" Click="CopyButton_Click" Command="Binding Path=ShowCopyFromCommand" IsEnabled="Binding Path=WorkInProgress, Converter=StaticResource ResourceKey=InverseBooleanConverter" />
            </CommandBar.SecondaryCommands>
        </CommandBar>
    </prism:VisualStateAwarePage.BottomAppBar>


</prism:VisualStateAwarePage>

这是用户控件 XAML;

<UserControl
    x:Class="M.Survey.UserControls.SectionNavigation"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:M.Survey.UserControls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:converters="using:M.Survey.Converters"
    mc:Ignorable="d"
    d:DesignHeight="30"
    d:DesignWidth="400">
    <UserControl.Resources>
        <ResourceDictionary>
            <converters:IntBooleanConverter x:Key="IntBooleanConverter" />
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>

        <StackPanel Orientation="Horizontal" >
            <Button Margin="0,40,40,0"
                IsEnabled="Binding Path=PreviousSectionId, 
                    Converter=StaticResource ResourceKey=IntBooleanConverter"
                Command="Binding 
                    Path=DataContext.SaveThenPreviousSectionCommand,
                    ElementName=ListResponses">&lt;&lt; Previous Section</Button>
            <Button Margin="0,40,0,0"
                    IsEnabled="Binding Path=NextSectionId, 
                        Converter=StaticResource ResourceKey=IntBooleanConverter"
                    Command="Binding  
                        Path=DataContext.SaveThenNextSectionCommand,
                        ElementName=ListResponses">Next Section &gt;&gt;</Button>
        </StackPanel>

    </Grid>
</UserControl>

【问题讨论】:

【参考方案1】:

假设 ListView XAML 与 Button XAML 位于同一文件中(并且 ListView 为 x:Name="listView"):

<Button Margin="0,40,0,0"
        IsEnabled="Binding Path=NextSectionId, Converter=StaticResource ResourceKey=IntBooleanConverter"
        Command="Binding ElementName=listView, Path=DataContext.Survey.DESIRED_COMMAND">Save and Next Section &gt;&gt;</Button>

此外,您还可以在实例化时将调查视图模型的实例传递给问题视图模型(取决于您创建视图模型的方式)。

最后,您还可以使用事件发布系统(例如 MVVM Light Messenger)在单击调查连接以响应的按钮时发布事件。

【讨论】:

我确信您的回答是正确的,但我无法将其连接起来。当我单击按钮时,没有任何反应。顺便说一句,我对 ViewModel 树的看法是错误的。 SurveyPageViewModel 包含 1 个 SurveyViewModel,其中包含 1 个 SelectedSection,其中包含 QuestionViewModel 对象的集合。命令事件在 SurveyPageViewModel 类上。所以对我来说有意义的是,在识别 ListView 的名称时,然后在按钮“Path=DataContext.DESIRED_COMMAND”中。 Button 位于 UserControl 文件中,而不是与 LIstView 位于同一文件中。是这个问题吗? 顺便将 SurveyPageViewModel 的引用传递给 QuestionViewModel 会创建一个循环引用,所以我认为这行不通。而且我不熟悉 MVVM Light Messenger。我查了一下,但对我来说看起来很复杂(我是 XAML 新手) 我已经更新了我的答案,所以你可以看到我做了什么。 您能否发布完整的 XAML 文件,以便我查看哪些项目在彼此的范围内? 好的。我曾认为 ListView 和按钮在同一范围内(或至少是文件)。 XAML ElementName 绑定不起作用。我最好的建议是使用像 MVVM Light Messenger 类 (msdn.microsoft.com/en-us/magazine/jj694937.aspx) 这样的 pub sub。【参考方案2】:

我从 Eric 那里得到了很多帮助,他给出了另一个答案。 为了在嵌入在它们自己的复杂设计中的 2 个类之间进行通信,一种方法是使用 EventAggregator 模式。碰巧我正在开发的应用程序使用 Prism,它是 EventAggregator 自己的实现。此模式使您能够发布有效负载,该有效负载由接收类上的订阅事件拾取。

【讨论】:

以上是关于ListView绑定到一个集合,如何访问父类中的事件?的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin Forms ListView 绑定到 Observable 集合中的子对象列表

如何访问父类中的标签表单用户控件?

继承&构造函数

如何将通用项目添加到绑定到 WPF 中的集合的 ComboBox

java基础疑难点总结之成员变量的继承,方法重载与重写的区别,多态与动态绑定

在 Xamarin 表单中将 Observable 集合绑定到我的 ListView 时遇到问题