我試圖用多級屬性路徑將依賴項屬性綁定到INotifyPropertyChanged
-enabled屬性。綁定無效嵌套屬性
當財產的所有人對象不是null
,結合作品,但如果車主對象null
,綁定不會做任何事情(轉換器不叫,不使用TargetNullValue
)。
下面是一些最小的樣品代碼來重現問題:
Window1.xaml.cs:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.ComponentModel;
namespace NPCPropertyPath
{
public abstract class VMBase : INotifyPropertyChanged
{
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (e == null) {
throw new ArgumentNullException("e");
}
if (PropertyChanged != null) {
PropertyChanged(this, e);
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class Window1 : Window
{
private class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) {
return null;
} else if (value is int) {
return (((int)value) + 15).ToString();
} else {
return "no int";
}
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
private class InnerVM : VMBase
{
private int myValue;
public int MyValue {
get {
return myValue;
}
set {
if (myValue != value) {
myValue = value;
OnPropertyChanged("MyValue");
}
}
}
}
private class OuterVM : VMBase
{
private InnerVM thing;
public InnerVM Thing {
get {
return thing;
}
set {
if (thing != value) {
thing = value;
OnPropertyChanged("Thing");
}
}
}
}
private readonly OuterVM vm = new OuterVM();
public Window1()
{
InitializeComponent();
var txt = new TextBlock();
txt.SetBinding(TextBlock.TextProperty,
new Binding("Thing.MyValue") {
Source = vm,
Mode = BindingMode.OneWay,
Converter = new MyConverter(),
TargetNullValue = "(error)"
});
container.Content = txt;
var txt2 = new TextBlock();
txt2.SetBinding(TextBlock.TextProperty,
new Binding("Thing") {
Source = vm,
Mode = BindingMode.OneWay,
Converter = new MyConverter(),
TargetNullValue = "(error)"
});
container2.Content = txt2;
}
void Button_Click(object sender, RoutedEventArgs e)
{
vm.Thing = new InnerVM();
vm.Thing.MyValue += 10;
}
}
}
Window1.xaml:
<Window x:Class="NPCPropertyPath.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="NPCPropertyPath" Height="300" Width="300">
<StackPanel>
<Button Content="Change value" Click="Button_Click"/>
<ContentControl Name="container"/>
<ContentControl Name="container2"/>
</StackPanel>
</Window>
當然,這是我真正的應用程序的顯著簡化形式,其中有相當多的事情和所涉及的類不是在兩個文件中擠在一起(甚至在同一程序),其中他們都可以看到對方。
此示例顯示帶有按鈕和兩個內容控件的窗口。每個內容控件都包含一個TextBlock
,其Text
property已綁定到來自視圖模型的屬性。視圖模型實例(類型爲OuterVM
)被分配給每個綁定的Source
property。
OuterVM
implements INotifyPropertyChanged
;它有一個屬性Thing
類型InnerVM
(也執行INotifyPropertyChanged
),其中又有一個屬性MyValue
。
第一個文本塊綁定到Thing.MyValue
,第二個僅僅到Thing
。如果目標屬性爲null
,則這兩個綁定都有一個轉換器集合以及應該顯示在文本塊上的TargetNullValue
屬性的值。
Thing
OuterVM
實例的屬性最初是null
。點擊按鈕時,會爲該屬性分配一些內容。
問題:只有第二個文本塊最初顯示任何內容。綁定到Thing.MyValue
的那個都不會調用轉換器(如通過設置斷點所證明的),也不會使用TargetNullValue
屬性的值。
爲什麼?我怎樣才能讓第一個文本塊顯示默認值而不是Thing.MyValue
而Thing
未分配?
迷人的發現!在找到'TargetNullValue'屬性後,誰會考慮在文檔中查找額外的'FallbackValue'屬性? :) –