DataContext为DataBound列表框中的ListPicker发出问题

时间:2013-10-19 12:55:27

标签: xaml windows-phone-7 mvvm binding listpicker

我正在使用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>

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

屏幕的DataContext设置为VM,ListBox Binding设置为NewPaymentsInfo集合,SelectedItem集合到另一个PaymentInfo对象NewPayInfo

ListPicker从Model中的另一个类PayType获取其数据(支付模式,如Cash,Card等),该类填充在VM Constructor中。

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

我搜索了很多但是无法获得ListPicker的Bindings。我试过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 N.B.我正在使用Pivot 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;
    }
}

如果发现任何遗失,请告诉我?我已经到了我的智慧结束:)

谢谢!

1 个答案:

答案 0 :(得分: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中的每个项目都有自己的选择!