我有一个自定义对象,我正试图绑定到一个控件。在这个自定义对象上,我实现了INotifyPropertyChanged接口。我已成功绑定到我的对象和该对象上的属性。
我不明白的是如何从那里开始。我已经做了两天了,但还是不能用。
我的假设是,当我更改绑定到控件的属性时,该属性中设置的值将显示在控件中。但是,无论我对属性做了多少更改,UI的更新都不会超出其初始值。
我以这种方式实现了INotifyPropertyChanged:
A base class which implements INotifyPropertyChanged
[Serializable]
public abstract class BindableObject : INotifyPropertyChanged
{
#region Data
private static readonly Dictionary<string, PropertyChangedEventArgs> eventArgCache;
private const string ERROR_MSG = "{0} is not a public property of {1}";
#endregion // Data
#region Constructors
static BindableObject()
{
eventArgCache = new Dictionary<string, PropertyChangedEventArgs>();
}
protected BindableObject()
{
}
#endregion // Constructors
#region Public Members
/// <summary>
/// Raised when a public property of this object is set.
/// </summary>
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Returns an instance of PropertyChangedEventArgs for
/// the specified property name.
/// </summary>
/// <param name="propertyName">
/// The name of the property to create event args for.
/// </param>
public static PropertyChangedEventArgs
GetPropertyChangedEventArgs(string propertyName)
{
if (String.IsNullOrEmpty(propertyName))
throw new ArgumentException(
"propertyName cannot be null or empty.");
PropertyChangedEventArgs args;
// Get the event args from the cache, creating them
// and adding to the cache if necessary.
lock (typeof(BindableObject))
{
bool isCached = eventArgCache.ContainsKey(propertyName);
if (!isCached)
{
eventArgCache.Add(
propertyName,
new PropertyChangedEventArgs(propertyName));
}
args = eventArgCache[propertyName];
}
return args;
}
#endregion // Public Members
#region Protected Members
/// <summary>
/// Derived classes can override this method to
/// execute logic after a property is set. The
/// base implementation does nothing.
/// </summary>
/// <param name="propertyName">
/// The property which was changed.
/// </param>
protected virtual void AfterPropertyChanged(string propertyName)
{
}
/// <summary>
/// Attempts to raise the PropertyChanged event, and
/// invokes the virtual AfterPropertyChanged method,
/// regardless of whether the event was raised or not.
/// </summary>
/// <param name="propertyName">
/// The property which was changed.
/// </param>
protected void RaisePropertyChanged(string propertyName)
{
this.VerifyProperty(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
// Get the cached event args.
PropertyChangedEventArgs args =
GetPropertyChangedEventArgs(propertyName);
// Raise the PropertyChanged event.
handler(this, args);
}
this.AfterPropertyChanged(propertyName);
}
#endregion // Protected Members
#region Private Helpers
[Conditional("DEBUG")]
private void VerifyProperty(string propertyName)
{
Type type = this.GetType();
// Look for a public property with the specified name.
PropertyInfo propInfo = type.GetProperty(propertyName);
if (propInfo == null)
{
// The property could not be found,
// so alert the developer of the problem.
string msg = string.Format(
ERROR_MSG,
propertyName,
type.FullName);
Debug.Fail(msg);
}
}
#endregion // Private Helpers
}
我从上面的类继承,并在派生类中对我的属性执行以下操作:
public virtual string Name
{
get
{
return m_strName;
}
set
{
m_strName = value;
RaisePropertyChanged("Name");
}
}
我的XAML看起来像这样(缩写版本):
<Window x:Class="PSSPECApplication.Windows.Project"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
DataContext="{Binding SizingProject, RelativeSource={RelativeSource Self}}">
<StackPanel VerticalAlignment="Center">
<TextBox Name="txtProjectName" Text="{Binding Name}" />
</StackPanel>
您可以看到窗口的数据上下文是一个名为SizingProject的属性。SizingProject属于派生类型(从BindableObject派生),其中包含Name属性并引发PropertyChanged事件处理程序。
在窗口的构造函数中,我填充SizingProject,并设置它的Name属性。
为了测试这一点,我在窗口上还有一个按钮,它触发一个事件,该事件将Name属性设置为与原来不同的内容。但是,当name属性更改时,什么都不会发生。我已经追溯到BindableObject,并且PropertyChanged事件总是设置为null,因此没有处理程序被设置和运行。为什么会这样?
我想通过实现INotifyPropertyChanged并在绑定中使用该类型,可以强制WPF自动设置事件处理程序,然后发生正确的行为?对我来说,我从没见过这种行为。
我发现了问题所在。我需要做的是为我的属性SizingProject创建一个dependencProperty。我做完之后,一切都很顺利。
public static readonly DependencyProperty SizingProjectProperty =
DependencyProperty.Register("SizingProject", typeof(Sizing.Project), typeof(Project), new UIPropertyMetadata());
public Sizing.Project SizingProject
{
get
{
return (Sizing.Project)GetValue(Project.SizingProjectProperty);
}
set
{
SetValue(Project.SizingProjectProperty, value);
}
}