简体   繁体   English

WPF:没有调用IValueConverter

[英]WPF: IValueConverter not being called

I am trying to change the 'Background' of a button based on the 'changed' condition of an ObservableCollection. 我试图根据ObservableCollection的“已更改”条件更改按钮的“背景”。 I have an 'IsDirty' boolean property on my ViewModel and I am sure it is getting updated when the ObservableCollection is changed. 我的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;         
    }
}

Remove RelativeSource={RelativeSource Self} , from your binding. 从绑定中删除RelativeSource={RelativeSource Self} This code is making the binding search IsDirty within the Button not in its DataContext. 此代码使得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");
        }

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. 在调试项目时应检查输出窗口,以查看是否出现任何绑定错误。

It looks like IsDirty doesn't have change notification. 看起来IsDirty没有更改通知。 Do you implement INotifyPropertyChanged on the ViewModel? 你在ViewModel上实现了INotifyPropertyChanged吗? And if it is implemented in ViewModelBase : I can't see any code like this. 如果它是在ViewModelBase实现的:我看不到像这样的代码。 PropertyChanged(new PropertyChangedEventArgs("IsDirty")); being called when you change IsDirty . 当你改变IsDirty时被调用。 So, most probably, the converter isn't called because it doesn't know that IsDirty has been changed. 因此,最有可能的是,转换器未被调用,因为它不知道IsDirty已被更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM