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

时间:2014-03-22 19:52:05

标签: c# xaml windows-8.1

我正在构建一个小型的Windows 8应用程序,经过几个小时的敲打,无法弄清楚为什么我的Binding无法正常工作。我有这个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

此外,在运行应用程序时,“输出”窗口中没有显示任何“绑定错误”。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

我只是遇到了类似的问题 - 在更新ObservableCollection后无法更改属性。回到Windows Phone开发中心的教程Implementing the Model-View-ViewModel pattern in a Windows Phone app,我将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));
        }
    }
}

答案 1 :(得分:0)

就像Mathew在评论中所说,你是直接更新字段_bookTitle而不是通过其属性设置器更新,因此假设“告诉”你的文本块更新的PropertyChanged事件永远不会被提出。

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

回到你的代码,现在你知道了,看看你的Get方法之间的关键差异。 GetBookDetails直接更新_bookTitle因此不会引发任何事件,而TextBlock无法知道需要更新的是值。 在GetAuthorBooks中,您还可以直接处理_authorsBooks,但您不会更改值,只需添加项目,现在就像最后一种情况一样,您的OnPropertyChanged方法永远不会被调用,但是ObservableCollection在添加项目时引发它自己的事件,因此告诉相关的UIElement更新。

事实上,如果您只打算在ObservableCollection中添加或删除项目而不更改值,您甚至无需在设置器中调用OnPropertyChanged,则只需要调用它如果用另一个列表替换当前列表。