Reputation: 576
A WPF application with a Window
containing a DataGrid
, trying to implement the MVVM architecture. There is a single Model class:
public class Book
{
public int id {get; set;}
public string title {get; set;}
public string isbn {get; set;}
}
This is the ViewModel:
class BookViewModel
{
public ObservableCollection<Book> Books;
public BookViewModel()
{
Books = new ObservableCollection<Book>();
// TODO: execute LoadData comand
}
}
A partial snippet of XAML code for markup for the View, which consists of a single Window:
<Window.CommandBindings>
<CommandBinding Command="self:CustomCommands.LoadData" CanExecute="LoadDataCommand_CanExecute" Executed="LoadDataCommand_Executed"/>
</Window.CommandBindings>
<DataGrid Name="BooksDataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Width="200" Binding="{Binding title}"/>
<DataGridTextColumn Header="isbn" Width="200" Binding="{Binding isbn}"/>
</DataGrid.Columns>
</DataGrid>
The code behind for the View above:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// TODO: execute LoadData command
}
private void LoadDataCommand_CanExecute(object sender, CanExecuteRoutedEventArgs args)
{
args.CanExecute = true;
}
private void LoadDataCommand_Executed(object sender, ExecutedRoutedEventArgs args)
{
// TODO: ask the model for the data
}
}
public static class CustomCommands
{
public static readonly RoutedUICommand LoadData = new RoutedUICommand
(
"LoadData",
"LoadData",
typeof(CustomCommands),
new InputGestureCollection()
{
// allow Ctrl+L to perform this command
new KeyGesture(Key.L, ModifierKeys.Control)
}
);
}
The codebehind for App.xaml:
public partial class App : Application
{
[STAThread()]
public static void Main()
{
App app = new App();
app.InitializeComponent();
app.Run();
}
// bind application and show main window on startup
// data context is default source of bindings
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
View.MainWindow mainWin = new View.MainWindow();
ViewModel.BookViewModel bookViewModel = new ViewModel.BookViewModel();
mainWin.DataContext = bookViewModel;
mainWin.Show();
}
}
I am transitioning from WinForms to WPF, and find certain aspects of WPF confusing. What is trying to be achieved, and the problems faced, are as follows:
LoadData
command should clean the GridView
, then fill it again from a database. The database connection has already been implemented. So far, I can't see how to get the databinding working.LoadData
command should be executed from both a menu and button (already implemented).LoadData
command should be executed when the application starts. This is so the DataGrid
would be filled when it starts.Upvotes: 0
Views: 12947
Reputation: 35646
step one: you created a window, its view model and connected them via DataContext. Already done
View.MainWindow mainWin = new View.MainWindow();
ViewModel.BookViewModel bookViewModel = new ViewModel.BookViewModel();
mainWin.DataContext = bookViewModel;
step two: fix (add) binding in xaml:
<DataGrid Name="BooksDataGrid" ItemsSource="{Binding Books}">
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Width="200" Binding="{Binding title}"/>
<DataGridTextColumn Header="isbn" Width="200" Binding="{Binding isbn}"/>
</DataGrid.Columns>
</DataGrid>
step three: fix view model for Binding to work - Binding works with properties:
class BookViewModel
{
public ObservableCollection<Book> Books { get; private set; }
public BookViewModel()
{
Books = new ObservableCollection<Book>();
}
}
step four: implement load data method in the view model amd call it from command, and after mainWin.Show();
to load initial data
Upvotes: 5
Reputation: 303
You shouldn't have much code in the code-behind of the window, other than initializing the component and setting the data context.
public MainWindow()
{
IntializeComponent();
DataContext = new BookViewModel();
}
and your loadData command would be implemented in the BookViewModel
private bool _canLoadDataExecute;
private ICommand _loadDataCommand;
public Icommand LoadDataCommand => _loadDataCommand ?? _loadDataCommand = new RelayCommand((obj) => LoadDataCommand = LoadData(), canLoadDataExecute);
public void LoadData()
{
}
For the code above to work you would also need to implement RelayCommand.cs, code for this can be found here : Full implementation of Relay Command - can it be applied to all cases?. Additionally, there are many other useful answers and resources online with RelayCommand implementation.
Upvotes: 0