在WPF中指定数据绑定

时间:2015-04-28 20:39:07

标签: c# wpf xaml user-interface data-binding

我有一个简单的WPF应用程序,有3个文本框,2个文本框输入数字,第三个文本框显示单击另一个按钮时的输入总和。

我来自WinForms和MFC背景,对我来说,直观的做法是右键单击textBoxes,打开它们的属性并指定局部变量来从框中读取数据。例如,MFC具有DDX机制。

但是,在WPF中,指定绑定的唯一方法似乎是将XAML代码直接添加到App.XAML,如here on MSDN所示。有没有办法创建绑定而无需手动编写XAML? XAML编码对我来说似乎有点令人生畏,因为我是新手。

我的WPF表格如下:

<Window x:Class="SimpleAdd.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="174,43,0,0" TextWrapping="Wrap" Text="{Binding dataModel.Value1}" VerticalAlignment="Top" Width="120"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="174,84,0,0" TextWrapping="Wrap" Text="{Binding dataModel.Value2}" VerticalAlignment="Top" Width="120"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="174,127,0,0" TextWrapping="Wrap" Text="{Binding dataModel.Value3}" VerticalAlignment="Top" Width="120"/>
        <Button Content="Add" HorizontalAlignment="Left" Margin="393,84,0,0" VerticalAlignment="Top" Width="75" Click="OnAdd"/>
    </Grid>
</Window>

我的C#文件如下:

namespace SimpleAdd
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void OnAdd(object sender, RoutedEventArgs e)
        {
            dataModel m1 = new dataModel();
            m1.Value3 = m1.Value1 + m1.Value2; // BUG : All Properties are 0 even after updating the boxes.
        }
    }

    public class dataModel
    {
        private int val1, val2, val3;

        public int Value1
        {
            get {return val1;}
            set { val1 = value; }
        }
        public int Value2
        {
            get { return val2; }
            set { val2 = value; }
        }
        public int Value3
        {
            get { return val3; }
            set { val3 = value; }
        }
    }

}

编辑:添加INotifyPropertyChanged

的实施
namespace SimpleAdd
{
    public abstract class ObservableObject : INotifyPropertyChanged
    {
        #region Debugging Aides

        /// <summary>
        /// Warns the developer if this object does not have
        /// a public property with the specified name. This 
        /// method does not exist in a Release build.
        /// </summary>
        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public virtual void VerifyPropertyName(string propertyName)
        {
            // Verify that the property name matches a real,  
            // public, instance property on this object.
            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                string msg = "Invalid property name: " + propertyName;

                if (this.ThrowOnInvalidPropertyName)
                    throw new Exception(msg);
                else
                    Debug.Fail(msg);
            }
        }

        /// <summary>
        /// Returns whether an exception is thrown, or if a Debug.Fail() is used
        /// when an invalid property name is passed to the VerifyPropertyName method.
        /// The default value is false, but subclasses used by unit tests might 
        /// override this property's getter to return true.
        /// </summary>
        protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

        #endregion // Debugging Aides

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raises the PropertyChange event for the property specified
        /// </summary>
        /// <param name="propertyName">Property name to update. Is case-sensitive.</param>
        public virtual void RaisePropertyChanged(string propertyName)
        {
            this.VerifyPropertyName(propertyName);
            OnPropertyChanged(propertyName);
        }

        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The property that has a new value.</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            this.VerifyPropertyName(propertyName);

            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        #endregion // INotifyPropertyChanged Members
    }

}

3 个答案:

答案 0 :(得分:1)

从技术上讲,这不在App.xaml中(这是WPF中的特殊文件)。

那就是说,你可以做到。您可以在代码中设置绑定,如下所示:

textBox1.Text = new Binding("SomeProperty");
...

好的,这真的很烦人,所以我们只是在XAML中这样做:

<TextBox Text="{Binding SomeProperty}"/>

两段代码都执行相同的操作,但是当您进入更高级的绑定时,XAML语法更容易使用。此外,它更明显地来自文本的来源,而不是必须打开两个文件。

答案 1 :(得分:1)

您的TextBox未更新,因为您尚未在绑定后面设置数据源(通常为DataContext)。

写作时

<TextBox Text="{Binding dataModel.Value1}" />

您真正说的是&#34;从TextBox.DataContext.dataModel.Value1&#34;中提取此字段的值。如果TextBox.DataContext为空,则不会显示任何内容。

DataContext会自动继承,因此以下代码可以使用:

public partial class MainWindow : Window
{
    public dataModel _data { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        _data = new dataModel();
        this.DataContext = _data;
    }

    private void OnAdd(object sender, RoutedEventArgs e)
    {
        _data.Value3 = _data.Value1 + _data.Value2;
    }
}

假设您还更改了TextBox绑定以从中删除dataModel.

<TextBox Text="{Binding Value1}" />

这会将整个表单的DataContext设置为_data对象,并且在OnAdd方法中,我们可以更新_data对象属性以便更新UI。

我喜欢在博客上写一些关于初学WPF的东西,你可能有兴趣查看一些解释这些概念的帖子:

答案 2 :(得分:0)

FrameworkElement类和FrameworkContentElement类都公开了SetBinding方法。如果要绑定继承这些类之一的元素,则可以直接调用SetBinding方法。 以下示例创建一个名为MyData的类,其中包含名为MyDataProperty的属性。

public class MyData : INotifyPropertyChanged
{
private string myDataProperty;

public MyData() { }

public MyData(DateTime dateTime)
{
    myDataProperty = "Last bound time was " + dateTime.ToLongTimeString();
}

public String MyDataProperty
{
    get { return myDataProperty; }
    set
    {
        myDataProperty = value;
        OnPropertyChanged("MyDataProperty");
    }
}

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged(string info)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(info));
    }
}

}

以下示例显示如何创建绑定对象以设置绑定源。该示例使用SetBinding将myText的Text属性(一个TextBlock控件)绑定到MyDataProperty。

MyData myDataObject = new MyData(DateTime.Now);
Binding myBinding = new Binding("MyDataProperty");    
myBinding.Source = myDataObject;
myText.SetBinding(TextBlock.TextProperty, myBinding);