2014-09-10 70 views
0

我的问题是,即使在触发PropertyChanged时UI也不会更新。 XAML:WPF与Notifyi的绑定不会更新UI

<ListBox Name="BookShelf" Visibility="Hidden" SelectedItem="{Binding SelectedItem}" Panel.ZIndex="1" Height="Auto" Grid.Column="3" Margin="8,50,0,0" HorizontalAlignment="Center" ItemsSource="{Binding BookShelf}" Background="Transparent" Foreground="Transparent" BorderThickness="0" BorderBrush="#00000000"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <StackPanel VerticalAlignment="Center" Orientation="Vertical"> 
         <TextBlock FontSize="14" Margin="0,10,0,0" FontWeight="Bold" Foreground="Black" HorizontalAlignment="Center" Text="{Binding Path=DbId}" /> 
         <TextBlock FontSize="16" FontWeight="Bold" Width="170" TextWrapping="Wrap" Foreground="Black" Margin="5" HorizontalAlignment="Center" Text="{Binding Path=DisplayName}" /> 
         <Image HorizontalAlignment="Center" Source="{Binding Path=bookImage}" Width="200" Height="200" Margin="0,0,0,10" /> 
        </StackPanel> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 

和:

<ComboBox Margin="8,15,0,0" Name="bookShelf_ComboBox" ItemsSource="{Binding BookShelf}"  SelectedItem="{Binding SelectedItem}" VerticalAlignment="Center" HorizontalAlignment="Center" DisplayMemberPath="DisplayName" Height="22" Width="140" Visibility="Visible" SelectionChanged="bookShelf_ComboBox_SelectionChanged"/> 

视图模型:

public class BookShelfViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    public event ShowContentInBrowser ShowDatabaseContent; 

    public BookShelfViewModel(ShowContentInBrowser showMethod) 
    { 
     ShowDatabaseContent += showMethod; 
    } 
    private ObservableCollection<DbInfo> _BookShelf = new ObservableCollection<DbInfo>(); 
    public ObservableCollection<DbInfo> BookShelf 
    { 
     get 
     { 
      if (_BookShelf == null) 
       _BookShelf = new ObservableCollection<DbInfo>(); 
      return _BookShelf; 
     } 
     set 
     { 
      if (value != _BookShelf) 
       _BookShelf = value; 
     } 
    } 
    private DbInfo _selectedItem { get; set; } 
    public DbInfo SelectedItem 
    { 
     get 
     { 
      return _selectedItem; 
     } 
     set 
     { 
      if (_selectedItem != value) 
      { 
       _selectedItem = value; 
       RaisePropertyChanged(new PropertyChangedEventArgs("SelectedItem")); 
       if (_selectedItem == null) 
        return; 
       if (_selectedItem.RelatedId != null) 
        ShowDatabaseContent(_selectedItem, _selectedItem.RelatedId); 
       else 
        ShowDatabaseContent(_selectedItem, _selectedItem.RelatedId); 

      } 
     } 
    } 
    public void RaisePropertyChanged(PropertyChangedEventArgs e) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, e); 
    } 
} 

这段代码我使用的是设置的DataContext和的SelectedItem:

await System.Windows.Application.Current.Dispatcher.BeginInvoke(
     DispatcherPriority.Background, new Action(
       () => this.BookShelf.SelectedItem = dbInfo 
     ) 
    ); 

而且DataContext的:

await System.Windows.Application.Current.Dispatcher.BeginInvoke(
     DispatcherPriority.Background, new Action(
       () => this.BookShelf.DataContext = bookShelfViewModel 
     ) 
     ); 

我对这个MVVM设计非常新的,至于我可以从我看过的文章说,我找不到什么是错的。我猜,使用Dispatcher是没有必要的,但我不认为在这种情况下,重要的... ListBox中确实显示出我的对象,但更新的SelectedItem是这里的问题...

UPDATE:

我的继承人为DBINFO代码:

public class DbInfo 
{ 
    public int RelatedId { get; set; } 
    public string DbId { get; set; } 
    public TBase3.Article currentArticle { get; set; } 
    public string LinkId { get; set; } 
    public bool IsArticle { get; set; } 
    public string folder { get; set; } 
    public bool IsNamedArticle { get; set; } 
    public int currentBlockIndex { get; set; } 
    public int currentBlockCount { get; set; } 
    public string DisplayName { get; set; } 
    public int VScrollPos { get; set; } 
    public int THTextVersion { get; set; } 
    public bool isHtmlToc { get; set; } 
    public ImageSource bookImage { get; set; } 
} 

提醒,当过我的视图模型设置新的价值 - >的SelectedItem和它去的PropertyChanged(这一点,E);线。它不会将DbInfo选为ListBox中的Selected。

UPDATE2:

