2014-07-10 63 views
4

我想了解下面的簡化repro代碼幕後實際發生了什麼。瞭解WPF數據綁定和值轉換器交互

我有一個WindowListBoxTextBlock綁定在一起(即主 - >細節)。然後我有一個ViewModel與幾個屬性 - 一個字符串和一個日期。到目前爲止,我實現了一個值轉換器(LongDateConverter)。

我有一對夫婦在代碼Debug.WriteLine()調用,導致下面的輸出:

  • 啓動應用
    • In converter: ConverterProblem.MainWindowViewModel
    • In converter: null
  • 單擊兩個項目之一在列表框中
    • In converter: ConverterProblem.DataModel

第二和第三個電話給IValueConverter方法,我想我明白了。第二個是null,因爲ListBox還沒有選定的項目。第三個是我選擇的項目。

我不明白的是:

  1. 爲什麼是第一次調用傳遞MainWindowViewModel類型的值?
  2. 爲什麼這個電話甚至發生在第一位?

這裏是我的代碼:

MainWindow.xaml:

<Window x:Class="ConverterProblem.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:app="clr-namespace:ConverterProblem" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <app:LongDateConverter x:Key="longDateConverter"/> 
    </Window.Resources> 
    <StackPanel Orientation="Horizontal"> 
     <ListBox SelectedItem="{Binding Data}" ItemsSource="{Binding DataList}" 
       DisplayMemberPath="Name"/> 
     <TextBlock Text="{Binding Converter={StaticResource longDateConverter}}" 
        DataContext="{Binding Data}" /> 
    </StackPanel> 
</Window> 

MainWindow.xaml.cs:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Data; 

namespace ConverterProblem 
{ 
    public class LongDateConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      if (value == null) { 
       Debug.WriteLine("In converter: null"); 
       return "null"; 
      } 

      Debug.WriteLine("In converter: " + value.GetType().ToString()); 

      if (value.GetType() == typeof(MainWindowViewModel)) 
       return "viewmodel"; 

      return ((DataModel)value).Date.ToLongDateString(); 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      return null; 
     } 
    } 

    public class DataModel 
    { 
     public string Name { get; set; } 
     public DateTime Date { get; set; } 
    } 

    public class MainWindowViewModel : INotifyPropertyChanged 
    { 
     private DataModel _data; 
     private List<DataModel> _dataList; 

     public MainWindowViewModel() 
     { 
      _dataList = new List<DataModel> { 
       new DataModel { Date = DateTime.Now, Name = "John" }, 
       new DataModel { Date = DateTime.Now.AddDays(50), Name = "Sue" } 
      }; 
     } 

     public DataModel Data 
     { 
      get { return _data; } 
      set 
      { 
       if (_data == value) return; 

       _data = value; 
       RaisePropertyChanged("Data"); 
      } 
     } 

     public List<DataModel> DataList 
     { 
      get { return _dataList; } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     private void RaisePropertyChanged(string propertyName) 
     { 
      var handler = PropertyChanged; 
      if (handler != null) { 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    } 

    public partial class MainWindow : Window 
    { 
     private MainWindowViewModel _viewModel; 

     public MainWindow() 
     { 
      _viewModel = new MainWindowViewModel(); 
      DataContext = _viewModel; 
      InitializeComponent(); 
     } 
    } 
} 
+0

你,或你的自己的MVVM? – Darek

+0

@Darek,我自己的。我在香草WPF應用程序中共享的代碼就是它的全部內容。 – GusP

+0

如果沒有看到代碼就很難弄清楚。在第一次迭代中,轉換器需要接收MainWindowViewModel的原因一定是有原因的。你在任何地方分配數據上下文? – Darek

回答

7

的問題是你已經綁定Text依賴關係之前的設置DataContext for TextBlock。

XAML文件被編譯成BAML和應用程序運行,它是從BAML通過XAMLLoader加載它從上到下解析XAML和設定值DP的相應

因爲Text DP首先遇到,所以它會嘗試首先設置它的值,並且DataContext尚未設置爲TextBlock,因此它將從其父DataContext設置爲MainWindowViewModel的父窗口繼承。因此,您可以在轉換器中看到MainWindowViewModel。並且當DataContext被設置時,所有DP的綁定都將按照新的DataContext重新評估。


更換您的XAML來此,你會看到MainWindowViewModel將不再打印:

<TextBlock DataContext="{Binding Data}" 
      Text="{Binding Converter={StaticResource longDateConverter}}" /> 

輸出:使用MVVMLight

In converter: null 
In converter: ConverterProblem.DataModel 
+0

不知道元素中實際屬性的順序有所不同。非常感謝細節! – GusP