2011-04-15 309 views
3

我有這樣的自定義用戶控件具有列表和一個按鈕:WPF自定義控件:DependencyProperty的雙向綁定

<UserControl x:Class="WpfApplication1.CustomList" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <ListBox Name="listBox1" ItemsSource="{Binding ListSource}" HorizontalAlignment="Right" Width="174" /> 
     <Button Name="ButtonAdd" Content="Add" HorizontalAlignment="Left" Width="101" /> 
    </Grid> 
</UserControl> 

的代碼背後有型的一個DependencyProperty IEnumerable和對Button處理程序(使用onAdd):

public partial class CustomList : UserControl 
{ 
    public CustomList() 
    { 
     InitializeComponent(); 
    ButtonAdd.Click += new RoutedEventHandler(OnAdd); 
    } 

private void OnAdd(object sender, EventArgs e) 
{ 
    IList<object> tmpList = this.ListSource.ToList(); 
    Article tmpArticle = new Article(); 
    tmpArticle .Name = "g"; 
    tmpList.Add(tmpArticle); 
    ListSource = (IEnumerable<object>) tmpList; 
} 

    public IEnumerable<object> ListSource 
    { 
     get 
     { 
      return (IEnumerable<object>)GetValue(ListSourceProperty); 
     } 
     set 
     { 
      base.SetValue(CustomList.ListSourceProperty, value); 
     } 
    } 

    public static DependencyProperty ListSourceProperty = DependencyProperty.Register(
     "ListSource", 
     typeof(IEnumerable<object>), 
     typeof(CustomList), 
     new PropertyMetadata(OnValueChanged)); 

    private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((CustomList)d).ListSource = (IEnumerable<object>)e.NewValue; 
    } 
} 

在按鈕處理程序中,我試圖將文章添加到ListSource(它綁定到文章)。 這是我用我的用戶(CustomList)窗口:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:local="clr-namespace:WpfApplication1" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     DataContext="{Binding RelativeSource={RelativeSource Self}}" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <local:CustomList ListSource="{Binding Articles, Mode=TwoWay}" Margin="80,0,0,0" /> 
    </Grid> 
</Window> 

當我點擊該按鈕時,文章變得無效,而不是增加在中相應的文章收集的文章。並且ListSource屬性也變爲空。我在這裏做錯了什麼?這是預期的行爲嗎?如果是的話,這將是一個不同的方式做到這一點: 創建一個自定義控件,將有一個列表和一個按鈕,按鈕的處理程序將添加列表中的對象。

回答

5

這裏有很多問題,但導致您的問題的主要問題是您嘗試使用雙向綁定的屬性之間可能存在類型不匹配。您沒有列出您的文章屬性的代碼,但我認爲它可能類似IEnumerable<Article>ObservableCollection<Article>而不是IEnumerable<object>,就像您的ListSource屬性一樣。

當您設置雙向綁定且目標值無法轉換回源類型(即IEnumerable<object> - >ObservableCollection<Article>)時,源屬性(此處的文章)將接收到一個空值,然後該值將被推送通過綁定回到目標屬性(這裏是ListSource)。

您可以更改任何一方的類型,但如果您將它們與TwoWay Binding一起使用,則類型應匹配。

一般來說,將TwoWay Bindings與集合一起使用是個不錯的主意。每次想要進行更改時,不要複製和替換集合實例,只需從一個實例中添加和刪除項目即可。由於(OneWay)Binding兩側的一個實例是相同的集合,所以更新將顯示在兩側,並且如果您使用的是ObservableCollection,則還可以在兩側獲取更改通知。

您還應該刪除您的OnValueChanged代碼,因爲它只是將屬性重置爲剛設置在屬性上的值。

+0

其實你是對的,我的文章集合是一個ObservableCollection的Articles.Now,如果理解正確,我的ListSource屬性必須是ObservableCollection類型的權利?但是,在那種情況下,我必須特別聲明我的ListSource屬性是Articles的ObservableCollection。如果我想使用具有不同種類的ObservableCollections(即ObservableCollection of Persons)的UserControl,這可能是個問題。如果我錯了,你認爲你可以提供一個更好的方法來做這件事的樣本? – Aris 2011-04-18 12:59:14