DataBinding in WPF?
I'm trying to get databinding set up in WPF. I've got the class person, which is updated (oldschool-like) through the one textbox, and the other textbox is supposed to mirror the change to the person object through a databinding (it used to be a type=twoway but that threw an xamlparseexception). It doesn't work like that, and hitting the button that shows the person.name and it shows the correct name but the textbox doesn't get updated via the databinding. Is this a bad way to try to understand databindings? If you've开发者_如何转开发 a better suggestion for a way to test it out I'm totally okay just ditching this code and doing that instead.
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:PeoplePleaser x:Key="PeoplePleaser" />
</Window.Resources>
<Grid>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<TextBox Height="125" HorizontalAlignment="Left" Margin="81,122,0,0" Name="textBox1" VerticalAlignment="Top" Width="388" FontSize="36" Text="{Binding Converter={StaticResource PeoplePleaser}, Mode=OneWay}" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="209,39,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" TextChanged="textBox2_TextChanged" />
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public static Person myPerson = new Person();
private void button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(myPerson.name);
}
private void textBox2_TextChanged(object sender, TextChangedEventArgs e)
{
myPerson = new Person(textBox2.Text);
}
}
public class Person
{
public String name;
public Person()
{
new Person("Blarg");
}
public Person(String args)
{
if (!args.Equals(null))
{
this.name = args;
}
else new Person();
}
public Person(String args, Person argTwo)
{
argTwo = new Person(args);
}
}
public class PeoplePleaser : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return MainWindow.myPerson.name;
}
catch (Exception e)
{
return "meh";
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!value.Equals(null))
{
return new Person(value.ToString(), MainWindow.myPerson);
}
else
{
return(new Person("", MainWindow.myPerson));
}
}
}
There's a bunch of problems here.
The first and probably most significant one is that you've implemented Person.name
as a field. Binding doesn't work with fields. Person.name
needs to be a property.
The next issue that you have is that if you want a control to be updated with the value of a property when that property changes, your class has to implement property-change notification. (Which is another reason that Person.name
has to be a property.)
A third issue is that you're using WinForms techniques in a WPF application. Data binding eliminates most of the use cases for the TextChanged
event. (Not all: it can be useful when you're developing custom controls.)
A fourth issue is there's no need for value conversion, so no need to implement a value converter.
A Person
class that implements property-changed notification correctly should look something like this:
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler h = PropertyChanged;
if (h != null)
{
h(this, new PropertyChangedEventArgs(propertyName));
}
}
public Person() { }
public Person(string name)
{
Name = name;
}
private string _Name = "I was created by the parameterless constructor";
public string Name
{
get { return _Name; }
set
{
if (_Name == value)
{
return;
}
_Name = value;
OnPropertyChanged("Name");
}
}
}
Once you've done this, if you create a Person
object and bind any TextBox
objects' Text
properties to its Name
property, they'll all be maintained in sync, e.g.:
<StackPanel>
<StackPanel.DataContext>
<local:Person Name="John Smith"/>
</StackPanel.DataContext>
<TextBox Text="{Binding Name, Mode=TwoWay}"/>
<TextBox Text="{Binding Name, Mode=TwoWay}"/>
</StackPanel>
There's much, much more to WPF data binding than this, but this should get you going down the right track.
精彩评论