为“ ObservableCollection不更新视图”提供的解决方案不起作用

时间:2019-11-19 22:12:18

标签: c# wpf

我有一个绑定到名为Programs的ObservableCollection的DataGrid。在窗口上有2个按钮,一个用于将所选行中的位字段更改为激活,另一个用于将其更改为停用。由于我们使用的是.EDMX文件,因此无权访问每个模型类生成的C#代码,因此更改“程序”行之一中的位字段的值不会更改DataGrid中的值。我明白那个。我在这里查找了如何执行此操作。我发现了将近8年前的一则帖子,名为ObservableCollection not updating View。这看起来很有希望,所以我实施了aqwert提供的解决方案。但是,它仍然无法正常工作。我知道值正在被修改,按照aqwert的解决方案,我要替换程序。没关系,它不会更新视图。

我们正在使用.NET Framework 4.5.2。我们也在使用MVVM Light。而且我们正在使用FirstFloor Software的ModernUI for WPF。

这是DataGrid的XAML:

<DataGrid
Grid.Row="3"
Grid.Column="2"
AutoGenerateColumns="False"
BorderThickness="1"
CanUserAddRows="False"
ItemsSource="{Binding Programs}"
SelectedItem="{Binding SelectedProgram, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<DataGrid.Columns>
    <DataGridTemplateColumn
        Width="Auto"
        Header="ID"
        IsReadOnly="True">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ID}" />
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    <DataGridTemplateColumn
        Width="Auto"
        Header="Abbrev"
        IsReadOnly="True">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ProgramAbbrev}" />
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    <DataGridTemplateColumn
        Width="Auto"
        Header="Program Name"
        IsReadOnly="True">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ProgramName}" />
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    <DataGridTemplateColumn
        Width="Auto"
        Header="Inactive"
        IsReadOnly="True">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Inactive, Converter={StaticResource BoolToYN}}" TextAlignment="Center" />
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
</DataGrid.Columns>

这是VM中程序的定义:

private ObservableCollection<Program> programs;
public ObservableCollection<Program> Programs
{
    get { return programs; }
    set
    {
        if (programs != value)
        {
            programs = value;
            RaisePropertyChanged("Programs");
        }
    }
}

最后,这是我按照aqwert解决方案编写的代码:

//make a copy of Programs
var programsCopy = new List<Program>();
foreach (var item in Programs)
{
    if (item.ID == SelectedProgram.ID)
    {
        item.Inactive = inactiveFlag;
        item.UpdatedBy = Environment.UserDomainName + "\\" + Environment.UserName;
        item.UpdatedOn = rightNow;
    }
    programsCopy.Add(item);
}
//copy over the top of Programs
Programs = new ObservableCollection<Program>(programsCopy);

2 个答案:

答案 0 :(得分:1)

修改集合中各个项目的属性时,ObservableCollection<T>不会向UI发出更改通知。实现此目的的方法是在INotifyPropertyChanged类中实现Program事件。

如果由于某种原因无法修改Program,则可以创建一个wraps的新视图模型类,并将源集合属性的类型从ObservableCollection<Programs>更改为{ {1}}。如果每次要更改集合时都将IEnumerable<ProgramViewModel>属性重置为新实例,则不需要ObservableCollection

然后您在Programs类中实现INotifyPropertyChanged并绑定到该属性。

答案 1 :(得分:0)

我终于发现了我的问题。我这是愚蠢的错误。我有2个例程,每个例程绑定到两个不同的ICommands。一个用于“激活”按钮,另一个用于“停用”按钮。我只需要停用按钮的代码即可:

    for ($i = 0; $i < $count; $i++) {

        $participant = new Participant();
        $participant->p_name = $participantArray[0][$i]['name'];
        $participant->p_email = $participantArray[0][$i]['email'];
        $participant->p_address = $participantArray[0][$i]['address'];
        $participant->p_postcode = $participantArray[0][$i]['postcode'];
        $participant->p_city = $participantArray[0][$i]['city'];
        $participant->p_state = $participantArray[0][$i]['state'];
        $participant->p_contact = $participantArray[0][$i]['contactno'];
        $confirmation_code = str_random(30);
        $participant->confirmation_code = $confirmation_code;
        $participant->save();
        $participant->campaign()->attach($request->campaign_id);

        $details = [
            'email' => $participantArray[0][$i]['email'],
            'confirmation_code' => $confirmation_code
        ];

        $emailJob = (new SendEmail($details))->delay(Carbon::now()->addSeconds(10));
        dispatch($emailJob);
    }

昨天我向您展示了SetInactiveFlag(true)调用中的一些代码。效果很好,并将Inactive位标志设置为true。但是,我忘记了调用GetProgramsSynchronously(SelectedRow.ID)调用会针对数据库并刷新内存中的Programs集合,并且Inactive标志设置为false。

鸡蛋在我的脸上。我希望大家都从我的错误中吸取教训,因此希望您避免在自己的脸上生鸡蛋。

相关问题