2010-10-09 6 views
0

PropertyChanged Это мой MainPage.xaml: -всегда нулевой

<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. Что вы можете сделать, это позвонить MainPage_Loaded с UserControl_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 вместо этого. Преобразование вашего примера использования Dependency Property, я бы:

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

- Я использовал 'INotifyPropertyChanged' для обновления сетки, как только содержимое' ObservableCollection' изменяется. Я разрешил ошибку, просто установив 'this.DataContext = this' вместо' this.DataContext = Customers' и изменив привязку DataGrid к '{Binding Path = Customers}' вместо '{Binding}'. – TCM

+0

@Nitesh: вам не нужно реализовывать 'INotifyPropertyChanged', чтобы обновлять сетку, когда содержимое' ObservableCollection' изменяется, что делается автоматически самим 'ObservableCollection'. Вы реализуете 'INotifyPropertyChanged', чтобы сеть узнала, что вы назначили совершенно новый экземпляр' ObservableCollection'. И да, вы также можете установить 'this.DataContext = this', это другой способ сделать это. Было бы лучше, если бы вы поняли, почему он работает так, как он работает. – Amry

+0

- Спасибо, что так любезны. Теперь мои концепции становятся все яснее. Однако есть еще несколько сомнений. Надеюсь, ты не против отвечать им. 1) Когда мы добавляем новую строку из пользовательского интерфейса (сетки данных), будет ли строка добавляться в код позади 'ObservableCollection'? 2) Должен ли я создать «DependencyProperty» или реализовать «INotifyPropertyChanged»? Какая практика? Является ли 'INotifyPropertyChanged' более эффективным? – TCM

0

Я считаю, что проблема заключается в том, что в конструкторе вы не имеете эту строку:

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

, прежде чем пытаться установить DataContext к этому значению.

Смежные вопросы