【问题标题】:ItemsControl view doesn't updated when an item in ObservableCollection is updated当 ObservableCollection 中的项目更新时,ItemsControl 视图不会更新
【发布时间】:2014-06-24 10:28:12
【问题描述】:

简介

嗨,我在这里遇到了一个奇怪的问题。如果我正在更新模型(例如更改 IsSelected 的值),我的 ItemsControl 不会更新视图。

IsSelected 的一个目的是,如果值为true,则MusicalNotationBox(用户控件)的背景更改为蓝色,如果为false,则将其更改回透明。

很多人问:为什么不用触发器比如FocusforIsSelected因为强>不只是 出于“视觉”目的。我有一个命令可以改变某些 每个MusicalNotationProperty(例如Note's Octave) VM 的MusicalNotations 中的对象,其中IsSelected==true(支持 多选),所以我认为模型中需要IsSelected但这不是这里的问题,所以请不要只回答这个问题。

问题是:

  1. 模型属性已成功更改(检查并验证),但似乎视图不是
  2. 如果我使用 UserControl 的 单数形式,例如<c:MusicalNotationBox DataContext={Binding}/>(ofc 以及它的朋友,也就是 VM 中的正确属性),它完美同步。所以,我不太确定 OC 的问题出在哪里。
  3. 更新:例如,如果我创建一个 MouseBinding,每次单击时都会添加一个新的 MusicalNotation 到列表中,然后,视图也会更新。

我已经阅读了几个关于“可观察集合”的主题(谷歌和这里) 没有更新 ItemsControl`,但仍然没有找到满意的答案。

这是我的代码(为了清楚起见,代码可能会被修剪 (...)):

型号

public class MusicalNotation : ... INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    ...
    private bool _isSelected;
    ...
    public bool IsSelected
    {
        get { return _isSelected; }
        set { _isSelected = value; NotifyPropertyChanged("IsSelected"); }
    }
    ...
    public MusicalNotation()
    {
        ...
        IsSelected = false;
    }
    ...
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

查看模型

public class MainWindowModelView : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private ObservableCollection<MusicalNotation> _musicalNotations;
    ...
    public ObservableCollection<MusicalNotation> MusicalNotations
    {
        get { return _musicalNotations; }
        set { _musicalNotations = value; NotifyPropertyChanged("MusicalNotations"); }
    }

    public MainWindowModelView()
    {
        ...
        MusicalNotations = new ObservableCollection<MusicalNotation>();

        //Direct initialization for testing purpose
        MusicalNotations.Add(MusicalNotation.GetEmptyNote(new TimeSignature(4, 4)));
        MusicalNotations.Add(MusicalNotation.GetEmptyNote(new TimeSignature(4, 4)));

        foreach (MusicalNotation item in MusicalNotations)
        {
            item.IsSelected = true;
        }
    }

    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

查看

<Window ...>
<Window.Resources>

</Window.Resources>
<Window.InputBindings>
    ...
</Window.InputBindings>
<Grid>
    ...        
    <ItemsControl Grid.Column="0" Grid.Row="0" ItemsSource="{Binding MusicalNotations, Mode=OneWay}"
                  HorizontalAlignment="Center" VerticalAlignment="Center">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel IsItemsHost="True" Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <c:MusicalNotationBox/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

谢谢。

更新,我的 MusicalNotationBox XAML

<UserControl x:Class="NumberedMusicScoresUserControl.MusicalNotationBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:NumberedMusicScoresUserControl.MusicalNotationBoxProperties"
         mc:Ignorable="d">
<UserControl.Resources>
    <local:DotConverter x:Key="DotConverter"/>
    <local:NoteConverter x:Key="NoteConverter"/>
    <local:AccidentalConverter x:Key="AccidentalConverter"/>
    <local:IsSelectedConverter x:Key="IsSelectedConverter"/>
</UserControl.Resources>

<Grid x:Name="grid" Margin="10,5,10,5"
      HorizontalAlignment="Center" VerticalAlignment="Center"
      Background="{Binding Path=MusicalNotation.IsSelected, Converter={StaticResource IsSelectedConverter}, Mode=OneWay}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <TextBlock Grid.Column="0" Grid.Row="1"
               Text="b"
               Visibility="{Binding Path=MusicalNotation.Accidental, Converter={StaticResource AccidentalConverter}, ConverterParameter=FL, Mode=OneWay}" 
               FontSize="15" FontFamily="CourierNew" 
               HorizontalAlignment="Center" VerticalAlignment="Center"/>
    <Path Grid.Column="1" Grid.Row="1" Stroke="Black" StrokeThickness="1" Stretch="Fill"
          Visibility="{Binding Path=MusicalNotation.Accidental, Converter={StaticResource AccidentalConverter}, ConverterParameter=SP, Mode=OneWay}" >
        <Path.Data>
            <LineGeometry StartPoint="1,0" EndPoint="0,1">
                <LineGeometry.Transform>
                    <RotateTransform CenterX="0" CenterY="0" Angle="30"/>
                </LineGeometry.Transform>
            </LineGeometry>
        </Path.Data>
    </Path>
    <TextBlock Grid.Column="1" Grid.Row="1" 
               Text="{Binding Path=MusicalNotation.Note, Converter={StaticResource NoteConverter}, Mode=OneWay}" 
               FontSize="15" FontFamily="CourierNew" 
               HorizontalAlignment="Center" VerticalAlignment="Center"
               Margin="2.5,0,2.5,0"/>
    <ItemsControl Grid.Column="1" Grid.Row="0" 
                  ItemsSource="{Binding Path=MusicalNotation.Octave, Converter={StaticResource DotConverter}, ConverterParameter=TOP, Mode=OneWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Ellipse HorizontalAlignment="Center" VerticalAlignment="Top"
                         Margin="{Binding Margin}" Fill="{Binding Fill}" 
                         Width="{Binding Diameter}" Height="{Binding Diameter}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    <ItemsControl Grid.Column="1" Grid.Row="2" 
                  ItemsSource="{Binding Path=MusicalNotation.Octave, Converter={StaticResource DotConverter}, ConverterParameter=BOT, Mode=OneWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Ellipse HorizontalAlignment="Center" VerticalAlignment="Bottom"
                         Margin="{Binding Margin}" Fill="{Binding Fill}" 
                         Width="{Binding Diameter}" Height="{Binding Diameter}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    <ItemsControl Grid.Column="2" Grid.Row="1" 
                  ItemsSource="{Binding Path=MusicalNotation.Dot, Converter={StaticResource DotConverter}, ConverterParameter=RIGHT, Mode=OneWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Ellipse HorizontalAlignment="Left" VerticalAlignment="Center"
                         Margin="{Binding Margin}" Fill="{Binding Fill}" 
                         Width="{Binding Diameter}" Height="{Binding Diameter}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

(我没有包含它,因为我认为,如果“单数”是正确的,那么我的 UserControl 也是正确的。但可能是错误的。)

【问题讨论】:

  • 没有任何东西绑定到IsSelected。数据模板的代码是什么?
  • @CameronMacFarland 更新

标签: c# wpf mvvm observablecollection


【解决方案1】:

您的用户控件的DataContextMusicalNotation 对象,所以虽然绑定而不是使用

Background="{Binding Path=MusicalNotation.IsSelected, Converter={StaticResource ....

只需使用

Background="{Binding Path=IsSelected, Converter={StaticResource ....

【讨论】:

    【解决方案2】:

    由于您没有为所选项目或 xaml 中的 IsSelected 指定任何绑定,这就是在 VM 中更改属性时未更新视图的原因。要更新视图,您必须为 ItemsControl 的 SelectedItem 属性提供绑定。

    【讨论】:

    • 它是一个用户控件,所以这种绑定在用户控件代码中完成。但现在我也包含了我的 usercontrol xaml。请检查一下。
    【解决方案3】:

    从绑定中删除 MusicalNotation 前缀。

    {Binding Path=IsSelected, ...
    

    【讨论】:

    • IsSelectedMusicalNotation 类中。无论如何,我已经尝试过了,没有任何变化。
    猜你喜欢
    • 2015-04-09
    • 2021-11-26
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多