2010-10-09 50 views
0

这是我的MainPage.xaml中: -的PropertyChanged总是空

<UserControl x:Class="SilverlightPlainWCF.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    d:DesignHeight="450" d:DesignWidth="800" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:my="clr-namespace:SilverlightPlainWCF.CustomersServiceRef" Loaded="UserControl_Loaded"> 
    <UserControl.Resources> 
     <CollectionViewSource x:Key="customerViewSource" d:DesignSource="{d:DesignInstance my:Customer, CreateList=True}" /> 
    </UserControl.Resources> 
    <Grid x:Name="LayoutRoot" Background="White"> 
     <sdk:DataGrid AutoGenerateColumns="False" Height="426" HorizontalAlignment="Left" ItemsSource="{Binding}" Margin="12,12,0,0" Name="customerDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" VerticalAlignment="Top" Width="776"> 
      <sdk:DataGrid.Columns> 
       <sdk:DataGridTextColumn x:Name="addressColumn" Binding="{Binding Path=Address}" Header="Address" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="cityColumn" Binding="{Binding Path=City}" Header="City" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="companyNameColumn" Binding="{Binding Path=CompanyName}" Header="Company Name" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="contactNameColumn" Binding="{Binding Path=ContactName}" Header="Contact Name" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="contactTitleColumn" Binding="{Binding Path=ContactTitle}" Header="Contact Title" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="countryColumn" Binding="{Binding Path=Country}" Header="Country" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="customerIDColumn" Binding="{Binding Path=CustomerID}" Header="Customer ID" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="faxColumn" Binding="{Binding Path=Fax}" Header="Fax" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="phoneColumn" Binding="{Binding Path=Phone}" Header="Phone" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="postalCodeColumn" Binding="{Binding Path=PostalCode}" Header="Postal Code" Width="SizeToHeader" /> 
       <sdk:DataGridTextColumn x:Name="regionColumn" Binding="{Binding Path=Region}" Header="Region" Width="SizeToHeader" /> 
      </sdk:DataGrid.Columns> 
     </sdk:DataGrid> 
    </Grid> 
</UserControl> 

这是我的MainPage.xaml.cs中: -

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 
using SilverlightPlainWCF.CustomersServiceRef; 
using System.Diagnostics; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 

namespace SilverlightPlainWCF 
{ 
    public partial class MainPage : UserControl, INotifyPropertyChanged 
    { 
     public MainPage() 
     { 
      InitializeComponent(); 
      this.DataContext = Customers; 
      this.Loaded += new RoutedEventHandler(MainPage_Loaded); 
     } 
     public ObservableCollection<Customer> customers; 

     public ObservableCollection<Customer> Customers 
     { 
      get { return customers; } 
      set 
      { 
       customers = value; 
       if (PropertyChanged != null) 
       { 
        PropertyChanged(this, new PropertyChangedEventArgs("Customers")); 
       } 
      } 
     } 

     void MainPage_Loaded(object sender, RoutedEventArgs e) 
     { 

      CustomersServiceClient objCustomersServiceClient = new CustomersServiceClient(); 

      objCustomersServiceClient.GetAllCustomersCompleted += (s, res) => 
      { 

       if (res.Error == null) 
       { 
        Customers = new ObservableCollection<Customer>(res.Result); 

       } 
       else 
       { 
        MessageBox.Show(res.Error.Message); 
       } 
      }; 

      objCustomersServiceClient.GetAllCustomersAsync(); 
     } 