我得到了我的窗口右侧的书籍列表,就像它书架很多书。 它显示所有书籍滚动。选择其内容正在窗口中显示的书。 但如果我之所以想换到另一本书从代码隐藏,它更新其内容,web浏览器,但不更新列表框,某些本书的SelectedItem

答案: 好吧,我找到了答案现在。其中设置BookShelf.SelectedItem = dbInfo的代码应该是bookShelfViewModel.SelectedItem = bookShelfViewModel.BookShelf.First(x => x.DbId == dbInfo.DbIf);

+1

您是否检查XAML上的绑定模式?如果从视图更新两个视图模型并从视图模型更新视图,您将希望使用双向模式 – aggietech 2014-09-10 20:32:38

+1

@aggietech您的意思是SelectedItem绑定?该属性默认绑定双向。 – Clemens 2014-09-10 20:39:03

+0

bookShelf_ComboBox_SelectionChanged没有发射任何东西吗?你试图让“SelectionChanged”事件在你的视图模型中触发一个命令? – aggietech 2014-09-10 20:40:52

回答

0

好吧,我找到了答案现在。其中设置BookShelf.SelectedItem = dbInfo的代码应该是bookShelfViewModel.SelectedItem = bookShelfViewModel.BookShelf.First(x => x.DbId == dbInfo.DbIf);

1
await System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => this.BookShelf.DataContext = bookShelfViewModel)); 

这看起来不太好,你在哪里做这个?我建议使用Galasoft MVVM Light以及ViewModelLocator的用法来设置DataContext(通过nuget提供)。它为您提供了一个ViewModelBase,其中包含所有属性已更改的需求和作品,您可以根据需要进行扩展。这听起来像DataContext,如果PropertyChanged没有被引发,可能是实际的问题。

编辑:

As pointed out by Clemens the Mode=TwoWay in the binding is not needed here,因为它是为SelectedItem属性的默认反正,我只是把它作为一个例子....

<ComboBox Margin="8,15,0,0" Name="bookShelf_ComboBox" ItemsSource="{Binding BookShelf}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" VerticalAlignment="Center" HorizontalAlignment="Center" DisplayMemberPath="DisplayName" Height="22" Width="140" Visibility="Visible"> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="SelectionChanged"> 
      <command:EventToCommand Command="{Binding SelectedItemChangedCommand}" PassEventArgsToCommand="True"/> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</ComboBox> 

我注意到你的SelectionChanged =“bookShelf_ComboBox_SelectionChanged”的代码,这是“讨厌”,使用事件,而不是命令,因为你是你绑视图模型,以你的意见CBOX。上面的代码将执行一个包含参数的命令,将以下内容添加到您的视图模型中。

public ICommand SelectedItemChangedCommand{ get; set;} 

// somewhere in your code.. 
SelectedItemChangedCommand = new RelayCommand<SelectedItemChangedCommand>(OnSelectedItemChanged); 

protected void OnSelectedItemChanged(SelectedItemChangedCommand e) 
{ 
    // Do your magic here! Or why not just call this method from the setter of your bound property? 
} 

The WPF Cheat Sheet是所有类型的绑定的一个不错的紧凑列表,这是非常方便的,我曾经有过它无论是在墙上和家庭,当我学习WPF :)

希望它帮助

干杯

了Stian

+1

默认情况下不是WPF TwoWay绑定? Silverlight是OneWay - 已经让我绊倒了很多次...总之最安全的方法是总是明确地指定它 – sondergard 2014-09-10 21:11:31

+0

@sondergard没有默认是OneWay,就像SL =) – 2014-09-10 21:18:03

+3

@Stian。这是错误的。默认情况下,某些依赖项属性双向绑定。例如SelectedItem可以。请参阅* Dependency Property Information * [here](http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.selector.selecteditem.aspx)。 – Clemens 2014-09-10 21:18:15

0

你的意思是由UI什么不更新?你设置了一个新的ItemsSource并没有看到任何更改?

,如果是这样的话改变你的物业

public ObservableCollection<DbInfo> BookShelf 
{ 
    get 
    { 
     if (_BookShelf == null) 
      _BookShelf = new ObservableCollection<DbInfo>(); 
     return _BookShelf; 
    } 
    set 
    { 
     if (value != _BookShelf) 
     { _BookShelf = value; 
      RaisePropertyChanged(new PropertyChangedEventArgs("BookShelf")); 
     } 
    } 

顺便说一句,我使用的ObservableCollection以另一种方式。我只是初始化一次,并使用清除,添加,删除。

如果的ItemsSource是不是你的问题请发布守则DBINFO,并写信给你更多的东西“UI不更新”的问题

+0

列表框显示我的ObservableCollection 有每个项目,但它没有选择该项目作为在列表框中选择什么是BookShelfViewModel.SelectedItem的值。除非我在ListBox中单击Item,否则它只会被选中,而不会代码隐藏 – 2014-09-11 07:41:01