【问题标题】:C# Databinding Textblock, PropertyChanged stays nullC# 数据绑定文本块,PropertyChanged 保持为空
【发布时间】:2021-06-11 08:33:38
【问题描述】:

我正在尝试使用数据绑定更改 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);
                }

            }
        }
    }
}


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

【问题讨论】:

  • 可以分享一下MovieProcessor的内容吗?

标签: c# visual-studio data-binding inotifypropertychanged propertychanged


【解决方案1】:

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

而不是在代码后面使用StaticResource movieModel assing DataContext

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

Xaml

<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>;
        ... 
    }
}

【讨论】:

  • 感谢您的回答,但在后面的代码(数据上下文)中添加一些东西不是我想要的。我知道在后面的代码中现在有 2 个事件,但我会在解决这个问题后移动它们。正如您所提到的,StaticResource movieModel 不是 datacontext 的替代品吗?我在我的问题中添加了来自电影处理器的代码,我在加载数据时设置了 original_title 和 overview。
【解决方案2】:

我将命令绑定到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>

【讨论】:

    猜你喜欢
    • 2018-11-19
    • 2020-05-11
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    • 2015-09-08
    • 2023-03-07
    • 1970-01-01
    • 2013-11-08
    相关资源
    最近更新 更多