简体   繁体   English

WPF Datagrid:强制刷新

[英]WPF Datagrid: Force Refresh

I have the following process: 我有以下过程:

  1. Create a new object in a view/viewmodel and save it in the database via a database handler 在视图/视图模型中创建一个新对象,并通过数据库处理程序将其保存在数据库中
  2. Database Handler implements INotifyProperyChanged. 数据库处理程序实现INotifyProperyChanged。 So after 1. the database handler notifies other viewmodels about the change. 因此,在1.之后,数据库处理程序将有关更改通知其他视图模型。 One of the corresponding view contains a datagrid which is bound to a ObservableCollection, which is stored in the database. 对应的视图之一包含绑定到ObservableCollection的数据网格,该数据网格存储在数据库中。 So the view/viewmodel access the database actively. 因此,视图/视图模型可以主动访问数据库。
  3. The creation of the new object (see 1.) changes the database content and should also updating the datagrid view. 新对象的创建(请参见1.)会更改数据库内容,并且还应该更新datagrid视图。 So the viewmodel is informed about the change via the notification. 因此,通过通知将有关更改的信息告知了视图模型。 So the next step would be to access the database again and filling or renew the observable with these new data. 因此,下一步将是再次访问数据库,并用这些新数据填充或更新可观察对象。

So how to force the refresh of the datagrid content? 那么如何强制刷新数据网格内容呢?

Tried following: 尝试以下:

  • Assigning the ObservableCollection temporarly to null does not refresh the datagrid, because it does not notify the datagrid view. 将ObservableCollection临时分配为null不会刷新datagrid,因为它不会通知datagrid视图。
  • Clearing the Collection and adding all items to the new collection (works, but sounds a bit weired because in most cases I will add simply one object to the database) 清除Collection并将所有项目添加到新Collection中(可以,但是听起来有些奇怪,因为在大多数情况下,我只会向数据库中添加一个对象)

Here is some sample code: 这是一些示例代码:

First the database handler, which handles the data exchange between viewmodels and database. 首先是数据库处理程序,它处理视图模型和数据库之间的数据交换。 The DBHandler implements the INotifyPropertyChanged to qualify the viewmodels to react on changes in the database. DBHandler实现INotifyPropertyChanged以使视图模型有资格对数据库中的更改做出反应。 Currently the DBHandler notifies only if the Names List is changed: 当前,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();
        }
    }

The MainWindowViewModels can save a new name via the DBHandler, and listens for changes of List DBHandler.Names by using 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
}

Last the view contains a TextBox for the name which will be saved by a button click and a DataGrid for displaying all names in the database. 最后,该视图包含一个名称的文本框(单击按钮将保存该名称)和一个用于显示数据库中所有名称的数据网格。 So the DataGrid is bounded to the ObservableCollection of Names in the viewmodel. 因此,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>

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

Delete most of DBHandler , it's just confusing you. 删除大部分DBHandlerDBHandler您感到困惑。 All you want to do is retrieve DB stuff when requested, and save it when told. 您要做的就是在请求时检索数据库内容,并在收到提示时将其保存。 It sits there waiting for orders from MainWindowViewModel . 它坐在那里等待MainWindowViewModel订单。 The main viewmodel is always in charge. 主视图模型始终负责。 It uses the model (that's DBHandler ) to store and retrieve information, which it exposes in its properties. 它使用模型(即DBHandler )来存储和检索信息,并在其属性中公开这些信息。 It also exposes commands. 它还公开了命令。 The view is how the user observes the the viewmodel and talks to it. 视图是用户观察视图模型并与之对话的方式。 The viewmodel doesn't know the view exists. viewmodel不知道该视图存在。 All it knows is that somebody out in the darkness occasionally calls the getters and setters on its properties, or calls Execute on one of its commands. 它所知道的是, 某个处于黑暗中的人偶尔会在其属性上调用吸气剂和塞特方法,或者在其命令之一上调用Execute

Give MainWindowViewModel a public Names property that's an ObservableCollection<String> . 为MainWindowViewModel提供一个名为ObservableCollection<String>的公共Names属性。 Bind that to the DataGrid or whatever in the UI. 将其绑定到DataGrid或UI中的任何对象。 Never use List<T> for anything in the viewmodel if there is the slightest chance that you'll be adding or removing items in it. 如果几乎没有机会在其中添加或删除项目,请不要对视图模型中的任何内容使用List<T>

Write a new Command class called DelegateCommand , something like this: 编写一个名为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);
        }
    }
}

Use it: 用它:

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();
        }
    }
}

I don't know what you're doing to bind Names to the DataGrid , but I infer that it's working OK. 我不知道您在做什么,以将Names绑定到DataGrid ,但是我推断它可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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