在StackPanel中绑定到属性不起作用

本文关键字:属性 不起作用 绑定 StackPanel | 更新日期: 2023-09-27 17:52:12

我正在构建一个Windows 8小应用程序,经过几个小时的绞尽脑汁,我不明白为什么我的绑定不能工作。我有这个ViewModel:

public class DetailsViewModel : ViewModelBase
{
    private BookDataService _bookDataService;
    private ObservableCollection<Book> _authorsBooks;
    public ObservableCollection<Book> AuthorsBooks
    {
        get
        {
            return _authorsBooks;
        }
            set
        {
            _authorsBooks = value;
            OnPropertyChanged("AuthorsBooks");
        }
    }
    private string _bookTitle;
    public string BookTitle
    {
        get
        {
            return _bookTitle;
        }
        set
        {
            _bookTitle = value;
            OnPropertyChanged("BookTitle");
        }
    }

    public DetailsViewModel()
    {
        _authorsBooks = new ObservableCollection<Book>();
    }
    public async Task GetBookDetails(string bookID)
    {
        _bookDataService = new BookDataService();
        var remoteResults = await _bookDataService.GetBookDetailsAsync(bookID);
        _bookTitle = remoteResults.Title;
    }
    public async Task GetAuthorBooks(string authorID)
    {
        _bookDataService = new BookDataService();
        var remoteResults = await _bookDataService.GetAuthorBooksAsync(authorID);
        foreach (var book in remoteResults)
            _authorsBooks.Add(book);
    }
}

这是StackPanel的XAML:

<StackPanel x:Name="BookDetailsStackPanel" 
            Grid.Row="0" 
            Orientation="Horizontal" 
            DataContext="{Binding DetailsViewModel}">
    <Image Source="{Binding LargeImage}" 
           Width="200" Height="300" 
           VerticalAlignment="Top" 
           HorizontalAlignment="Left"  
           Margin="24"/>
    <StackPanel Orientation="Vertical">
        <TextBlock Margin="24" Text="{Binding BookTitle}" Foreground="Black"/>
        <TextBlock Margin="24" Text="{Binding Author.Name}" Foreground="Black"/>
        <TextBlock Margin="24" Foreground="Black">
            <Run Text="{Binding Rating}"/>
            <Run Text="("/>
            <Run Text="{Binding RatingsCount}"/>
            <Run Text=")"/>
        </TextBlock>
    </StackPanel>
</StackPanel>

我在代码后面初始化ViewModel并获得数据:

private DetailsViewModel _detailsViewModel = new DetailsViewModel();
public DetailsViewModel DetailsViewModel
{
    get { return this._detailsViewModel; }
}
async void DetailsPage_Loaded(object sender, RoutedEventArgs e)
{
    BookDetailsProgressRing.IsActive = true;
    await _detailsViewModel.GetBookDetails(_bookID);
    BookDetailsProgressRing.IsActive = false;
}

显然,我只是在谈论BookTitle属性,一旦我知道我的代码出了什么问题,我就会设置其他属性。

经过几个小时的调试,我可以肯定地说,BookTitle被设置为正确的值,但它只是不绑定到TextBlock。此外,我在同一页上有一个ListView,它绑定到AuthorsBooks属性,它工作得很好,所以我认为我的问题是StackPanel

同时,当运行应用程序时,没有任何绑定错误显示在输出窗口。

有什么建议吗?

在StackPanel中绑定到属性不起作用

我刚刚遇到了一个类似的问题-在更新ObservableCollection后无法获得属性更改。参考在Windows Phone开发中心的Windows Phone应用程序中实现模型-视图-视图模式的教程,我将PropertyChangedEventHandler和RaisePropertyChanged事件添加到类中,它工作了!见下文:

public class ActivityLog : INotifyPropertyChanged
{
    public string strLogID { get; set; } //unique id for the log entry.
    private string _strLogDate;
    public string strLogDate
    {
        get
        {
            return _strLogDate;
        }
        set
        {
            _strLogDate = value;
            RaisePropertyChanged("strLogDate");
        }
    }
    public bool booIsUploaded { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

就像Mathew在评论中说的,你直接更新字段_bookTitle,而不是通过它的属性设置器,所以PropertyChanged事件,假设"告诉"你的文本块更新永远不会引发。

这在所有与作者相关的事情中起作用的原因是因为使用了ObservableCollection。绑定的工作方式是必须引发一个事件,列出相关的属性名称,通知相关的UIElement进行更新。在大多数情况下,当我们为属性设置一个新值时,这个值就会累积,这就是为什么在那里放置OnPropertyChanged调用非常常见的原因。但是对于列表,情况就有点不同了,因为我们不仅要知道什么时候给整个列表设置了一个新值,还要知道列表中的项什么时候被添加或删除了。ObservableCollection就是这样做的,每次添加或删除一个项目时,它都会引发一个事件(如果你不愿意,你甚至可以注册到这个事件)。

回到您的代码,现在您知道了,看看Get方法之间的关键区别。GetBookDetails直接更新_bookTitle,因此没有事件被引发,你的TextBlock没有理由知道它需要更新它的值。在GetAuthorBooks中,你也直接处理_authorsBooks,但你不改变它的值,只是简单地添加项目,现在就像上一个例子一样,你的OnPropertyChanged方法永远不会被调用,但是ObservableCollection在添加项目时引发它自己的事件,因此告诉相关的UIElement更新。

事实上,如果你只打算从你的ObservableCollection中添加或删除项目,而不改变它的值,你甚至不需要在setter中调用OnPropertyChanged,只有当你用一个不同的列表替换当前列表时,你才需要调用它