WPF:未调用 IValueConverter
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19453568/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF: IValueConverter not being called
提问by BrianKE
I am trying to change the 'Background' of a button based on the 'changed' condition of an ObservableCollection. I have an 'IsDirty' boolean property on my ViewModel and I am sure it is getting updated when the ObservableCollection is changed.
我正在尝试根据 ObservableCollection 的“已更改”条件更改按钮的“背景”。我的 ViewModel 上有一个“IsDirty”布尔属性,我确信当 ObservableCollection 更改时它会更新。
However, the background of the button is not being changed and it doesn't appear that the 'Convert' method is ever being called.
但是,按钮的背景并未更改,并且似乎从未调用过“Convert”方法。
What am I missing with my converter? The button's background should change to red when the ObservableCollection is changed (IsDirty is true)
我的转换器缺少什么?当 ObservableCollection 更改时,按钮的背景应更改为红色(IsDirty 为 true)
EDIT
编辑
I updated the converter to return a value of red or green (instead of red and transparent) and the button has no background color so that would tell me the converter is never getting called.
我更新了转换器以返回红色或绿色(而不是红色和透明)的值,并且按钮没有背景颜色,所以这会告诉我转换器永远不会被调用。
EDIT 2
编辑 2
Added the ViewModel code showing the IsDirty property.
添加了显示 IsDirty 属性的 ViewModel 代码。
Converter
转换器
public class IsDirtyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return System.Convert.ToBoolean(value) ?
new SolidColorBrush(Colors.Red)
: new SolidColorBrush(Colors.Green);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
View
看法
<Window x:Class="SerializeObservableCollection.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:conv="clr-namespace:SerializeObservableCollection.Converter"
xmlns:ignore="http://www.ignore.com"
mc:Ignorable="d ignore"
Height="300"
Width="491"
Title="MVVM Light Application"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins/MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
<conv:IsDirtyConverter x:Key="IsDirtyConverter" />
</ResourceDictionary>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<TextBlock FontSize="36"
FontWeight="Bold"
Foreground="Purple"
Text="{Binding WelcomeTitle}"
VerticalAlignment="Top"
TextWrapping="Wrap" Margin="10,10,10,0" Height="54" HorizontalAlignment="Center" />
<DataGrid Margin="10,69,10,38"
ItemsSource="{Binding CodeCollection, Mode=TwoWay}"/>
<Button Name="SaveButton" Content="Save"
Command="{Binding SaveButtonClickedCommand}"
Background="{Binding
RelativeSource={RelativeSource Self},
Path=IsDirty,
UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource IsDirtyConverter}}"
HorizontalAlignment="Right" Margin="0,0,90,10"
Width="75" Height="20"
VerticalAlignment="Bottom"/>
<Button Content="Refresh" HorizontalAlignment="Right" Margin="0,0,10,10" Width="75"
Command="{Binding RefreshButton_Click}" Height="20" VerticalAlignment="Bottom"/>
</Grid>
</Window>
View Model
查看模型
public class MainViewModel : ViewModelBase
{
public bool IsDirty;
/// <summary>
/// ObservableCollection of Codes
/// </summary>
private const string CodeCollectionPropertyName = "CodeCollection";
private ObservableCollection<Code> _codeCollection;
public ObservableCollection<Code> CodeCollection
{
get
{
if (_codeCollection == null)
{
_codeCollection = new ObservableCollection<Code>();
}
return _codeCollection;
}
set
{
if (_codeCollection == value)
{
return;
}
_codeCollection = value;
RaisePropertyChanged(CodeCollectionPropertyName);
}
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IDataService dataService)
{
// Load XML file into ObservableCollection
LoadXML();
}
private void LoadXML()
{
try
{
XmlSerializer _serializer = new XmlSerializer(typeof(Codes));
// A file stream is used to read the XML file into the ObservableCollection
using (StreamReader _reader = new StreamReader(@"LocalCodes.xml"))
{
CodeCollection = (_serializer.Deserialize(_reader) as Codes).CodeCollection;
}
// Change notification setup
CodeCollection.CollectionChanged += OnCodeCollectionChanged;
}
catch (Exception ex)
{
// Catch exceptions here
}
}
private void SaveToXML()
{
try
{
XmlSerializer _serializer = new XmlSerializer(typeof(ObservableCollection<Code>));
using (StreamWriter _writer = new StreamWriter(@"LocalCodes.xml"))
{
_serializer.Serialize(_writer, CodeCollection);
}
}
catch (Exception ex)
{
}
}
private RelayCommand _saveButtonClickedCommand;
public RelayCommand SaveButtonClickedCommand
{
get
{
return _saveButtonClickedCommand ??
(_saveButtonClickedCommand = new RelayCommand(
() =>
{
SaveButtonClicked();
}));
}
}
private void SaveButtonClicked()
{
SaveToXML();
}
private void OnCodeCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
IsDirty = true;
}
}
回答by Nitin
Remove RelativeSource={RelativeSource Self}, from your binding. This code is making the binding search IsDirty within the Button not in its DataContext.
RelativeSource={RelativeSource Self}从您的绑定中删除, 。此代码使 Button 内的绑定搜索 IsDirty 而不是其 DataContext。
Background="{Binding
Path=IsDirty,
UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource IsDirtyConverter}}"
OR use
或使用
Background="{Binding
RelativeSource={RelativeSource Self},
Path=DataContext.IsDirty,
UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource IsDirtyConverter}}"
Also IsDirty should be property not variable
IsDirty 也应该是属性而不是可变的
private bool _isDirty;
public bool IsDirty
get
{
return _isDirty;
}
set
{
_isDirty = value
_codeCollection = value;
RaisePropertyChanged("IsDirty");
}
回答by gleng
I don't think you are binding this correctly. Try this:
我认为您没有正确绑定它。尝试这个:
Background="{Binding IsDirty, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IsDirtyConverter}}"
You should check the output window when you are debugging the project to see if you get any binding errors.
您应该在调试项目时检查输出窗口,看看是否有任何绑定错误。
回答by hbarck
It looks like IsDirtydoesn't have change notification. Do you implement INotifyPropertyChangedon the ViewModel? And if it is implemented in ViewModelBase: I can't see any code like this.PropertyChanged(new PropertyChangedEventArgs("IsDirty"));being called when you change IsDirty. So, most probably, the converter isn't called because it doesn't know that IsDirtyhas been changed.
看起来IsDirty没有更改通知。你INotifyPropertyChanged在 ViewModel 上实现了吗?如果它是在 中实现的ViewModelBase:我看不到任何这样的代码。PropertyChanged(new PropertyChangedEventArgs("IsDirty"));当你改变时被调用IsDirty。因此,很可能没有调用转换器,因为它不知道IsDirty已更改。

