DataBinding in WPF?

有些话、适合烂在心里 提交于 2020-04-06 22:11:08

问题


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));
        }
    }
}

回答1:


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.



来源:https://stackoverflow.com/questions/6414952/databinding-in-wpf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!