WPF Datagrid:强制刷新

时间:2017-05-09 12:47:42

标签: c# wpf mvvm datagrid

我有以下过程:

  1. 在view / viewmodel中创建一个新对象,并通过数据库处理程序将其保存在数据库中
  2. 数据库处理程序实现了INotifyProperyChanged。因此,在1.之后,数据库处理程序会通知其他视图模型有关更改的信息。其中一个相应的视图包含一个绑定到ObservableCollection的数据网格,该数据存储在数据库中。所以view / viewmodel主动访问数据库。
  3. 创建新对象(请参阅1.)会更改数据库内容,还应更新数据网格视图。因此,视图模型通过通知被告知更改。因此,下一步将是再次访问数据库并使用这些新数据填充或更新observable。
  4. 那么如何强制刷新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
    }
    

    最后一个视图包含一个名称的TextBox,它将通过按钮单击保存,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>
    

2 个答案:

答案 0 :(得分:0)

使用ICollectionView - 将Datagrid绑定到它 - 并且只要你想刷新Datagrid就在Viewmodel中调用.Refresh()

答案 1 :(得分:0)

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

为MainWindowViewModel提供一个公共Names属性ObservableCollection<String>。将它绑定到DataGrid或UI中的任何内容。如果您有可能添加或删除其中的项目,请不要在视图模型中使用List<T>

编写一个名为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的行为,但我推断它的工作正常。