问题描述
我正在尝试使用数据绑定更改 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_Title
和 MovieModel.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>