2016-08-15 3 views
1

私は何か問題を診断しているという問題が発生しています。私のDependency Propertyがビューモデルにnullを送信するのはなぜですか?

データグリッドのさまざまな選択項目にバインドできるようにカスタムのDataGridオブジェクト(Sandeshの回答hereで詳しく説明)を作成しました。ただし、DependecyProperty自体が選択が変更されたときに正しい値を取得しているように見えても、ビューモデルは更新された値を受け取っていないようです(代わりにnullが返されます)。

カスタムDataGridクラス:

class CustomDataGrid : DataGrid 
{ 
    public CustomDataGrid() 
    { 
     this.SelectionChanged += CustomDataGrid_SelectionChanged; 
    } 

    void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     this.SelectedItemsList = this.SelectedItems; 
    } 
    #region SelectedItemsList 

    // In the setter, the value is a valid List with the correct elements. 
    // For some reason it doesn't seem to be passed on to the view model. 
    public IList SelectedItemsList 
    { 
     get { return (IList)GetValue(SelectedItemsListProperty); } 
     set { SetValue(SelectedItemsListProperty, value); } 
    } 

    public static readonly DependencyProperty SelectedItemsListProperty = 
      DependencyProperty.Register("SelectedItemsList", typeof(IList), typeof(CustomDataGrid), new PropertyMetadata(OnSelectedItemsListChanged)); 

    private static void OnSelectedItemsListChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
    { 
     System.Diagnostics.Debug.WriteLine("Test"); 
    } 

    #endregion 
} 

XAMLファイル:

<Window x:Class="Test.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:Test" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.DataContext> 
     <local:TestViewModel /> 
    </Window.DataContext> 
    <Grid> 
     <local:CustomDataGrid AutoGenerateColumns="True" 
           SelectionMode="Extended" 
           SelectionUnit="FullRow" 
           CanUserAddRows="False" 
           CanUserDeleteRows="False" 
           CanUserResizeRows="False" 
           ItemsSource="{Binding TestModels}" 
           SelectedItemsList="{Binding Path=SelectedTestModels, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />  
    </Grid> 
</Window> 

ビューモデル:

class TestViewModel : INotifyPropertyChanged 
{ 
    public TestViewModel() 
    { 
     TestModels = new List<TestModel> 
     { 
      new TestModel { Name = "Test 1", ID = 1 }, 
      new TestModel { Name = "Test 2", ID = 2 }, 
      new TestModel { Name = "Test 3", ID = 3 }, 
     }; 
    } 

    private IEnumerable<TestModel> _testModels; 

    public IEnumerable<TestModel> TestModels 
    { 
     get { return _testModels; } 
     set 
     { 
      _testModels = value; 
      OnPropertyChanged(); 
     } 
    } 

    private IEnumerable<TestModel> _selectedTestModels; 

    public IEnumerable<TestModel> SelectedTestModels 
    { 
     get { return _selectedTestModels; } 
     set 
     { 
      // Right here I would expect value to have a non-null value... but it's always null 
      _selectedTestModels = value; 
      OnPropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     var propChanged = PropertyChanged; 
     if (propChanged != null) 
      propChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

TestModelクラス(非常に単純なPOCO):

class TestModel 
{ 
    public string Name { get; set; } 
    public int ID { get; set; } 
} 
+0

Visual Studioの出力ウィンドウにバインディングエラーメッセージはありますか? 'IList'は' IEnumerable 'に/から割り当てられないかもしれません。 – Clemens

+0

出力ウィンドウに表示されるエラーメッセージは、バインディングなどではありません。さらに、ビューモデルの 'TestModels'と' SelectedTestModels'の型を 'IList 'に変更すると、まだnull値が送られてきます。 –

答えて

1

汎用でないIListとIListを同じ意味で使用しています。あなたにはいくつかの選択肢があります。

ビューモデルでは、プロパティと項目をIListに変更できます。

private IList _selectedTestModels; 

public IList SelectedTestModels 
{ 
    get { return _selectedTestModels; } 
    set 
    { 
     _selectedTestModels = value; 
     OnPropertyChanged(); 
    } 
} 

また、CustomControlでは、

public static readonly DependencyProperty SelectedItemsListProperty = DependencyProperty.Register("SelectedItemsList", typeof(IList<TestModel>), typeof(CustomDataGrid)); 

public IList<TestModel> SelectedItemsList 
{ 
    get { return (IList<TestModel>)GetValue(SelectedItemsListProperty); } 
    set { SetValue(SelectedItemsListProperty, value); } 
} 

void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    SetCurrentValue(SelectedItemsListProperty, SelectedItems.OfType<TestModel>().ToList()); 
} 

このメモのコードは、あなたの拘束力を損なう可能性があると私は考えています。

void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    this.SelectedItemsList = this.SelectedItems; 
} 

バインディングを維持するためにSetCurrentValueを試してみてください。

void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    SetCurrentValue(SelectedItemsListProperty, SelectedItems); 
} 
+0

申し訳ありませんが、それは何もしなかったように見えません。ビューモデルはまだnullを受け取ります。 –

+0

私はそれがあなたのバインディングだとは思わない、私はあなたのIListはCustomControlでnullだと思う。あなたのSelectionChangedイベントの終わりにブレークポイントと次のコードを入れてみてください。SelectedItemsListもnullだと思います。 var test = SelectedItemsList; –

+0

あなたは正しいです。 'SelectedItems'が有効でデータが入っていても、' this.SelectedItemsList = this.SelectedItems'呼び出しを行った後にその行を追加すると、 'SelectedItemsList'はヌルです。私はそれをどうやって解決しますか? –

関連する問題