2010-10-09 49 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於前值。