簡體   English   中英

當使用MVVM將事件綁定到ListView ItemsSource生成的元素時,如何修復“對象引用未設置為對象實例。”

[英]How to fix “Object reference not set to an instance of object.” when binding an event to an element generated by ListView ItemsSource when using MVVM?

我有一個ListView,其ItemsSource設置為一種Movies集合(帶有Movie對象)。 然后在里面我有一個包含ComboBox和TextBlock的DataTemplate。 在ComboBox上,我將Selected項目綁定到Movie對象包含的進度(劇集)。 這里我使用普通的“綁定”方法。 但是當我想將方法​​綁定到“DropDownClosed”事件時,問題就出現了。 這在使用Code Behind時工作正常,但使用ViewModel和x:綁定它給了我“對象引用未設置為對象的實例”。 在構建我的應用程序時

目標是綁定到ViewModel中的方法,而不是沒有錯誤的Code Behind。

當我拿走“DropDownClosed”活動時,一切順利。 沒有其他事件可以更好地運作。

<ListView ItemsSource="{x:Bind ViewModel.MovieLibrary}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Spacing="20" Orientation="Horizontal">
                <ComboBox SelectedItem="{Binding Progress}"
                                          ItemsSource="{Binding Media.Episodes, Converter={StaticResource NumberToArrayConverter}}"
                                          DropDownClosed="{x:Bind ViewModel.UpdateStuff}">
                </ComboBox>
                <TextBlock Text="{Binding Media.Title}" TextWrapping="Wrap" />
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

而這一點,但是如果它是空的那么這就好了,如果這是必要的(從視圖模型):

public void UpdateStuff(object sender, object e)
        {
            //blabla not important
        }

問題是我不能使用x:任何屬性都綁定。

要在DataTemplate中使用x:Bind,必須在DataTemplate中指定x:DataType =“local:Movie”。 然后,x:在模板中綁定的路徑應該相對於Movie對象。

“未設置對象引用”僅表示您尚未分配指針。 也許ViewModel為null或ViewModel.UpdateStuff為null。

我試着用一個小例子向你展示一個解決方案。 你會看到一些事情發生了變化。 我希望它仍然符合您的需求:

    <ListView ItemsSource="{Binding MovieLibrary}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <ComboBox  ItemsSource="{Binding Episodes}" 
                               SelectedItem="{Binding Progress}" >
                    </ComboBox>
                    <TextBlock Text="{Binding Title}" TextWrapping="Wrap" />
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

這是一個示例視圖模型:

public class MainWindowModel
{
    public MainWindowModel()
    {
        MovieLibrary = new ObservableCollection<Media>();

        //
        //Exmaple Fill
        //
        var m1 = new Media() { Title = "Breaking Bad", Episodes = new List<string> { "1", "2", "3", "4", "5", "6" } };
        var m2 = new Media() { Title = "The Big Bang Theory", Episodes = new List<string> { "1", "2", "3" } };
        m1.MediaChangedAction += OnMediaChanged;
        m2.MediaChangedAction += OnMediaChanged;
        MovieLibrary.Add(m1);
        MovieLibrary.Add(m2);
    }
    public ObservableCollection<Media> MovieLibrary { get; set; }

    private void OnMediaChanged(Media movie)
    {
        // do something
    }

}

public class Media
{
    public event Action<Media> MediaChangedAction;

    public Media()
    {
    }

    public string Title { get; set; }
    public List<string> Episodes { get; set; }


    private string _progress;
    public string Progress
    {
        get { return _progress; }
        set
        {
            _progress = value;
            MediaChangedAction?.Invoke(this);
        }
    }
}

你看我把它簡化了一點(沒有轉換器等)。 “事件”也移動到視圖模型。 至於我的優點是,它現在不依賴於調用事件的視圖,它只是視圖模型的重要。 因此,如果您使用不同的視圖來顯示媒體,它仍然可以正常工作。

我也遠離了“雙向”的東西,因為目前沒有必要從視圖模型發送到視圖。 如果需要,“Media”將需要實現INotifyPropertyChanged。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM