从ViewModel中的绑定更新DataGrid背景

时间:2016-06-30 19:01:24

标签: c# wpf xaml mvvm datagrid

今天我发现了一些奇怪的东西(对我而言)。如果我想通过ViewModel中的属性更新DataGrid,Binding将不会收到通知。这里的特殊想法是(我认为)Binding绑定到另一个对象(Collection的一部分)而不是直接改变的属性。

我为您准备了一些示例代码。但首先是一个(Depper)解释。

当然它只是一个示例,但在这里我有一个带有两个公共属性(Items和CurrentItem)的ViewModel。 Items是一个ObservableCollection,用作我的DataGrid的ItemsSource。 CurrentItem是一个String,用作转换器设置背景颜色(对于网格)的指示器。

我将两个实例添加到我的Collection中,并且在程序启动后,行为符合预期。第一行是绿色,第二行是白色(通过转换器和属性设置)。

但是如果我在加载程序后更改了CurrentItem的值(让我们通过按钮说),颜色就不会在我的Datagrid上更新。

如果我在转换器的开头创建一个断点,我可以看到(在加载过程之后)转换器不会再次执行,因此它必须是绑定的问题。我认为问题是我的属性不属于我的Collection中的项目。 OnPropertyChange方法似乎没有正确触发RowStyle的更新。

在现实生活中,集合的模型类不是字符串,模型类实现了INotifyPropertyChange(但我不认为这是问题,因为我只是不更新​​模型中的任何内容)。

我需要这种行为才能在基于动态指标的情况下突出显示更多行(类似于示例)。如果没有人知道更好的方法,我想我会在我的模型中实现某种属性,并使用ViewModel中的方法更新属性。

视图模型:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public static MainWindowViewModel instance = null;

    private string _CurrentItem;

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string Property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(Property));
        }
    }

    public string CurrentItem
    {
        get
        {
            return _CurrentItem;
        }
        set
        {
            if (value != _CurrentItem)
            {
                _CurrentItem = value;
                OnPropertyChanged("CurrentItem");
                OnPropertyChanged("Items");
            }
        }
    }
    public ObservableCollection<String> Items { get; set; }

    public MainWindowViewModel()
    {
        instance = this;
        Items = new ObservableCollection<string>();

        CurrentItem = "First";

        Items.Add("First");
        Items.Add("Second");
        Items.Add("First");

    }

查看XAML

<Window.DataContext>
    <local:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
    <local:StringToColorConverter x:Key="StringToColorConverter" />
</Window.Resources>
<DockPanel Margin="30">
    <Button DockPanel.Dock="bottom" Content="From First to Second" Click="Button_Click" />
    <DataGrid IsReadOnly="True" ItemsSource="{Binding Items}" ColumnWidth="*" AutoGenerateColumns="False">
        <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
                <Setter Property="Background" 
                        Value="{Binding Converter={StaticResource StringToColorConverter}}" />
            </Style>
        </DataGrid.RowStyle>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Text" Binding="{Binding}" />
        </DataGrid.Columns>
    </DataGrid>
</DockPanel>

转换器

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    var item = value as string;

    if (item == MainWindowViewModel.instance?.CurrentItem)
        return "Green";
    return "White";
}

很抱歉这篇长篇文章我希望你能理解我的问题,当然也许可以帮助我:)。

2 个答案:

答案 0 :(得分:2)

一切都很正常!

这是设计的。 您的背景绑定到DataGrid的第n个对象。 它没有绑定到CurrentItem,因此绑定没有理由更新第n行背景。

因为你有一个ObservableCollection,你可以在 MyItem 类中加上 IsSelected 属性 你应该在 IsSelected 属性上使 MyItem ràise成为PropertyChanged事件。

当然 MyItem 会实施INotifyPropertyChanged

最后,您应该更改绑定:

<DataGrid.RowStyle>
  <Style TargetType="DataGridRow">
    <Setter Property="Background" 
                    Value="{Binding Path=IsSelected,
                                    Converter={StaticResource BooleanToColorConverter}}" />
  </Style>
</DataGrid.RowStyle>

当然,将StringToColorConverter更改为BooleanToColorConvert将是微不足道的。

此致

答案 1 :(得分:2)

您可以使用IMultiValueConverter

来涉及CurrentItem
<DataGrid.RowStyle>
    <Style TargetType="DataGridRow">
        <Setter Property="Background">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource MultiStringToColorConverter}">
                    <Binding />
                    <Binding Path="DataContext.CurrentItem" 
                             RelativeSource="{RelativeSource FindAncestor, 
                                              AncestorType={x:Type Window}}"/>
                </MultiBinding>
            </Setter.Value>
        </Setter>
    </Style>
</DataGrid.RowStyle>

转换器

public class MultiStringToColorConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter,
                  System.Globalization.CultureInfo culture)
    {
        var item = values[0] as string;
        var current = values[1] as string;

        if (item == current)
            return new SolidColorBrush(Colors.Green);
        return new SolidColorBrush(Colors.White);
    }

    public object[] ConvertBack(object values, Type[] targetType, object parameter,
                    System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}