WPF Custom Control: DependencyProperty TwoWay Binding
I have this Custom UserControl which has a List and a Button:
<UserControl x:Class="WpfApplication1.C开发者_如何学GoustomList"
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>
The code behind has a DependencyProperty of Type IEnumerable and a handler(OnAdd) for the Button:
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;
}
}
In the Button handler I am trying to add an Article to the ListSource(which is bound to the Articles). This is the window where I use my UserControl(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>
When I click the Button, the Articles become null instead of adding an Article in the in the Articles collection. And the ListSource property also becomes null. Am I doing something wrong here? Is this an expected behavior? If yes, what would be a different way of doing this: Create a Custom Control that will have a List and a Button and the handler for the button will add objects in the List.
There are a lot of issues here but the main one that's causing your problem is that there is probably a type mismatch between the properties that you are trying to use TwoWay Binding on. You didn't list the code for your Articles property, but I assume it's probably something like IEnumerable<Article>
or ObservableCollection<Article>
and not IEnumerable<object>
as is your ListSource property.
When you set up two way Binding and the target value can't be converted back to the source type (i.e. IEnumerable<object>
-> ObservableCollection<Article>
) the source property (Articles here) will receive a null value, which will then get pushed back through the Binding to the target property (ListSource here).
You can change the type on either side but if you're using them with a TwoWay Binding the types should match.
In general it's a bad idea to use TwoWay Bindings with collections. Instead of copying and replacing the collection instance every time you want to make a change, just add and remove items from one instance. Since that one instance is the same collection on both sides of the (OneWay) Binding the updates will show up on both sides, and if you're using an ObservableCollection you can also get change notifications on either side.
You should also get rid of your OnValueChanged code since it is just resetting the property to the value that was just set on the property.
精彩评论