属性更改时,ObservableCollection未更新为UI

时间:2017-11-20 16:36:04

标签: c# wpf xaml datagrid

问题:当属性更改时,ObservableCollection未更新为UI

我尝试了什么

XAML视图:

<UserControl x:Class="FlexilineDotNetGui.Flexiline.UserControls.UCRealestate"
             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" 
             mc:Ignorable="d" 
             xmlns:translations="clr-namespace:FlexilineDotNetGui.Flexiline.Translations"
             xmlns:viewModels="clr-namespace:FlexilineDotNetGui.Flexiline.ViewModels"
             x:Name="Realestate"
             DataContext="{StaticResource vmRealestate}">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" >
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <DataGrid Grid.Row="0" Grid.RowSpan="3" Grid.Column="0" Height="200" Margin="5"
                          ItemsSource="{Binding Panden, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" 
                          CanUserAddRows="False" IsReadOnly="True" SelectedItem="{Binding Pand}">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="{x:Static translations:UCRealestate.RegistrationType}" Binding="{Binding RegistrationType, Mode=TwoWay}" Width="Auto"/>
                    </DataGrid.Columns>
                </DataGrid>
                <Button Grid.Column="1"  Grid.Row="0" Background="Transparent"
                        Width="20" Height="20" Padding="0" Margin="5" Command="{Binding AddPandCMD}"
                        CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type viewModels:RealestateViewModel}}}">
                    <Image Source="/Flexiline;component/Resources/New_16x16.ico"/>
                </Button>
                <Button Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" 
                        Width="20" Height="20" Padding="0" Background="Transparent" Margin="5" Command="{Binding DeletePandCMD}"
                        CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type viewModels:RealestateViewModel}}}">
                    <Image Source="/Flexiline;component/Resources/Delete_16x16.ico"/>
                </Button>
                <Grid Grid.Row="3" Margin="5">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid Grid.Row="1" Grid.Column="1" Margin="0,5">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" MaxWidth="100"/>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                        </Grid>         
                        <Label Grid.Row="2" Grid.Column="2" Content="{x:Static translations:UCRealestate.RegistrationType}" HorizontalContentAlignment="Right" VerticalAlignment="Center"/>
                        <ComboBox Grid.Row="2" Grid.Column="3" Margin="5" ItemsSource="{Binding AardInschrijving, UpdateSourceTrigger=PropertyChanged}" SelectedValue="{Binding SelectedAardInschrijving, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Description" SelectedValuePath="FlexKey"/>
                    </Grid>
                </Grid>
            </Grid>
        </Grid>
    </Grid>
</UserControl>

ViewModel:

using FlexilineDotNet.SharedDomainLogic.Models.CommunicationModels;
using FlexilineDotNetGui.Domain.Controls;
using FlexilineDotNetGui.Domain.Models;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Data;

namespace FlexilineDotNetGui.Flexiline.ViewModels
{
    public class RealestateViewModel : ANavigationPaneSubViewModel, INotifyPropertyChanged
    {
        BorgRealestate _borgRealestate = new BorgRealestate();
        ObservableCollection<BorgRealestate> ocPanden = new ObservableCollection<BorgRealestate>();
        private DomainController _controller = DomainController.GetInstance();

        public RelayCommand<object> AddPandCMD { get; private set; }
        public RelayCommand<object> DeletePandCMD { get; private set; }

        #region "properties"

        public ObservableCollection<BorgRealestate> Panden
        {
            get
            {           
                return ocPanden ?? (ocPanden = new ObservableCollection<BorgRealestate>());
            }
            set
            {
                if (ocPanden == value)
                    return;

                ocPanden = value;
                OnPropertyChanged("Panden");
            }
        }

        //public ObservableCollection<BorgRealestate> Panden { get; }


        public BorgRealestate Pand
        {
            get
            {
                return _borgRealestate ?? (_borgRealestate = new BorgRealestate());
            }
            set
            {
                if (value == _borgRealestate) return;
                _borgRealestate = value;
                OnPropertyChanged();
                OnPropertyChanged("Panden");
            }
        }


        public List<DropDownItem> AardInschrijving { get { return _controller.GetDropDownItemsByType("AardInschrijving"); } }

        private DropDownItem SelectedAardInschrijvingDI
        {
            get
            {
                DropDownItem test = _controller.GetDropDownItemsByType("AardInschrijving").FirstOrDefault(x => x.FlexKey == _borgRealestate?.RegistrationType);
                if (test == null)
                {
                    test = _controller.GetDropDownItemsByType("AardInschrijving").FirstOrDefault();
                }
                return test;
            }
            set
            {
                OnPropertyChanged();
                OnPropertyChanged("Panden");
            }
        }

