2013-10-19 3 views
1

MVVM 패턴을 사용하여 내 첫 WP7.1 App을 개발 중입니다. (그리고 이것은 stackoverflow에 대한 나의 첫 번째 질문입니다!)DataBound Listbox의 ListPicker에 대한 DataContext 문제

화면 중 하나에서 지불 설명 (텍스트 상자), 지불 모드/유형 (툴킷 : 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 속성이 있습니다.

화면의의 DataContext는 VM로 설정하고 목록 상자는 다른 PaymentInfo 객체 NewPayInfoSelectedItem으로 NewPaymentsInfo 컬렉션에 설정되어있는 바인딩.

ListPicker는 VM 생성자로 채워진 Model의 다른 클래스 PayType에서 데이터 (현금, 카드 등의 지불 모드)를 가져옵니다.

제 문제는 ListPicker가 화면에 비어있는 것입니다. <ListPickerItem>을 사용하여 ListPicker를 채우면 작동합니다 (이는 지불 모드가 사전 정의되었으므로 해결 방법이지만 런타임에 ItemSource의 데이터를 가져오고 싶습니다).

많이 검색했지만 ListPicker 바인딩의 바인딩을 가져올 수 없습니다. 나는 RelativeSource와 함께 시험해 보았지만 행운은 없었다. 전문가의 도움이 많이 필요합니다. 더 많은 정보가 필요한지 알려주십시오.

감사합니다. UPDATE


: (그 부분은 잘 작동으로 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); 
    } 
} 

가 여기에있다 :

여기
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"); 
     } 
    } 
} 

는 뷰 모델입니다 : 여기

는 모델의 MainPage.xaml.cs 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; 
    } 
} 

누락 아무것도 찾을 수 있으면 알려 주시기 바랍니다인가? 나는 이미 내 순발력의 끝에 도달했습니다.

Thank You!

+0

안녕하세요. SO! 위대한 첫 번째 질문. ViewModel의 생성자에서 NewPaymentsInfo를 인스턴스화하고 있습니까? 그렇지 않은 경우 인스턴스화 된 후에 속성 변경 알림을 실행해야합니다. 모델/ViewModel에 대한 코드를 게시 할 수 있습니다. – ChrisO

+0

@ChrisO - Thanks! 예, VM 생성자에서'NewPaymentsInfo'를 인스턴스화합니다. 곧 Model/VM 코드를 게시하고 더 자세히 설명하려고합니다. – NP3

답변

0

PayTypesList 컬렉션을 얻으려면 RelativeSource 바인딩이 필요하다고 가정하면 정확합니다. RelativeSource을 사용하면 시각적 트리를 탐색하여 상위 요소에 바인딩 할 수 있습니다. 이 경우 ListBox까지 걸어 가서 DataContext을 사용하여 PaymentViewModel에 액세스하는 것이 좋습니다.

Snoop을 다운로드하면 런타임에 응용 프로그램의 시각적 트리를 볼 수 있고 바인딩에 적합한 대상 요소를 선택할 수 있습니다.

ItemsSource는 ListPicker에 바인딩이된다 :이이 유형 ListBox의 첫 번째 UIElement을 찾을 때까지 시각적 트리를 통과 유지하는 바인딩 다음의 타겟으로서 사용하기 말하고있다

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

바인딩. 물론 SelectedPayTypesList 속성을 사용하여 SelectedItem에 대한 유사한 바인딩을 원할 것입니다.

편집 : 덧붙여서 SelectedPayTypePaymentViewModel이 아닌 PaymentInfo 모델의 멤버가되고 싶습니다. ListBox의 각 항목마다 고유 한 선택 항목이 필요하다고 가정합니다.

+0

글쎄,이 시도했지만 AncestorType 지원되지 않는 오류가 발생합니다. Silverlight 및 WP에서는 지원되지 않습니다! 여기를 봐 [여기] (http://stackoverflow.com/questions/15233072/windowsphone-relativesource-mode-findancestor-ancestortype-cannotresolve-sy) – NP3

+0

아,이 경우 http : // stackoverflow에 도움이 될 수 있습니다. .com/questions/2291310/silverlight-4- -relativesource-findancestor-binding/8564277 # 8564277 몇 가지 해결 방법이있는 것으로 보입니다. 미안 해요, 난별로 도움이 될 수 없어, WPF와 실버 라이트를 사용합니다. – ChrisO

+0

ChrisO에게 감사드립니다. 내일 귀하의 링크를 살펴보고 업데이트를 게시하겠습니다. – NP3