我正在构建一个小型的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
。
此外,在运行应用程序时,“输出”窗口中没有显示任何“绑定错误”。
有什么建议吗?
答案 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
,则只需要调用它如果用另一个列表替换当前列表。