1

我正在使用 MVVM 模式开发我的第一个 WP7.1 应用程序。(这是我关于stackoverflow的第一个问题!)

在其中一个屏幕中,我使用“添加信息”按钮收集付款信息,例如付款说明(文本框)、付款方式/类型(工具包:ListPicker)、付款到期日(工具包:DatePicker)等。这被包装在一个 ListBox 中。

<ListBox x:Name="AddPayListBox" ItemsSource="{Binding NewPaymentsInfo}" SelectedItem="{Binding NewPayInfo}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBox x:Name="DescInput" Text="{Binding PayDesc, Mode=TwoWay}"/>
                    <toolkit:ListPicker x:Name="TypeInput" Header="Mode:" CacheMode="BitmapCache"
                            ItemsSource="{Binding DataContext.PayTypesList}"
                            SelectedItem="{Binding DataContext.SelectedPayTypesList, Mode=TwoWay}">
                        <toolkit:ListPicker.ItemTemplate>
                            <DataTemplate>
                                 <TextBlock Text="{Binding Path=PayTypesList.PayTypeDesc}"/>
                            </DataTemplate>
                        </toolkit:ListPicker.ItemTemplate>
                    </toolkit:ListPicker>
                    <toolkit:DatePicker x:Name="DateInput" Value="{Binding DueDate, Mode=TwoWay}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
        <Button x:Name="btnAddPay" Content="Add" Command="{Binding AddCommand}" />
    </StackPanel>

我的模型(实现 INotifyPropertyChanged)有一个类 PaymentInfo 映射到这个屏幕。我的 ViewModel 有一个ObservableCollection<PaymentInfo> NewPaymentsInfo属性。

Screen 的 DataContext 设置为 VM,ListBox Binding 设置为与另一个对象的NewPaymentsInfo集合。SelectedItemPaymentInfoNewPayInfo

ListPicker 从PayTypeModel 中的另一个类获取其数据(支付模式,如现金、卡等),该类填充在 VM Constructor 中。

我的问题是 ListPicker 在屏幕上仍然是空的。如果我<ListPickerItem>用来填充 ListPicker,那么它可以工作。(这是一种解决方法,因为付款模式是预定义的;但是,我想ItemSource在运行时获取数据)。

我搜索了很多,但无法正确获取 ListPicker 的绑定。我试过了,RelativeSource但没有运气。非常需要您的专家帮助。如果需要更多信息,请告诉我。

谢谢!


更新:

这是模型:

    public class PaymentInfo : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private string _PayDesc;
    public string PayDesc
    {
        get { return _PayDesc; }
        set
        {
            _PayDesc = value;
            RaisePropertyChanged("PayDesc");
        }
    }

    private byte _PayType;
    public byte PayType
    {
        get { return _PayType; }
        set
        {
            _PayType = value;
            RaisePropertyChanged("PayType");
        }
    }

    private DateTime _DueDate;
    public DateTime DueDate
    {
        get { return _DueDate; }
        set
        {
            _DueDate = value;
            RaisePropertyChanged("DueDate");
        }
    }
}

public class SupportedPayTypes : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private byte _PayTypeIdx;
    public byte PayTypeIdx
    {
        get { return _PayTypeIdx; }
        set
        {
            _PayTypeIdx = value;
            RaisePropertyChanged("PayTypeIdx");
        }
    }

    private string _PayTypeDesc;
    public string PayTypeDesc
    {
        get { return _PayTypeDesc; }
        set
        {
            _PayTypeDesc = value;
            RaisePropertyChanged("PayTypeDesc");
        }
    }
}

这是 ViewModel:(不包括 AddCommand,因为该部分工作正常)

    public class PaymentViewModel
{
    public ObservableCollection<PaymentInfo> NewPaymentsInfo { get; set; }
    public PaymentInfo NewPayInfo;

    public ICommand AddCommand { get; set; }

    public ObservableCollection<SupportedPayTypes> PayTypesList;
    public SupportedPayTypes SelectedPayTypesList;

    public PaymentViewModel()
    {
        AddCommand = new DelegateCommand<PaymentSetup>(AddAction);

        PayTypesList = new ObservableCollection<SupportedPayTypes>();
        PayTypesList.Add(new SupportedPayTypes() { PayTypeIdx = 0, PayTypeDesc = "Cash" });
        PayTypesList.Add(new SupportedPayTypes() { PayTypeIdx = 1, PayTypeDesc = "Credit Card" });

        //SelectedPayTypesList = PayTypesList[0];
        SelectedPayTypesList = new SupportedPayTypes();
        SelectedPayTypesList.PayTypeIdx = PayTypesList[0].PayTypeIdx;
        SelectedPayTypesList.PayTypeDesc = PayTypesList[0].PayTypeDesc;

        NewPaymentsInfo = new ObservableCollection<PaymentInfo>();
        NewPayInfo = new PaymentInfo();
        NewPayInfo.PayDesc = "";
        NewPayInfo.PayType = SelectedPayTypesList.PayTypeIdx;
        NewPayInfo.DueDate = DateTime.Now;
        NewPaymentsInfo.Add(NewPayInfo);
    }
}

最后,这是MainPage.xaml.cs我正在使用 Pivot 的 NB MainPivot,有问题的屏幕是AddView

public partial class MainPage : PhoneApplicationPage
{
    private PaymentViewModel vm;

    public MainPage()
    {
        InitializeComponent();
        vm = new PaymentViewModel();
    }

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        AddView.DataContext = vm;
        MainPivot.SelectedIndex = 1;
    }
}

如果您发现任何遗漏,请告诉我?我已经走到尽头了:)

谢谢你!

4

1 回答 1

0

是的,所以您假设您需要RelativeSource绑定才能访问您的PayTypesList收藏是正确的。RelativeSource允许您向上走可视化树并绑定到任何父元素。在这种情况下,我建议您走到ListBox,然后使用它DataContext来访问PaymentViewModel.

帮自己一个忙,下载Snoop,它将允许您在运行时查看应用程序的可视化树,并帮助选择适当的目标元素进行绑定。

ListPicker 上的 ItemsSource 绑定变为:

ItemsSource="{Binding Path=DataContext.PayTypesList, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"

这告诉绑定继续向上遍历可视化树,直到找到第一个UIElement类型ListBox,然后将其用作绑定的目标。您当然会想要一个类似的绑定来SelectedItem使用该SelectedPayTypesList属性。

编辑:顺便说一句,我认为你会希望SelectedPayType成为模型的成员,PaymentInfo而不是PaymentViewModel. 我假设您希望 ListBox 中的每个项目都有自己的选择!

于 2013-10-20T22:52:03.400 回答