簡體   English   中英

WPF Datagrid:強制刷新

[英]WPF Datagrid: Force Refresh

我有以下過程:

  1. 在視圖/視圖模型中創建一個新對象,並通過數據庫處理程序將其保存在數據庫中
  2. 數據庫處理程序實現INotifyProperyChanged。 因此,在1.之后,數據庫處理程序將有關更改通知其他視圖模型。 對應的視圖之一包含綁定到ObservableCollection的數據網格,該數據網格存儲在數據庫中。 因此,視圖/視圖模型可以主動訪問數據庫。
  3. 新對象的創建(請參見1.)會更改數據庫內容,並且還應該更新datagrid視圖。 因此,通過通知將有關更改的信息告知了視圖模型。 因此,下一步將是再次訪問數據庫,並用這些新數據填充或更新可觀察對象。

那么如何強制刷新數據網格內容呢?

嘗試以下:

  • 將ObservableCollection臨時分配為null不會刷新datagrid,因為它不會通知datagrid視圖。
  • 清除Collection並將所有項目添加到新Collection中(可以,但是聽起來有些奇怪,因為在大多數情況下,我只會向數據庫中添加一個對象)

這是一些示例代碼:

首先是數據庫處理程序,它處理視圖模型和數據庫之間的數據交換。 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綁定到了視圖模型中的名稱的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()

刪除大部分DBHandlerDBHandler您感到困惑。 您要做的就是在請求時檢索數據庫內容,並在收到提示時將其保存。 它坐在那里等待MainWindowViewModel訂單。 主視圖模型始終負責。 它使用模型(即DBHandler )來存儲和檢索信息,並在其屬性中公開這些信息。 它還公開了命令。 視圖是用戶觀察視圖模型並與之對話的方式。 viewmodel不知道該視圖存在。 它所知道的是, 某個處於黑暗中的人偶爾會在其屬性上調用吸氣劑和塞特方法,或者在其命令之一上調用Execute

為MainWindowViewModel提供一個名為ObservableCollection<String>的公共Names屬性。 將其綁定到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 ,但是我推斷它可以正常工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM