C# WPF数据绑定在绑定整个对象时失败
在下面的C# WPF数据绑定在绑定整个对象时失败,c#,wpf,data-binding,C#,Wpf,Data Binding,在下面的DataTemplate中,第一个绑定不起作用,而第二个绑定起作用,我想知道原因 <local:IsEnabledConverter x:Key="isEnabled"/> <local:Boolean2TextConverter x:Key="txtConverter"/> <DataTemplate x:Key="fileinfoTemplate" DataType="{x:Type local:MyFileInfo}"> <Sta
DataTemplate
中,第一个绑定不起作用,而第二个绑定起作用,我想知道原因
<local:IsEnabledConverter x:Key="isEnabled"/>
<local:Boolean2TextConverter x:Key="txtConverter"/>
<DataTemplate x:Key="fileinfoTemplate" DataType="{x:Type local:MyFileInfo}">
<StackPanel>
<Label x:Name="1stLabel" Content="{Binding Path=Filename}" IsEnabled="{Binding Path=., Converter={StaticResource isEnabled}}"/> <--- doesn't work
<Label x:Name="2ndLabel" Content="{Binding Path=IfPrint, Converter={StaticResource txtConverter}}" IsEnabled="{Binding Path=IsChecked, ElementName=ckBox}"/> <--- works
<CheckBox x:Name="ckBox" IsChecked="{Binding Path=IfPrint}" IsEnabled="{Binding Path=IsValid}" Style="{StaticResource printCkBox}"/>
</StackPanel>
</DataTemplate>
Boolean2TextConverter:
class IsEnabledConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
MyFileInfo f = value as MyFileInfo;
return f.IsValid && f.IfPrint;
}
//... omit ConvertBack NotImplementedException stuff
}
class IsEnabledConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
Boolean b = (Boolean)value;
return b.ToString();
}
//similarly omit ConvertBack here
}
MyFileInfo的代码:
public class MyFileInfo {
public string IfPrint {
get;
set;
}
public string IsValid {
get;
set;
}
...
}
问题:当切换
复选框时,第二个标签将变灰并显示“false”,或者变为正常并显示“true”,这是应该的。然而,第一个标签
根本没有改变;它的IsEnabled
状态应该是两个布尔值的结合,其中一个由复选框更改。怎么了?(请注意,IsEnabledConverter
在GUI初始化时被调用一次,但在其绑定源更改时不会再次调用。)因为当您选中/取消选中复选框时,MyFileInfo
的实例不会更改,因此不会调用IsEnabledConverter
要根据两个属性启用/禁用1stLabel
,请使用MultiValueConverter
或通过将样式应用于标签来使用MultiDataTrigger
。这里有两个问题。首先,必须为ViewModelMyFileInfo
实现INotifyPropertyChanged
。其次,您必须在这里使用多重绑定
。因为如果将整个视图模型绑定到IsEnabled
目标,我认为我们没有办法触发更新目标(例如在切换复选框时)。因此,应该如何做到这一点:
您的视图模型:
public class MyFileInfo : INotifyPropertyChanged {
bool _ifPrint;
bool _isValid;
public bool IfPrint {
get { return _ifPrint; }
set {
if(_ifPrint != value) {
_ifPrint = value;
OnPropertyChanged("IfPrint");
}
}
}
public bool IsValid {
get { return _isValid; }
set {
if(_isValid != value) {
_isValid = value;
OnPropertyChanged("IsValid");
}
}
}
//Implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string prop){
var handler = PropertyChanged;
if(handler != null) handler(this, new PropertyChangedEventArgs(prop));
}
//.... should do the same for the remaining properties....
//...
}
以下是用于多绑定的转换器,它应该实现IMultiValueConverter
(而不是IValueConverter
):
以下是修改后的XAML(改为使用多重绑定):
现在,IsValid
和IfPrint
中的一个更改将触发多重绑定的转换器。在这里,您还可以直接绑定到复选框的IsChecked
,而不是通过IfPrint
间接绑定
PS:注意Name
在XAML中使用(以及在codebehind中使用)不能以数字开头。似乎没有源对象本身的更改通知,只有其属性,如IfPrint
。您也可以使用带有IMultiValueConverter
的MultiBinding
绑定到IsValid
和IfPrint
属性。再次感谢您的耐心和好意:)您能解释一下为什么需要为多值
转换器实现INotifyPropertyChanged
,但不是单一的ValueConverter
?@绿色当使用MVVM模式时,您必须始终实现INotifyPropertyChanged
。否则,它可能只工作一次(例如加载后立即工作)。但在我的原始代码中,它每次都适用于单值绑定(文本在复选框切换时在“true”和“false”之间变化),而不实现INotifyPropertyChanged
。只是好奇为什么…@格林:嗯,很有趣。我说的规则事实上是正确的。通常我们必须使用代码更改属性,然后inotifypropertychanged
将显示这是必要的(如果不实现它,使用代码更改属性将不会触发绑定)。在本例中,您的IfPrint
通过UI(复选框)更改(绑定到),因此它会自动通知并使后续绑定工作(在本例中,后续绑定位于标签内容和IfPrint
属性之间).@green这也让我感到惊讶(以前从未经历过,因为我总是实现INotifyPropertyChanged
),+1出于您有用的好奇心,它教会了我一些新东西:)
class IsEnabledConverter : IMultiValueConverter {
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture) {
if(values.Length == 2){
return (bool) values[0] && (bool) values[1];
}
return false;
}
//... omit ConvertBack NotImplementedException stuff
}
<Label x:Name="firstLabel" Content="{Binding Path=Filename}">
<Label.IsEnabled>
<MultiBinding Converter="{StaticResource isEnabled}">
<Binding Path="IsValid"/>
<Binding Path="IfPrint"/>
</MultiBinding>
</Label.IsEnabled>
</Label>