【问题标题】:WPF: IValueConverter not being calledWPF:未调用 IValueConverter
【发布时间】:2013-10-18 15:37:57
【问题描述】:

我正在尝试根据 ObservableCollection 的“已更改”条件更改按钮的“背景”。我的 ViewModel 上有一个“IsDirty”布尔属性,我确信当 ObservableCollection 更改时它会更新。

但是,按钮的背景并没有改变,而且似乎也没有调用过“转换”方法。

我的转换器缺少什么?当 ObservableCollection 改变时,按钮的背景应该变为红色(IsDirty 为真)

编辑

我更新了转换器以返回红色或绿色的值(而不是红色和透明),并且按钮没有背景颜色,因此这会告诉我转换器永远不会被调用。

编辑 2

添加了显示 IsDirty 属性的 ViewModel 代码。

转换器

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();
    }

}

查看

<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>

查看模型

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;         
    }
}

【问题讨论】:

  • 调试输出中是否有任何绑定错误?
  • @Chris 我没有找到

标签: c# wpf button converter


【解决方案1】:

从绑定中删除 RelativeSource={RelativeSource Self}。此代码在 Button 中而不是在其 DataContext 中进行绑定搜索 IsDirty。

            Background="{Binding 
                        Path=IsDirty, 
                        UpdateSourceTrigger=PropertyChanged, 
                        Converter={StaticResource IsDirtyConverter}}"

或者使用

               Background="{Binding 
                        RelativeSource={RelativeSource Self},
                        Path=DataContext.IsDirty, 
                        UpdateSourceTrigger=PropertyChanged, 
                        Converter={StaticResource IsDirtyConverter}}"

IsDirty 也应该是属性而不是变量

 private bool _isDirty;
 public bool IsDirty
        get
        {

            return _isDirty;
        }
        set
        {
            _isDirty = value

            _codeCollection = value;
            RaisePropertyChanged("IsDirty");
        }

【讨论】:

  • 谢谢尼特。这是 IsDirty.set 中没有 RaisePropertyChanged 调用和 Path=DataContext.IsDirty 的组合。不确定“DataContext”指的是什么,但它不是包含集合的数据上下文。
  • 您的组合框的数据上下文将是您的视图数据上下文,即您的视图模型
【解决方案2】:

我认为您的绑定不正确。试试这个:

Background="{Binding IsDirty, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IsDirtyConverter}}"

您应该在调试项目时检查输出窗口,看看是否有任何绑定错误。

【讨论】:

  • 给我与原始代码相同的结果,Convert' 方法没有被点击来找到应该用于背景的颜色。
  • UpdateSourceTrigger=PropertyChanged 解决了我的问题。怎么默认没有设置,还指望我们设置这个值?
【解决方案3】:

看起来IsDirty 没有更改通知。你在 ViewModel 上实现INotifyPropertyChanged 吗?如果它在ViewModelBase 中实现:我看不到任何这样的代码。PropertyChanged(new PropertyChangedEventArgs("IsDirty")); 在您更改IsDirty 时被调用。因此,很可能没有调用转换器,因为它不知道 IsDirty 已更改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    相关资源
    最近更新 更多