在 GridView DataTemplate 内的 ComboBox 中填充 ComboBox 项和 SelectedValue

Populate ComboBox items and SelectedValue in a ComboBox that is within a GridView DataTemplate

我正在开发一个 Windows 10 通用应用程序,但我无法将项目填充到 GridView DataTemplate 中的 ComboBox(ComboBox 项目和 SelectedValue)中。我似乎找不到办法做到这一点。

详情如下:

我有一个对象 (UserData),它可以包含另一个对象 (List<VisitedCity>) 的多个实例。在 XAML 页面上,VisitedCity 的多个实例显示在垂直的 GridView 上。

VisitedCity 的每个实例都可以包含 CityNameVisitedDate。在 XAML 页面上,CityName 将显示在 ComboBox 上,访问日期将显示在每个 GridViewItem 内 DatePicker 上的 Date 上。

什么不起作用:

显示每个 VisitedCity 的选定城市名称的 ComboBox 需要从 List<string> 变量加载其项目列表(以便用户可以更改它)并且需要加载 ComboBox SelectedValue来自 curretUserData 对象的 VisitedCities 属性 (CityName 属性).

我尝试在 XAML 上使用 x:Bind 来执行此操作,以尽量减少后面的代码。

我已经包含了我为解决此问题所做的示例应用程序中的所有代码,并且我还在 XAML 上指出了我遇到问题的代码行。

请注意,这是以 VisistedCities 为例的大型应用程序的高度简化部分,以便更好地演示问题。感谢您的所有帮助和意见!

这是我的 class 文件:

namespace mySampleApp
{
    class UserData
    {
        public string FullName { get; set; }
        public List<VisitedCity> VisitedCities { get; set; }
    }

    class VisitedCity
    {
        public string CityName { get; set; }
        public DateTime VisitedDate { get; set; }

    }

    class CityNameManager
    {
        public static List<string> GetListOfCitiesFromServer()
        {
            List<string> listOfCities = new List<string>();

            //code will be here to get the latest list from the server. for now we will manually return a list

            listOfCities.Add("City1");
            listOfCities.Add("City2");
            listOfCities.Add("City3");
            listOfCities.Add("City4");
            listOfCities.Add("City5");

            return listOfCities;

        }
    }
}

这是我的 XAML:

<Page
    x:Class="mySampleApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:mySampleApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

        <Grid.RowDefinitions>
            <RowDefinition  Height="Auto"/>
            <RowDefinition  Height="Auto"/>
            <RowDefinition  Height="Auto"/>
            <RowDefinition  Height="Auto"/>
            <RowDefinition  Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBox x:Name="txtFirstName" Grid.Row="0" Header="Enter Your Name" Text="{x:Bind curretUserData.FullName}"/>

        <TextBlock x:Name="label1" Grid.Row="1" TextWrapping="WrapWholeWords" Text="Please select all cities you have visited during the last 5 years. For each city please enter the data visited. If you visited a city multiple times, please have multiple entries for each time indicating the date visited each time." />

        <TextBlock x:Name="label2" Grid.Row="2" TextWrapping="WrapWholeWords" Text="Press the + button to add rows as needed. " />

        <Button x:Name="myButton" Grid.Row="3" Content="+" Click="myButton_Click" />

        <GridView x:Name="myGridView" Grid.Row="4" HorizontalContentAlignment="Stretch" SelectionMode="None" ItemsSource="{x:Bind curretUserData.VisitedCities}">
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsStackPanel Orientation="Vertical" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>

            <GridView.ItemContainerStyle>
                <Style TargetType="GridViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                    <Setter Property="HorizontalAlignment" Value="Stretch"/>
                </Style>
            </GridView.ItemContainerStyle>

            <GridView.ItemTemplate>
                <DataTemplate x:DataType="local:VisitedCity">
                    <Grid HorizontalAlignment="Stretch">

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

                        <!-- This is the line of code which has issues-->
                        <ComboBox Grid.Column="0" x:Name="myTemplateComboBox"  ItemsSource="{local:CityList ??? }" SelectedValue="{x:Bind CityName ??? }" HorizontalAlignment="Stretch"  />

                        <DatePicker Grid.Column="1" x:Name="myTemplateDatePicker" Date="{x:Bind VisitedDate }" />

                    </Grid>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>
</Page>

下面是我的代码:

namespace mySampleApp
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        //variables to use in XAML x:Bind
        private UserData curretUserData = new UserData();
        private List<string> CityList = new List<string>();

        public MainPage()
        {
            //get latest list of cities from the server
            CityList = CityNameManager.GetListOfCitiesFromServer();

            //add sample data to show on the page for demo
            curretUserData.FullName = "Sample User";
            List<VisitedCity> sampleUserVisitedCities = new List<VisitedCity>();
            sampleUserVisitedCities.Add(new VisitedCity {CityName = "City1", VisitedDate=DateTime.Parse("2/2/2016") });
            sampleUserVisitedCities.Add(new VisitedCity {CityName = "City2", VisitedDate = DateTime.Parse("2/2/2015") });
            curretUserData.VisitedCities = sampleUserVisitedCities;

            this.InitializeComponent();
        }

        private void myButton_Click(object sender, RoutedEventArgs e)
        {
            //add a new row
            GridViewItem gridViewItem = new GridViewItem();
            gridViewItem.ContentTemplate = myGridView.ItemTemplate;
            myGridView.Items.Add(gridViewItem);
        }
    }
}

您需要修改绑定表达式以从父页面抓取。 x:Bind 将仅使用本地 DataContext,在本例中为模板化项。

<ComboBox Grid.Column="0" x:Name="myTemplateComboBox"  ItemsSource="{Binding ElementName=MyPage, Path=CityList }" SelectedValue="{x:Bind CityName, Mode=TwoWay}" HorizontalAlignment="Stretch"  />

在这种情况下,我将 CityList 设为 public 属性,然后命名页面,以便我们可以使用 ElementName.

抓取它

您还需要启用 TwoWay 绑定,以便您可以在用户进行更改后将值设置回您的数据模型。

如果您使用 Observable 集合而不是 List,那么您可以通过修改您的数据模型来添加到您的 GridView 行。否则我遇到了异常。

我还换出了 PlaceholderText 的初始用户名,这样用户就不必为了键入他们的示例名称而擦除示例名称。

完整代码

<Page
    x:Class="SOCityGridView.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SOCityGridView"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="MyPage"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

        <Grid.RowDefinitions>
            <RowDefinition  Height="Auto"/>
            <RowDefinition  Height="Auto"/>
            <RowDefinition  Height="Auto"/>
            <RowDefinition  Height="Auto"/>
            <RowDefinition  Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBox x:Name="txtFirstName" Grid.Row="0" Header="Enter Your Name" Text="{x:Bind currentUserData.FullName}" PlaceholderText="Sample User"/>

        <TextBlock x:Name="label1" Grid.Row="1" TextWrapping="WrapWholeWords" Text="Please select all cities you have visited during the last 5 years. For each city please enter the data visited. If you visited a city multiple times, please have multiple entries for each time indicating the date visited each time." />

        <TextBlock x:Name="label2" Grid.Row="2" TextWrapping="WrapWholeWords" Text="Press the + button to add rows as needed. " />

        <Button x:Name="myButton" Grid.Row="3" Content="+" Click="myButton_Click" />

        <GridView x:Name="myGridView" Grid.Row="4" HorizontalContentAlignment="Stretch" SelectionMode="None" ItemsSource="{x:Bind currentUserData.VisitedCities}">
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsStackPanel Orientation="Vertical" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>

            <GridView.ItemContainerStyle>
                <Style TargetType="GridViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                    <Setter Property="HorizontalAlignment" Value="Stretch"/>
                </Style>
            </GridView.ItemContainerStyle>

            <GridView.ItemTemplate>
                <DataTemplate x:DataType="local:VisitedCity">
                    <Grid HorizontalAlignment="Stretch">

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

                        <!-- This is the line of code which has issues-->
                        <ComboBox Grid.Column="0" x:Name="myTemplateComboBox"  ItemsSource="{Binding ElementName=MyPage, Path=CityList }" SelectedValue="{x:Bind CityName, Mode=TwoWay}" HorizontalAlignment="Stretch"  />

                        <DatePicker Grid.Column="1" x:Name="myTemplateDatePicker" Date="{x:Bind VisitedDate, Mode=TwoWay}" />

                    </Grid>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>
</Page>

以及隐藏代码:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace SOCityGridView
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        //variables to use in XAML x:Bind
        private UserData currentUserData = new UserData();
        public List<string> CityList { get; set; } = new List<string>();

        public MainPage()
        {
            //get latest list of cities from the server
            CityList = CityNameManager.GetListOfCitiesFromServer();

            //add sample data to show on the page for demo
            List<VisitedCity> sampleUserVisitedCities = new List<VisitedCity>();
            sampleUserVisitedCities.Add(new VisitedCity { CityName = "City1", VisitedDate = DateTime.Parse("2/2/2016") });
            sampleUserVisitedCities.Add(new VisitedCity { CityName = "City2", VisitedDate = DateTime.Parse("2/2/2015") });
            currentUserData.VisitedCities = new ObservableCollection<VisitedCity>(sampleUserVisitedCities);

            this.InitializeComponent();
        }

        private void myButton_Click(object sender, RoutedEventArgs e)
        {
            currentUserData.VisitedCities.Add(new VisitedCity { CityName = "City1", VisitedDate = DateTime.Now });
        }
    }

    public class UserData
    {
        public string FullName { get; set; }
        public ObservableCollection<VisitedCity> VisitedCities { get; set; }
    }

    public class VisitedCity
    {
        public string CityName { get; set; }
        public DateTimeOffset VisitedDate { get; set; }

    }

    public class CityNameManager
    {
        public static List<string> GetListOfCitiesFromServer()
        {
            List<string> listOfCities = new List<string>();

            //code will be here to get the latest list from the server. for now we will manually return a list

            listOfCities.Add("City1");
            listOfCities.Add("City2");
            listOfCities.Add("City3");
            listOfCities.Add("City4");
            listOfCities.Add("City5");

            return listOfCities;

        }
    }
}