C# 数据绑定文本块,PropertyChanged 保持为 null

问题描述

我正在尝试使用数据绑定更改 2 个文本块。 propertyChanged 始终为 null,因此 ui 不会更新。

这是我的模型代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MovieApp.Models
{
    public class MovieModel : INotifyPropertyChanged
    {
        string original_title,overview;
        public event PropertyChangedEventHandler PropertyChanged;

        public string Original_Title {
            get
            {
                return original_title;
            }
            set
            {
                original_title = value;
                onPropertyChanged(nameof(Original_Title));
            } 
        }
        public string Overview
        {
            get
            {
                return overview;
            }
            set
            {
                overview = value;
                onPropertyChanged(nameof(Overview));
            }
        }
        protected void onPropertyChanged(string propertyName)
        {
            if(PropertyChanged != null)
            {
                PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
            }
            //PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
        }

    }
}

mainview.xaml.cs:

using MovieApp.API;
using MovieApp.Models;
using MovieApp.Processor;
using System.Windows;

namespace MovieApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        //private readonly MovieModel movieModel = new MovieModel(); 

        public MainWindow()
        {
            InitializeComponent();
            ApiCaller.InitializeClient();
            // DataContext = movieModel;
        }

        private async void prevIoUsImageButton_Click(object sender,RoutedEventArgs e)
        {
            int id = 484718;
            await MovieProcessor.LoadMovie(id);
       
        }

        private async void nextimageButton_Click(object sender,RoutedEventArgs e)
        {
            int id = 527774;
            await MovieProcessor.LoadMovie(id);
           
        }
    }
}


和 maindwindow.xaml:

<Window x:Class="MovieApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MovieApp.Models"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <local:MovieModel x:Key="movieModel" />
    </Window.Resources>
    
    <Grid>

        <Grid.RowDeFinitions>
            <RowDeFinition Height="*" />
            <RowDeFinition Height="*" />
            <RowDeFinition Height="*" />
        </Grid.RowDeFinitions>
        
        <Button x:Name="prevIoUsImageButton" Padding="15" Margin="15" Click="prevIoUsImageButton_Click">PrevIoUs</Button>
        <StackPanel Grid.Row="1">
            <TextBlock Text="{Binding  Source={StaticResource movieModel},Path=Original_Title}"  ></TextBlock>
            <TextBlock Text="{Binding  Source={StaticResource movieModel},Path=Overview }"></TextBlock>
        </StackPanel>
        <Button Grid.Row="2" x:Name="nextimageButton" Padding="15" Margin="15" Click="nextimageButton_Click">Next</Button>
    </Grid>
</Window>

编辑: 添加了电影处理器代码

using MovieApp.API;
using MovieApp.Models;
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace MovieApp.Processor
{
    class MovieProcessor    
    {
        public static async Task<MovieModel> LoadMovie(int id)
        {
            
            string url = $"movie/{id}?api_key=77e7d2ef687aedca2119680778f1d619&language=en-US";
            using (HttpResponseMessage response = await ApiCaller.httpClient.GetAsync(url))
            {
                if (response.IsSuccessstatusCode)
                {
                    MovieModel movie = await response.Content.ReadAsAsync<MovieModel>();
                    Console.WriteLine(movie.Original_Title);
                    Console.WriteLine(movie.Overview);
                    return movie;
                }
                else
                {
                    throw new Exception(response.ReasonPhrase);
                }

            }
        }
    }
}


我不知道哪里出了问题。我尝试了多种方法,但似乎没有什么对我有用。我尝试添加数据上下文,但这也不起作用。我让它在我的代码中注释,以便任何人都可以看到它。

解决方法

如果您的 MovieProcess 类设置了 MovieModel.Original_TitleMovieModel.Overview 属性的值,那么您必须确保 MovieProcess 正在访问与 MovieModel 相同的实例您的视图 (xaml)。

而不是在后面的代码中使用 StaticResource movieModel 赋值 DataContext

private readonly MovieModel movieModel = new MovieModel(); 
public MovieProcessor MovieProcessor { get; set; }
public MainWindow()
{
    InitializeComponent();
    ApiCaller.InitializeClient();
    DataContext = movieModel;
    MovieProcessor = new MoviewProcessor(moviewModel);
}

XML

<StackPanel Grid.Row="1">
    <TextBlock Text="{Binding Original_Title}" />
    <TextBlock Text="{Binding Overview }" />
</StackPanel>

MovieProcessor 类

public class MovieProcessor
{
    private readonly MovieModel movieModel;
    public MovieProcessor(MovieModel movieModel)
    {
        this.movieModel = movieModel;
    }

    public async Task LoadMovie(int id)
    {
        ...
        movieModel.Original_Title = <loaded_movie_title>;
        movieModel.Overview = <loaded_movie_overview>;
        ... 
    }
}
,

我将命令绑定到 MovieProcessor 中的按钮以使用 StaticResource movieModel 在 Maindwindow 中显示数据,以下是我的代码:

NotifyObject.cs

 public class NotifyObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChange(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
        }
    }
}

MyCommand.cs

public class MyCommand : ICommand
{
    private Func<object,bool> _canExecute;
    private Action<object> _execute;

    public event EventHandler CanExecuteChanged
    {
        add
        {
            if (_canExecute != null)
            {
                CommandManager.RequerySuggested += value;
            }
        }
        remove
        {
            if (_canExecute != null)
            {
                CommandManager.RequerySuggested -= value;
            }
        }
    }


    public bool CanExecute(object parameter)
    {
        if (_canExecute == null) return true;
        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        if (_execute != null && CanExecute(parameter))
        {
            _execute(parameter);
        }
    }

    public MyCommand(Action<object> execute) : this(execute,null)
    {
    }
    public MyCommand(Action<object> execute,Func<object,bool> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }
}

MovieProcessor.cs

 public class MovieProcessor:NotifyObject
{       
    private MovieModel vm;
    public MovieModel VM
    {
        get { return vm; }
        set
        {
            vm = value;
            OnPropertyChange("VM");
        }
    }
    public MovieModel LoadMovie(int id)
    {
        //....
    }


    private MyCommand _cmd1;
    public MyCommand Cmd1
    {
        get
        {
            if (_cmd1 == null)
                _cmd1 = new MyCommand(new Action<object>
                (
                    o =>
                    {
                        int id = 484718;
                        LoadMovie(id);
                    }
                ));
            return _cmd1;
        }
    }

    private MyCommand _cmd2;
    public MyCommand Cmd2
    {
        get
        {
            if (_cmd2 == null)
                _cmd2 = new MyCommand(new Action<object>
                (
                    o =>
                    {
                        int id = 527774;
                        LoadMovie(id);
                    }
                ));
            return _cmd2;
        }
    }
}

MainWindow.xaml

   <Window.Resources>
    <local:MovieProcessor x:Key="movieModel" />
</Window.Resources>
<Grid >

    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <Button x:Name="previousImageButton" Padding="15" Margin="15" Command="{Binding Source={StaticResource movieModel},Path=Cmd1}">Previous</Button>
    <StackPanel Grid.Row="1">
        <TextBlock Text="{Binding  Source={StaticResource movieModel},Path=VM.Original_Title}"  ></TextBlock>
        <TextBlock Text="{Binding  Source={StaticResource movieModel},Path=VM.Overview }"></TextBlock>
    </StackPanel>

    <Button Grid.Row="2" x:Name="nextImageButton" Padding="15" Margin="15" Command="{Binding Source={StaticResource movieModel},Path=Cmd2}">Next</Button>

</Grid>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...