I have the following process:
So how to force the refresh of the datagrid content?
Tried following:
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. Currently the DBHandler notifies only if the Names List is changed:
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
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.
<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. All you want to do is retrieve DB stuff when requested, and save it when told. It sits there waiting for orders from 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. 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. 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.
Give MainWindowViewModel a public Names
property that's an ObservableCollection<String>
. Bind that to the DataGrid or whatever in the 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.
Write a new Command class called DelegateCommand
, something like this:
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.