     private void UserControl_Loaded(object sender, RoutedEventArgs e) 
     { 

      // Do not load your data at design time. 
      // if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) 
      // { 
      // //Load your data here and assign the result to the CollectionViewSource. 
      // System.Windows.Data.CollectionViewSource myCollectionViewSource = (System.Windows.Data.CollectionViewSource)this.Resources["Resource Key for CollectionViewSource"]; 
      // myCollectionViewSource.Source = your data 
      // } 
      // Do not load your data at design time. 
      // if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) 
      // { 
      // //Load your data here and assign the result to the CollectionViewSource. 
      // System.Windows.Data.CollectionViewSource myCollectionViewSource = (System.Windows.Data.CollectionViewSource)this.Resources["Resource Key for CollectionViewSource"]; 
      // myCollectionViewSource.Source = your data 
      // } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 
} 

,如果我只是招行: -

this.DataContext = Customers; 

从构造函数到这里: -

if (res.Error == null) 
       { 
        Customers = new ObservableCollection<Customer>(res.Result); 
        this.DataContext = Customers; 
       } 

它工作正常,我得到的所有数据。可能是什么问题。有谁能够帮助我?

回答

2

当你把它放在构造函数中时,它不起作用的原因是那时customers字段中还没有任何值。

MainPage_Loaded被触发,因为在你的XAML下面一行的,不会发生你将只能得到价值:

Loaded="UserControl_Loaded" 

,将执行UserControl_Loaded而不是MainPage_Loaded。你可以做的是从UserControl_Loaded拨打MainPage_Loaded,这可能不是你打算做的。因此,在这种情况下,你应该将改变你的XAML到:

Loaded="MainPage_Loaded" 

你可以因为你不使用它了完全删除UserControl_Loaded

而对于将结果分配给DataGrid,实际上可以直接将结果赋给DataContext而不是通过Customers属性。

但如果你坚持把它分配给了Customers财产,并已在DataGrid相应的更新,那么下一个最简单的解决办法是将地方包括下面的行放在Customers设置方法:

DataContext = value; 

如果您确实,真的坚持要求DataGrid在触发PropertyChanged事件时自行更新,而不需要编写DataContext = Customers行,那么你想要的是数据绑定。通过将DataContext属性绑定到您的Customers属性,然后DataGrid将在其收到PropertyChanged事件时进行更新。

要在XAML中声明数据绑定,您需要为UserControl标签指定一个名称。然后,你会指定绑定到DataContext,沿着这条线的东西:

DataContext="{Binding Path=Customers, ElementName=theUserControlName}" 

如果我是你,而不是必须实现INotifyPropertyChanged界面,我就改用Dependency Properties代替。转换您的示例使用依赖项属性,我早就:

public static DependencyProperty CustomersProperty = 
    DependencyProperty.Register("Customers", typeof(ObservableCollection<Customer>), typeof(MainPage), null); 

public ObservableCollection<Customer> Customers 
{ 
    get { return (ObservableCollection<Customer>) GetValue(CustomersProperty); } 
    set { SetValue(CustomersProperty, value); } 
} 

只是,在属性更改通知将由框架处理。

+1

- 一旦ObservableCollection的内容发生变化,我就使用'INotifyPropertyChanged'来更新网格。我通过设置'this.DataContext = this'而不是'this.DataContext = Customers'并根据更改的DataGrid绑定到'{Binding Path = Customers}'而不是'{Binding}''来解决错误。 – TCM 2010-10-09 06:25:13

+0

@Nitesh:当ObservableCollection的内容改变时,你不需要实现'INotifyPropertyChanged'来更新网格,这是ObservableCollection自身自动完成的。你实现'INotifyPropertyChanged'让网格知道你指定了一个全新的'ObservableCollection'实例。是的,你也可以设置'this.DataContext = this',这是另一种方式。如果你明白为什么它的工作方式会更好,那会更好。 – Amry 2010-10-09 15:08:58

+0

- 感谢您的亲切。现在我的概念越来越清晰。但是有更多的疑问。我希望你不要介意回答他们。 1)当我们从UI(数据网格)添加新行时,该行会被添加到代码的'ObservableCollection'后面吗? 2)我应该做一个'DependencyProperty'或实现'INotifyPropertyChanged'?最佳做法是什么?是不是'INotifyPropertyChanged'更有效? – TCM 2010-10-10 03:37:10

0

我认为,问题是,在构造函数中你没有这样一行:

Customers = new ObservableCollection<Customer>(res.Result); 

您尝试设置的DataContext于前值。