【问题标题】:Bind ObservableCollection using MVVM使用 MVVM 绑定 ObservableCollection
【发布时间】:2014-02-14 23:56:54
【问题描述】:

我正在尝试将应该是一个非常基本的 MVVM 示例放在一起,但我无法让它工作。基本上,我想将ObservableCollection 绑定到ListBox,并为用户提供搜索选项以搜索其他项目。搜索时,ListBox 应该被刷新,因为集合会改变。这是我的代码:

型号:

public class Item
   public string Name { get; set; }
}

视图模型:

public class ViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Item> _items { get; set; }
    public ObservableCollection<Item> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            RaisePropertyChanged("Items");
        }
    }

    public void GetDefaultItems()
    {
        ObservableCollection<Item> temp = new ObservableCollection<Item>();
        temp.Add(new Item() { Name = "abc" + " 1" });
        temp.Add(new Item() { Name = "def" + " 2" });
        temp.Add(new Item() { Name = "ghi" + " 3" });
        Items = temp;
    }


    public void Search(string query)
    {
       ObservableCollection<Item> temp = new ObservableCollection<Item>();
       temp.Add(new Item() { Name = query + " 1" });
       temp.Add(new Item() { Name = query + " 2" });
       temp.Add(new Item() { Name = query + " 3" });
       Items = temp;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

查看:

<Grid x:Name="LayoutRoot">
    <ListBox ItemsSource="{Binding}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock x:Name="Name" Text="{Binding Name}" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

MainPage.xaml:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <StackPanel>
        <TextBox x:Name="txtSearch"/>
        <TextBlock Text="Items:" />
        <views:ItemView x:Name="ItemsOnPage" />
    </StackPanel>
</Grid>

最后是 MainPage.xaml.cs:

public partial class MainPage : PhoneApplicationPage
{
    private ViewModel vm;

    // Constructor
    public MainPage()
    {
        InitializeComponent();
        txtSearch.KeyUp += txtSearch_KeyUp;
        vm = new ViewModel();
    }

    void txtSearch_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            vm.Search(txtSearch.Text);
        }
    }

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        vm.GetDefaultItems();
        ItemsOnPage.DataContext = vm.Items;
    }
}

所以发生的情况是,我可以看到第一次加载默认项目,但是当我搜索时,列表没有刷新。它现在都是硬编码的,所以如果搜索确实有效我应该看到 3 个项目,无论他们搜索什么。

我注意到的是,如果我在 ViewModel 中的 RaisePropertyChanged 处设置断点,this.PropertyChanged总是为空,因此它永远不会在 if 语句中出现.我已经看到在模型上使用INotifyPropertyChanged 的示例,但在这种情况下,由于我需要在集合更改时收到通知,因此在视图模型上使用似乎是正确的。这可能是错误的,但我不确定如何设置它。

谁能看出我做错了什么?

【问题讨论】:

  • 尝试将 ItemsOnPage.DataContext = vm.Items; 放入 MainPage 构造函数中。
  • 所以只是将它从OnNavigatedTo 移到构造函数中?我刚才试过了,没什么区别。
  • 也许你需要为windows-phone-8 举办一些其他活动
  • 我实现 Xamarin 表单视图模型的好例子

标签: c# mvvm windows-phone-8 observablecollection


【解决方案1】:

尝试这样做

  1. 将 ItemSource 设置为 Items

  2. 清除并添加数据项

    String preQuery="";
    public void Search(string query)
    {
       if(preQuery==query)
          return;
    
       Items.Clear();
    
       Items.Add(new Item() { Name = query + " 1" });
       Items.Add(new Item() { Name = query + " 2" });
       Items.Add(new Item() { Name = query + " 3" }); 
    }
    

希望这会有所帮助。

【讨论】:

  • 哇,好用。不过,我现在注意到我在RaisedPropertyChanged 内的断点没有被命中,但值仍然正确更新。这应该发生吗?
  • 我的意思是我什至需要为此实现INotifyPropertyChanged 吗?从页面上的项目列表中,用户将无法编辑它们,因此我不需要重新绑定其他方式。对于每个列表项,我唯一需要做的就是为它们提供一个事件处理程序,例如,点击一个可以将您带到不同的页面。
  • @lhan16 在这种情况下,从技术上讲,您不需要实现 INotifyPropertyChanged。那是因为ObservableCollection 实现了INotifyCollectionChanged,它会在您添加、清除等时通知视图。
【解决方案2】:

UI 上似乎没有刷新项目集合的值。

试试这个-

MainPage.cs中的代码

   private ViewModel _viewModel;

MainPage 构造函数

  _viewModel = new ViewModel();
  this.DataContext = _viewModel ;

MainPage 中的绑定XAML

<views:ItemView x:Name="ItemsOnPage" DataContext="{Binding Path=Items,UpdateSourceTrigger=PropertyChanged}"/>

【讨论】:

  • 谢谢。我今晚会试试这个。不过有一个问题,如果我将绑定移动到 MainPage.xaml,我在 View.xaml 中的 ListBox 是否应该有 any 绑定(TextBlock 中的 Name 除外)?跨度>
  • @lhan16:我认为应该没有问题,你可以将它与你想要的任何属性绑定,只要该属性属于它的数据上下文。
猜你喜欢
  • 1970-01-01
  • 2013-09-18
  • 1970-01-01
  • 2016-08-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多