当 T 中的属性更改时刷新 ObservableCollection<T> - WPF MVVM

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11928887/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 04:57:26  来源:igfitidea点击:

Refresh ObservableCollection<T> when a property in T changes - WPF MVVM

c#wpfxamlmvvm

提问by Denys Wessels

I have a ListBoxwhich I bind to an ObservableCollection<Series>in the view model. Everytime users click on the "Delete" button the DeleteDelegateCommandfor the specific item is executed inside the Seriesclass and the item is removed from the Database.

我有一个ListBox绑定到ObservableCollection<Series>视图模型中的一个。每次用户单击“删除”按钮时,DeleteDelegateCommand都会在Series类内执行特定项目,并将该项目从数据库中删除。

I'm looking for some way to update the ObservableCollection<Series>when this happens so that the relevant item is removed from the XAML view as soon as it's deleted.

我正在寻找某种方法来更新ObservableCollection<Series>发生这种情况时的相关项目,以便在相关项目被删除后立即从 XAML 视图中删除。

Currently this is not happening, I'm relatively new to WPF and have been trying to get this working for days, please suggest where I'm going wrong:

目前这并没有发生,我对 WPF 还比较陌生,并且已经尝试让它工作好几天了,请建议我哪里出错了:

Relevant XAML:

相关 XAML:

<ListBox ItemsSource="{Binding SeriesCollection}" Name="lbSeries" Background="#6E7587" ItemContainerStyle="{StaticResource highlightStyle}" SelectionMode="Single" AlternationCount="2" Grid.Row="2" ScrollViewer.VerticalScrollBarVisibility="Auto">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="200" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBox Margin="5,0" FontSize="14" Name="txtName" Text="{Binding Name}" Width="190" Height="30" Grid.Column="0" />
                <wpfToolkit:IntegerUpDown Value="{Binding Season}"  Name="nudSeason" FontSize="14" Height="30" Width="95" Increment="1" Maximum="100000" Minimum="0" Grid.Column="1" />
                <wpfToolkit:IntegerUpDown Value="{Binding Episode}" Name="nudEpisode" FontSize="14" Height="30" Width="95" Increment="1" Maximum="100000" Minimum="0" Grid.Column="2" />
                <Button Command="{Binding Save}" Grid.Column="3" Width="60" Height="50" Cursor="Hand" ToolTip="Save program" VerticalAlignment="Center" HorizontalAlignment="Center">
                    <Button.Template>
                        <ControlTemplate>
                            <Border HorizontalAlignment="Center" VerticalAlignment="Center" >
                                <Image Source="Resources\Save.png" Width="30" Height="40" />
                            </Border>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
                <Button Command="{Binding Delete}" Grid.Column="4" Width="60" Height="50" Cursor="Hand" CommandParameter="{Binding ElementName=lbSeries,Path=SelectedItem}" ToolTip="Remove program" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="15,0">
                    <Button.Template>
                        <ControlTemplate>
                            <Border HorizontalAlignment="Center" VerticalAlignment="Center" >
                                <Image Source="Resources\Delete.png" Width="30" Height="40" />
                            </Border>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
                <Label Content="{Binding Information}" Grid.Column="5" FontSize="14" Margin="10,0" />
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

View model:

查看型号:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using SeriesTracker.Functions;
using System.Linq;

namespace SeriesTracker.Client
{
    public class SeriesTrackerViewModel : INotifyPropertyChanged
    {
        public DelegateCommand NewSeries { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        private ObservableCollection<Series> _series = new ObservableCollection<Series>();
        public ObservableCollection<Series> SeriesCollection
        {
            get { return _series; }
            set
            {
                _series = value;
                RaisePropertyChanged("SeriesCollection");
            }
        }

        public SeriesTrackerViewModel()
        {
            NewSeries = new DelegateCommand(AddNewSeries);

            DataTable table = DataAccessLayer.GetSeries();
            if (table.Rows.Count > 0)
                LoadSeries(table);
        }

        private void LoadSeries(DataTable table)
        {
            foreach (DataRow row in table.Rows)
            {
                int id = Int32.Parse(row["Id"].ToString());
                string name = row["Name"].ToString();

                int season = 0;
                int episode = 0;

                if (Int32.TryParse(row["Season"].ToString(), out season) &&
                    Int32.TryParse(row["Episode"].ToString(), out episode))
                {
                    var series = new Series(id, name, season, episode);
                    SeriesCollection.Add(series);
                }
            }
        }

        public void AddNewSeries()
        {
            SeriesCollection.AddSeries();
        }

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

Series class:

系列类:

using System;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace SeriesTracker.Functions
{
    public class Series : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private DelegateCommand _save;
        public DelegateCommand Save 
        {
            get { return _save; }
            set
            {
                _save = value;
                RaisePropertyChanged("Save");
            }
        }

        private DelegateCommand _delete;
        public DelegateCommand Delete 
        { 
            get{return _delete;}
            set
            {
                _delete = value;
                RaisePropertyChanged("Delete");
            }
        }

        public int Id { get; set; }

        string _name;
        public String Name
        {
            get { return _name; } 
            set
            {
                _name = value;
                RaisePropertyChanged("Name");
            }
        }

        int _season;
        public Int32 Season 
        {
            get { return _season; } 
            set
            {
                _season = value;
                RaisePropertyChanged("Season");
            }
        }

        int _episode;
        public Int32 Episode 
        {
            get { return _episode; }
            set
            {
                _episode = value;
                RaisePropertyChanged("Episode");
            }
        }

        string _information;
        public String Information 
        {
            get { return _information; }
            set
            {
                _information = value;
                RaisePropertyChanged("Information");
            }
        }

        public Series(int id,string name,int season, int episode)
        {
            Id = id;
            Name = name;
            Season = season;
            Episode = episode;

            Save = new DelegateCommand(SaveItem);
            Delete = new DelegateCommand(DeleteItem);
        }

        public void DeleteItem()
        {
            var selectedItem = this;
            if (selectedItem.Id != -1)
            {
                DataAccessLayer.Delete(selectedItem.Id);
            }
        }

        public void SaveItem()
        {
            var selectedItem = this;
            if (selectedItem.Id == -1)
                DataAccessLayer.AddEntry(selectedItem.Name,selectedItem.Season,selectedItem.Episode);
            else
                DataAccessLayer.Update(selectedItem.Id,
                    selectedItem.Name,selectedItem.Season,selectedItem.Episode);
        }

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

回答by pchajer

You should not keep the DeleteCommand in Series class, it should be on the view model.

你不应该在 Series 类中保留 DeleteCommand,它应该在视图模型上。

And in view model you can easily update the ObservableCollection.

在视图模型中,您可以轻松更新 ObservableCollection。

You need to use Generic delegate command of Type Series on ViewModel and on XAML you need to pass {Binding} on command Parameter.

您需要在 ViewModel 和 XAML 上使用 Type Series 的通用委托命令,您需要在命令参数上传递 {Binding}。

View Model C#:-

查看模型 C#:-

DelegateCommand<Series> DeleteCommand { get; set; } 
DeleteCommand = new RelayCommand<Series>(OnDelete); 

// This method will gets execute on click the of Delete Button1
private void OnDelete(Series series) 
{
}

XAML :-On Delete button change the binding and command parameter value

XAML :-在删除按钮上更改绑定和命令参数值

CommandParameter="{Binding }"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"

CommandParameter="{Binding }"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"

Hope this will help you

希望能帮到你

回答by kotlyarovsa

You may subscribe to PropertyChangedEventHandlerof each Series in ObservableCollection, and then invoke RaisePropertyChanged("SeriesCollection")when event fired

您可以订阅 中PropertyChangedEventHandler的每个系列ObservableCollection,然后RaisePropertyChanged("SeriesCollection")在事件触发时调用

UPDATE:I mean something like that:

更新:我的意思是这样的:

private void LoadSeries(DataTable table)
{
    ...
    {
        var series = new Series(id, name, season, episode);
        series.PropertyChanged += { RaisePropertyChanged("SeriesCollection"); }
        SeriesCollection.Add(series);
    }
}