【发布时间】:2015-07-07 21:31:19
【问题描述】:
我有一个带有 3 个文本框的简单 WPF 应用程序,其中 2 个文本框输入数字,第三个文本框显示单击另一个按钮时输入的总和。
我来自 WinForms 和 MFC 背景,对我来说,直观的做法是右键单击文本框,打开它们的属性并指定局部变量以从框中读取数据。例如,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
}
}
【问题讨论】:
-
正确的 WPF 方法是将所有 3 个文本框绑定到数据模型上的属性,并在数据模型中确保
Value3 = Value1 + Value2,或者创建一个IMultiValueConverter,将其传递给将 TextBox1 和 TextBox2 中的值传递给它,并将它们组合起来并返回 TextBox3 的值。 XAML 通常用于这两种情况。如果您没有尝试以正确的 WPF 方式做事,欢迎您使用后面的代码来执行TextBox3.Text = int.Parse(TextBox1.Text) + int.Parse(TextBox2.Text);或您想要的任何方式 :) -
@Rachel 感谢您向我展示了绳索。然而,我还没有到那里。我想学习正确的 WPF 方式,但基于新的实现,我认为我的绑定不起作用,因为我所有的属性只有 0 个值。
-
老实说,就 UI 的构建方式而言,我仍然发现 WinForms 在我的大脑中更容易一些。但是,如果您还没有尝试过,我建议您深入研究 MVVM - 您肯定会充分利用您的 XAML!
-
@Rintintin 进行转换时,心态肯定会发生变化。你可能会发现this answer about transitioning from WPF to Winforms 很有用:)
-
@Rachel 感谢您分享指向您博客的链接,我不知道数据上下文。现在将阅读它。
标签: c# wpf xaml user-interface data-binding