        public int SelectedAardInschrijving
        {
            get
            {
                return SelectedAardInschrijvingDI.FlexKey;
            }
            set
            {
                if (value == Pand?.RegistrationType) return;
                Pand.RegistrationType = value;
                OnPropertyChanged();
                OnPropertyChanged("Panden");
            }
        }

        public string SelectedAardInschrijvingText
        {
            get
            {
                return SelectedAardInschrijvingDI.Description;
            }
        }


        #endregion

        #region "ctor"

        public RealestateViewModel()
        {
            //Panden = new ObservableCollection<BorgRealestate>();
            AddPandCMD = new RelayCommand<object>(o => AddPand());
            DeletePandCMD = new RelayCommand<object>(o => DeletePand());
        }

        #endregion

        #region "methods"

        private void AddPand()
        {
            BorgRealestate newBorgRealestate = new BorgRealestate { RegistrationType = SelectedAardInschrijving };
            Panden.Add(newBorgRealestate);      
        }

        private void DeletePand()
        {
            Panden.Remove(Pand);
        }

        #endregion
    }
}  

问题描述:

当我更新组合框值时,当我使用断点检查时,它在“Panden”属性中更新,但视图中的数据网格未更新。 Oneway以及TwoWay存在问题,正如我在datagrid列中定义的那样。我尝试了两种模式。

视图位于dxnavbar控件内,当我在导航栏项目之间切换时,视图会更新确定。

编辑:

当应用程序启动时,Panden列表确实为null,我忘了提一些东西......

在我看来,有一个带有按钮的数据网格,我将项目添加到可观察集合中,其中一些属性作为示例自然题字组合框值显示在数据网格中。然后将该按钮连接到继电器命令。这是我绑定到datagridview的集合。

属性属性的getter不为空,因此填充了正确的值,只有更改在视图中不会更改。

如果没有通过UI上提供的按钮(relaycommand)将“Pand”项添加到“Panden”集合中,则集合为null是正常的。但是,在将带有按钮的项目添加到集合后,从组合框中更改值后,de datagrid中的“Pand”项将不会更新。

EDIT 21/11 08:54

这是添加pand的逻辑:

private void AddPand()
        {
            BorgRealestate newBorgRealestate = new BorgRealestate { RegistrationType = SelectedAardInschrijving };
            Panden.Add(newBorgRealestate);      
        }

但是在我添加后,我看到项目被添加到集合中,并且在组合框值仅在ui中更改之后也在集合中更新。 (当数据网格中的行具有焦点时)

2 个答案:

答案 0 :(得分:0)

在此代码中:

public ObservableCollection<BorgRealestate> Panden
{
    get
    {
        return ocPanden ?? (ocPanden = new ObservableCollection<BorgRealestate>());
    }

您创建了一个新的集合,但此时您还没有调用OnPropertyChanged;你不应该因为在这里这样做是错误的。因此,用户界面并不知道您已创建新集合。看起来第一次在AddPand函数中调用上面的getter。因此,UI永远不会收到Panden的OnPropertyChanged,因此不会更新。

而不是在构造函数中创建集合,你会发现它会更新。如果Panden从未重新创建,你可能根本不需要一个setter。

在构造函数中:

Panden = new ObservableCollection<BorgRealestate>();

然后Panden财产成为:

public ObservableCollection<BorgRealestate> Panden { get; }

可以简化为:

public ObservableCollection<BorgRealestate> Panden { get; } = new ObservableCollection<BorgRealestate>();

答案 1 :(得分:0)

在Viewmodel中:

这段简短的代码就可以解决问题:

CollectionViewSource.GetDefaultView(ocPanden).Refresh();

替换它:

 public ObservableCollection<BorgRealestate> Panden
        {
            get
            {           
                return ocPanden ?? (ocPanden = new ObservableCollection<BorgRealestate>());
            }
            set
            {
                if (ocPanden == value)
                    return;

                ocPanden = value;
                OnPropertyChanged("Panden");
            }
        }

有了这个:

public ObservableCollection<BorgRealestate> Panden
        {
            get
            {
                if(ocPanden != null)
                {
                    CollectionViewSource.GetDefaultView(ocPanden).Refresh(); //This will do the trick
                }
                return ocPanden ?? (ocPanden = new ObservableCollection<BorgRealestate>());
            }
            set
            {
                if (ocPanden == value)
                    return;

                ocPanden = value;
                OnPropertyChanged("Panden");
            }
        }

不幸的是,我还没有找到原因的真正来源?

如果有人能够知道然后留言?