简体   繁体   中英

Changes to ObservableCollection from UI not updating the Bound Collection

In XAML I have a list view:

<UserControl x:Class="HspSetup.View.UserInputData"
             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:HspSetup.View"
             xmlns:viewModel="clr-namespace:HspSetup.ViewModel"
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
             xmlns:Behaviours="clr-namespace:HspSetup.Behaviours"
             mc:Ignorable="d" 
             Height="Auto" Width="Auto">
    <UserControl.Resources>
        <viewModel:UserInputDataViewModel x:Key="ViewModel"/>
    </UserControl.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="0.1*"/>       
            <RowDefinition Height="Auto"/>      
            <RowDefinition Height="*"/>       
            <RowDefinition Height="*"/>    
            <RowDefinition Height="*"/>       
            <RowDefinition Height="*"/>      
            <RowDefinition Height="*"/>     
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*"   />
            <ColumnDefinition Width="20*"/>
            <ColumnDefinition Width="0.5*" />
        </Grid.ColumnDefinitions>

        <TextBlock  Background="Coral" Height="50"
                    VerticalAlignment="Center" TextAlignment="Center"
                    Grid.Row="0"  Grid.ColumnSpan="3">
            <TextBlock.Text>Some More Data</TextBlock.Text>
            <TextBlock.FontFamily>Segoe UI</TextBlock.FontFamily>
            <TextBlock.Foreground>White</TextBlock.Foreground>
            <TextBlock.FontSize>30</TextBlock.FontSize>
        </TextBlock>

        <ListView   Grid.Row="2" Width="Auto" 
                    Behaviours:GridViewColumnResize.Enabled="True"
                    Height="Auto" Name="OrderNumberListView" 
                    IsSynchronizedWithCurrentItem="True" Grid.Column="1"
                    DataContext="{Binding Source={StaticResource ViewModel}}" 
                    ItemsSource="{Binding ConfigObjects}" >
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" 
                            Value="Stretch" />
                    <Setter Property="Behaviours:LostFocus.LostFocusCommand"
                            Value="{Binding Path=LostFocusCommand, Source={StaticResource ViewModel}}"/>
                    <Setter Property="Behaviours:LostFocus.CommandParem" 
                            Value="{Binding}"/>
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.View>
                <GridView>

                    <GridViewColumn Header="Order Name" 
                                    Behaviours:GridViewColumnResize.Width="*">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Text="{Binding OrderNumber, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                         Style="{StaticResource flatTextBox}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Type Name"
                                    Behaviours:GridViewColumnResize.Width="*">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Text="{Binding TypeName, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                         Style="{StaticResource flatTextBox}">
                                </TextBox>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Behaviours:GridViewColumnResize.Width="*"  >
                        <GridViewColumn.HeaderTemplate>
                            <DataTemplate>
                                <Button Content="Add" 
                                        Command="{Binding AddConfigObjectCommand, Mode=OneWay, Source={StaticResource ViewModel}}"/>
                            </DataTemplate>
                        </GridViewColumn.HeaderTemplate>
                        <GridViewColumnHeader HorizontalContentAlignment="Stretch"/>
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Button Name="RemoveButton" 
                                        Content="Remove" 
                                        Command="{Binding RemoveConfigObjectCommand, Mode=OneWay, Source={StaticResource ViewModel}}" CommandParameter="{Binding}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>

    </Grid>
</UserControl>

The Corresponding UI looks like this:

对应的UI看起来像这样

On Click of an Add button I add an Empty row as follows :

UI更新如下

I Enter text into the text boxes. The change made to the listview by entering text in the textbox is not updating the observableCollection to which the textboxes are bound.

The class of the observable collection is as below :

class UserInputDataViewModel: BaseViewModel
{       
    private ObservableCollection<ConfigObject> _configObjects;

    public ObservableCollection<ConfigObject> ConfigObjects
    {
        get { return _configObjects; }
        set
        {
            _configObjects = value;
            OnPropertyChanged("ConfigObjects");
        }
    }

    private ICommand _addConfigObject;

    public ICommand AddConfigObjectCommand
    {
        get
        {
            if (_addConfigObject == null)
            {
                _addConfigObject = new RelayCommand(
                    p => AddConfigObject(),
                    p => CanAddConfigObject);
            }
            return _addConfigObject;
        }
    }

    private void AddConfigObject()
    {
        ConfigObjects.Add(new ConfigObject() { OrderNumber = "", TypeName = "" });
        OnPropertyChanged("ConfigObjects");
    }

    private ICommand _removeConfigObject;

    public ICommand RemoveConfigObjectCommand
    {
        get
        {
            if (_removeConfigObject == null)
            {
                _removeConfigObject = new RelayCommand(
                    p => RemoveConfigObject((ConfigObject)p),
                    p => CanRemoveConfigObject);
            }
            return _removeConfigObject;
        }
    }

    private void RemoveConfigObject(ConfigObject configObject)
    {
        ConfigObjects.Remove(configObject);
        OnPropertyChanged("ConfigObjects");
    }

    bool CanAddConfigObject
    {
        get { return true; }
    }
    bool CanRemoveConfigObject
    {
        get { return true; }
    }
}

class BaseViewModel:INotifyPropertyChanged
{
    /// <summary>
    /// Name of the property that changed
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Send the notification to the property that change
    /// </summary>
    /// <param name="pPropertyName">name of the property</param>
    protected virtual void OnPropertyChanged(string pPropertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, 
                                 new PropertyChangedEventArgs(pPropertyName));
        }
    }
}

internal class ConfigObject : INotifyPropertyChanged
{
    private string _orderNumber;

    public string OrderNumber
    {
        get { return _orderNumber; }
        set { _orderNumber = value; OnPropertyChanged("OrderNumber"); }
    }

    private string _typeName;


    public string TypeName
    {
        get { return _typeName; }
        set { _typeName = value; OnPropertyChanged("TypeName"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

By editing the text in the textboxes you do not change the ObservableCollection but you change one of the objects inside the collection. The collection is not aware of changing the internal(!) state of one the objects in it. Those changes can be captured by the PropertyChanged event of your ConfigObject class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM