【问题标题】:WPF Datagrid: Force RefreshWPF Datagrid:强制刷新
【发布时间】:2017-05-09 12:47:41
【问题描述】:

我有以下流程:

  1. 在视图/视图模型中创建一个新对象并通过数据库处理程序将其保存在数据库中
  2. 数据库处理程序实现 INotifyProperyChanged。因此,在 1. 之后,数据库处理程序会通知其他视图模型有关更改。其中一个对应的视图包含一个绑定到存储在数据库中的 ObservableCollection 的数据网格。所以视图/视图模型主动访问数据库。
  3. 新对象的创建(参见 1.)会更改数据库内容,并且还应该更新数据网格视图。因此视图模型通过通知获知更改。因此,下一步将是再次访问数据库并使用这些新数据填充或更新 observable。

那么如何强制刷新datagrid内容呢?

尝试以下:

  • 暂时将 ObservableCollection 分配为 null 不会刷新数据网格,因为它不会通知数据网格视图。
  • 清除集合并将所有项目添加到新集合(可行,但听起来有点奇怪,因为在大多数情况下我只会将一个对象添加到数据库中)

这里是一些示例代码:

首先是数据库处理程序,它处理视图模型和数据库之间的数据交换。 DBHandler 实现 INotifyPropertyChanged 以限定视图模型以对数据库中的更改做出反应。目前 DBHandler 仅在名称列表发生更改时通知:

public class DBHandler:INotifyPropertyChanged
{
    #region Singleton Pattern

    private static DBHandler instance;

    private DBHandler()
    {
    }

    public static DBHandler GetInstance()
    {
        if (instance == null)
            instance = new DBHandler();
        return instance;
    }

    #endregion

    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    // Represents Sample Data of the database
    private List<string> names = new List<string>() { "Sample1", "Sample2" };

    public List<string> Names
    {
        get { return names; }
    }

    /// <summary>
    /// Saves a new name in the database
    /// </summary>
    /// <param name="name"></param>
    public void AddNewName(string name)
    {
        names.Add(name);
        NotifyPropertyChanged();
        }
    }

MainWindowViewModels可以通过DBHandler保存一个新名字,并通过监听List DBHandler.Names的变化

public class MainWindowViewModel
{
    #region Constructors
    public MainWindowViewModel()
    {
        // Initialize the command for the add button click
        addName = new AddNameCommand();
        // Assign database collection entries
        names = new ObservableCollection<string>(DBHandler.GetInstance().Names);

        DBHandler.GetInstance().PropertyChanged += MainWindowViewModel_PropertyChanged_Names;
    }

    /// <summary>
    /// Listen for the DBHandler.Names change for updating the datagrid view.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void MainWindowViewModel_PropertyChanged_Names(object sender, PropertyChangedEventArgs e)
    {
        if(e.PropertyName == "Names")
        {
            // Try to update the datagrid view

            // First Try: Reassign
            names = new ObservableCollection<string>(DBHandler.GetInstance().Names);
        }
    }
    #endregion

    private ObservableCollection<string> names;
    public ObservableCollection<string> Names
    {
        get { return names; }
        set { names = value; }
    }

    #region Commands

    /// <summary>
    /// Command for adding the textbox content as new name to the database
    /// </summary>
    public class AddNameCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            Debug.WriteLine("CanExecute");
            return ((string)parameter) != "" || parameter != null;
        }

        public void Execute(object parameter)
        {
            // Save the name in the database
            DBHandler.GetInstance().AddNewName((string)parameter);
        }
    }


    AddNameCommand addName; // Instance of the command which will be intialized in the constructor

    public ICommand btnClickAdd
    {
        get {
            Debug.WriteLine("btnClickAdd");
            return (ICommand) addName; }
    }

    #endregion
}

最后一个视图包含一个文本框,用于保存通过单击按钮保存的名称,以及一个用于显示数据库中所有名称的 DataGrid。因此,DataGrid 绑定到视图模型中的名称的 ObservableCollection。

<Window.Resources>
    <local:MainWindowViewModel x:Key="ViewModel"/>
</Window.Resources>
<Grid>
    <DataGrid x:Name="dataGrid" ItemsSource="{Binding Source={StaticResource ViewModel}, Path=Names}" HorizontalAlignment="Left" Margin="48,142,0,0" VerticalAlignment="Top" Height="127" Width="422"/>
    <Button x:Name="button_AddName" Command="{Binding Source={StaticResource ViewModel}, Path=btnClickAdd}" Content="Add" HorizontalAlignment="Left" Margin="331,61,0,0" VerticalAlignment="Top" Width="75" CommandParameter="{Binding Text, ElementName=textBox_Name}"/>
    <TextBox x:Name="textBox_Name" HorizontalAlignment="Left" Height="23" Margin="160,58,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>

</Grid>

【问题讨论】:

  • 向我们展示代码。没有人可以根据对您打算做什么的 50,000 英尺描述来猜测您的代码实际上在做什么。我需要: 1)您如何将集合放入网格中? 2)你是如何将新项目添加到集合中的?代码,代码,只有代码。如果您有一点解释任何东西的冲动,只需粘贴代码即可。
  • 是的,添加了代码。
  • MainWindowViewModel 应该实现INotifyPropertyChanged
  • 当您在AddNewName() 中调用NotifyPropertyChanged(); 时,您认为事件参数对于PropertyName 会有什么影响?你有没有在MainWindowViewModel_PropertyChanged_Names 中设置断点来了解那里到底发生了什么?
  • 你是对的。我过滤了 PropertyName,它是“AddNewName”。我从我的主要项目中复制了这个。在此更改和 INotifyPropertyChanged 的​​实施之后,它似乎工作正常。因此,我将搜索与我的主项目的差异,因为我还在视图模型中实现了 INotifyPropertyChanged,但它不起作用。

标签: c# wpf mvvm datagrid


【解决方案1】:

删除大部分DBHandler,这只会让你感到困惑。您要做的就是在请求时检索数据库内容,并在被告知时保存。它坐在那里等待来自MainWindowViewModel 的订单。主视图模型始终负责。它使用模型(即DBHandler)来存储和检索信息,并在其属性中公开这些信息。它还公开命令。视图是用户观察视图模型并与之对话的方式。视图模型不知道视图存在。它只知道有人 在黑暗中偶尔调用其属性的getter 和setter,或调用Execute 对其命令之一。

给 MainWindowViewModel 一个公共的Names 属性,它是一个ObservableCollection&lt;String&gt;。将其绑定到 DataGrid 或 UI 中的任何内容。如果您有最微小的机会添加或删除其中的项目,则切勿将 List&lt;T&gt; 用于视图模型中的任何内容。

编写一个名为DelegateCommand 的新Command 类,如下所示:

public class DelegateCommand<T> : ICommand
{
    public DelegateCommand(Action<T> action, Func<T, bool> canExecute = null)
    {
        _action = action;
        _canExecute = canExecute;
    }

    private Action<T> _action;
    private Func<T, bool> _canExecute;

    public event EventHandler CanExecuteChanged;

    public void RaiseCanExecuteChanged()
    {
        var handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute != null)
        {
            return _canExecute((T)parameter);
        }
        return true;
    }

    public void Execute(object parameter)
    {
        if (_action != null)
        {
            _action((T)parameter);
        }
    }
}

使用它:

public MainWindowViewModel()
{
    // Initialize the command to add a name
    _addNameCommand = new DelegateCommand<string>(DoAddName);

    // Assign database collection entries
    Names = new ObservableCollection<string>(DBHandler.GetInstance().Names);
}

public void DoAddName(String name)
{
    Names.Add(name);
    /*
        Update database here
    */
}

ICommand _addName;

//  Don't name anything "button" in your viewmodel; it's a bad habit to think 
//  that way. It's just a command. If the view wants to use a button to invoke 
//  it, that's the view's business. The viewmodel just makes stuff available. 
public ICommand AddNameCommand
{
    get {
        Debug.WriteLine("getting AddNameCommand");
        return _addNameCommand; 
    }
}
//  Never, never, NEVER NEVER NEVER NEVER touch _names other than in the 
//  get and set blocks of Names. 
//  And make the set private. It should be kept in sync with the database, so 
//  don't let any other class but this one mess with it. 
private ObservableCollection<string> _names = new ObservableCollection<string>();
public ObservableCollection<string> Names
{
    get { return _names; }
    private set { 
        if (_names != value)
        {
            _names = value; 
            NotifyPropertyChanged();
        }
    }
}

我不知道你在做什么将Names 绑定到DataGrid,但我推断它工作正常。

【讨论】:

  • 感谢您在此处总结您的解决方案并添加更多提示,例如在 Names 的 Setter 中移动 NotifyPropertyChanged() 执行(看起来更干净)。
【解决方案2】:

使用 ICollectionView - 将您的 Datagrid 绑定到它 - 并在您想要刷新 Datagrid 时在您的 Viewmodel 中调用 .Refresh()

【讨论】:

  • 可能是另一种选择...我会想办法
猜你喜欢
  • 2021-01-26
  • 2010-10-23
  • 2012-12-09
  • 2013-11-06
  • 2010-12-19
  • 2010-10-30
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
相关资源
最近更新 更多