How to use communication between ViewModels in WPF Catel framework? - c#

When I click to register button (for example) in RegistrationViewModel or any other ViewModel, I would like to change the LeftSlide and MainSlide properties in MainWindowViewModel
LeftSlide = _leftSlides[0];
MainSlide = any other ViewModel;
I've read this documentation, but i can't implement this in my code
https://catelproject.atlassian.net/wiki/display/CTL/MVVM+communication+styles
How can i do this? Help me please
MainWindow.xaml
<DockPanel LastChildFill="True">
<DockPanel DockPanel.Dock="Top">
<Grid Width="120" DockPanel.Dock="Left">
<ContentControl Content="{Binding LeftSlide,
Converter={StaticResource ViewModelToViewConverter}}"></ContentControl>
</Grid>
<Grid DockPanel.Dock="Right">
<ContentControl Content="{Binding MainSlide,
Converter={StaticResource ViewModelToViewConverter}}"></ContentControl>
</Grid>
</DockPanel>
</DockPanel>
RegistrationViewModel.cs
public class RegistrationViewModel : ViewModelBase
{
public RegistrationViewModel()
{
RegistrationUserCommand = new Command(OnRegistrationUserCommandExecute);
}
public Command RegistrationUserCommand { get; private set; }
private void OnRegistrationUserCommandExecute()
{
//when I click this button, I need to change LeftSlide property in
// MainWindowViewModel to _leftSlides[1] (LeftSlide = _leftSlides[1];)
//for example
}
}
MainWindowViewModel.cs
public class MainWindowViewModel : ViewModelBase
{
private List<IViewModel> _leftSlides;
private List<IViewModel> _mainSlides;
public MainWindowViewModel()
{
_leftSlides = new List<IViewModel>
{
new NavViewModel(),
new AnotherNavViewModel()
//another ViewModels
};
_mainSlides = new List<IViewModel>
{
new RegistrationViewModel()
//another ViewModels
};
//Default ViewModels
MainSlide = _mainSlides[0];
LeftSlide = _leftSlides[0];
}
public IViewModel LeftSlide { get; set; }
public IViewModel MainSlide { get; set; }
}
I haven't any experience with WPF and Catel. It's our first project with my team. We are studying. And we can't stop using Catel Framework.

Related

How to write a DataTemplate that works with a VisualStateGroup in WinUI 3?

I've been trying to pass collections of VisualStateGroup objects to various ContentControls in WinUI 3 (1.1.5) but I keep getting a 'Value does not fall within the expected range.' error. I think I've defined an appropriate DataTemplate, but nothing seems to work. Here's a simple example Page from a new Template Studio Winui 3 project:
public sealed partial class MainPage : Page
{
public MainViewModel ViewModel { get; }
public ShellPage ShellPage { get; }
public MainPage()
{
ViewModel = App.GetService<MainViewModel>();
InitializeComponent();
ShellPage = App.GetService<ShellPage>();
var rootGrid = (ShellPage.IsLoaded) ? VisualTreeHelper.GetChild(ShellPage.NavigationViewControl, 0) as Grid : null;
if (rootGrid != null)
{
var listOfVisualStateGroups = VisualStateManager.GetVisualStateGroups(rootGrid);
if (listOfVisualStateGroups?.Count > 0) cControl.Content = listOfVisualStateGroups[0];
}
}
}
<Page
x:Class="TestCollection.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="ContentArea">
<ContentControl x:Name="cControl">
<ContentControl.ContentTemplate>
<DataTemplate x:DataType="VisualStateGroup">
<TextBlock Text="{x:Bind Name}" />
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</Page>
All this does is fetch the list of VisualStateGroups attached to the NavigationViewControl of a vanilla WinUI 3 project. The first group in the list is then displayed in the ContentControl cControl by assigning it to Content. But the assignment causes the error.
I gather there is something wrong with the DataTemplate, but I can't figure out what. A similar problem occurs if I try to create a templated ListViewItem with a VisualStateGroup object.
This is a significant refinement of a question I asked a few days ago (please see: Bound ListView won't accept List<VisualStateGroup> as ItemsSource in WinUI 3. Any idea why?, if curious). My purpose in asking is to better understand the mechanics and requirements of templating. Any help is greatly appreciated.
Update: 10/2/2022
I haven't found an explanation for the error but I have found that simply wrapping the VisualStateGroup and VisualState classes lets me use collections of the new classes as I would expect. Thing1 and Thing2 are just copies of VisualStateGroup and VisualState (both of which are sealed and can't be inherited directly).
public sealed partial class MainPage : Page
{
public MainViewModel ViewModel { get; }
public ShellPage ShellPage { get; }
public List<Thing1> Things { get; set; } = new();
public List<Thing2> OtherThings { get; set; } = new();
public MainPage()
{
ViewModel = App.GetService<MainViewModel>();
InitializeComponent();
ShellPage = App.GetService<ShellPage>();
var rootGrid = (ShellPage.IsLoaded) ? VisualTreeHelper.GetChild(ShellPage.NavigationViewControl, 0) as Grid : null;
if (rootGrid != null)
{
var listOfVisualStateGroups = VisualStateManager.GetVisualStateGroups(rootGrid);
foreach (var group in listOfVisualStateGroups) Things.Add(new(group));
if (listOfVisualStateGroups?.Count > 0)
foreach (var state in listOfVisualStateGroups[0].States) OtherThings.Add(new(state));
}
}
}
// copy of VisualStateGroup
public partial class Thing1
{
public VisualState CurrentState { get; }
public CoreDispatcher Dispatcher { get; }
public DispatcherQueue DispatcherQueue { get; }
public string Name { get; }
public IList<VisualState> States { get; }
public IList<VisualTransition> Transitions { get; }
public Thing1(VisualStateGroup group)
{
CurrentState = group.CurrentState;
Dispatcher = group.Dispatcher;
DispatcherQueue = group.DispatcherQueue;
Name = group.Name;
States = group.States;
Transitions = group.Transitions;
}
}
// copy of VisualState
public partial class Thing2
{
public CoreDispatcher Dispatcher { get; }
public DispatcherQueue DispatcherQueue { get; }
public string Name { get; }
public SetterBaseCollection Setters { get; }
public IList<StateTriggerBase> StateTriggers { get; }
public Storyboard Storyboard { get; set; }
public Thing2(VisualState state)
{
Dispatcher = state.Dispatcher;
DispatcherQueue = state.DispatcherQueue;
Name = state.Name;
Setters = state.Setters;
StateTriggers = state.StateTriggers;
Storyboard = state.Storyboard;
}
}
<Page
x:Class="TestCollection.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:views="using:TestCollection.Views"
mc:Ignorable="d">
<Grid x:Name="ContentArea">
<StackPanel Orientation="Horizontal">
<ListView Margin="0,0,20,20" BorderThickness="1" BorderBrush="Black" Header="Things (VisualStateGroups)"
ItemsSource="{x:Bind Things}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="views:Thing1">
<TextBlock Text="{x:Bind Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Margin="0,0,20,20" BorderThickness="1" BorderBrush="Black" Header="OtherThings (VisualStates)"
ItemsSource="{x:Bind OtherThings}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="views:Thing2">
<TextBlock Text="{x:Bind Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
</Page>
Any idea why an ObservableCollection<Thing1> works but an ObservableCollection<VisualStateGroup> doesn't?

WPF Usercontrol Bindings with MVVM ViewModel not working

I've spent some time trying to solve this problem but couldn't find a solution.
I am trying to bind commands and data inside an user control to my view model. The user control is located inside a window for navigation purposes.
For simplicity I don't want to work with Code-Behind (unless it is unavoidable) and pass all events of the buttons via the ViewModel directly to the controller. Therefore code-behind is unchanged everywhere.
The problem is that any binding I do in the UserControl is ignored.
So the corresponding controller method is never called for the command binding and the data is not displayed in the view for the data binding. And this although the DataContext is set in the controllers.
Interestingly, if I make the view a Window instead of a UserControl and call it initially, everything works.
Does anyone have an idea what the problem could be?
Window.xaml (shortened)
<Window x:Class="Client.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Client.Views"
mc:Ignorable="d">
<Window.Resources>
<local:SubmoduleSelector x:Key="TemplateSelector" />
</Window.Resources>
<Grid>
<StackPanel>
<Button Command="{Binding OpenUserControlCommand}"/>
</StackPanel>
<ContentControl Content="{Binding ActiveViewModel}" ContentTemplateSelector="{StaticResource TemplateSelector}">
<ContentControl.Resources>
<DataTemplate x:Key="userControlTemplate">
<local:UserControl />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Grid>
</Window>
MainWindowViewModel (shortened)
namespace Client.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
private ViewModelBase mActiveViewModel;
public ICommand OpenUserControlCommand { get; set; }
public ViewModelBase ActiveViewModel
{
get { return mActiveViewModel; }
set
{
if (mActiveViewModel == value)
return;
mActiveViewModel = value;
OnPropertyChanged("ActiveViewModel");
}
}
}
}
MainWindowController (shortened)
namespace Client.Controllers
{
public class MainWindowController
{
private readonly MainWindow mView;
private readonly MainWindowViewModel mViewModel;
public MainWindowController(MainWindowViewModel mViewModel, MainWindow mView)
{
this.mViewModel = mViewModel;
this.mView = mView;
this.mView.DataContext = mViewModel;
this.mViewModel.OpenUserControlCommand = new RelayCommand(ExecuteOpenUserControlCommand);
}
private void OpenUserControlCommand(object obj)
{
var userControlController = Container.Resolve<UserControlController>(); // Get Controller instance with dependency injection
mViewModel.ActiveViewModel = userControlController.Initialize();
}
}
}
UserControlSub.xaml (shortened)
<UserControl x:Class="Client.Views.UserControlSub"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Client.Views"
xmlns:viewModels="clr-namespace:Client.ViewModels"
mc:Ignorable="d">
<Grid>
<ListBox ItemsSource="{Binding Models}" SelectedItem="{Binding SelectedModel}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Attr}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel>
<Button Command="{Binding Add}">Kategorie hinzufügen</Button>
</StackPanel>
</Grid>
</UserControl>
UserControlViewModel (shortened)
namespace Client.ViewModels
{
public class UserControlViewModel : ViewModelBase
{
private Data _selectedModel;
public ObservableCollection<Data> Models { get; set; } = new ObservableCollection<Data>();
public Data SelectedModel
{
get => _selectedModel;
set
{
if (value == _selectedModel) return;
_selectedModel= value;
OnPropertyChanged("SelectedModel");
}
}
public ICommand Add { get; set; }
}
}
UserControlController (shortened)
namespace Client.Controllers
{
public class UserControlController
{
private readonly UserControlSub mView;
private readonly UserControlViewModel mViewModel;
public UserControlController(UserControlViewModel mViewModel, UserControlSub mView)
{
this.mViewModel = mViewModel;
this.mView = mView;
this.mView.DataContext = mViewModel;
this.mViewModel.Add = new RelayCommand(ExecuteAddCommand);
}
private void ExecuteAddCommand(object obj)
{
Console.WriteLine("This code gets never called!");
}
public override ViewModelBase Initialize()
{
foreach (var mod in server.GetAll())
{
mViewModel.Models.Add(mod);
}
return mViewModel;
}
}
}

Binding several buttons to individual items in an observable collection

If I have an ObservableCollection in one of my classes. In my code behind my view I have an object of this class and use it as the DataBinding
this.DataContext = MyCustomClass;
in the xaml code of the view I want to bind several buttons to items in the Observable collection. Something like this:
<Button x:Name="Bid_Price_10" Grid.Row="0" Content="{Binding myObservableCollection[0].Price, Mode=OneWay}" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" UseLayoutRounding="True" Padding="0"/>
<Button x:Name="Bid_Price_11" Grid.Row="1" Content="{Binding myObservableCollection[1].Price, Mode=OneWay}" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" UseLayoutRounding="True" Padding="0"/>
At the moment this is not working, am I missing something ?
EDIT: Create full code to demo what I am trying to do:
So I have a Coffee class:
class Coffee
{
public int price { get; set; }
}
I have a drinks class that holds a list of coffees:
class Drinks
{
public List<Coffee> CoffeeList;
public Drinks()
{
CoffeeList = new List<Coffee>();
for (int i = 0; i < 10; i++)
{
Coffee c = new Coffee();
c.price = i;
CoffeeList.Add(c);
}
this.startCoffeePriceUpdateThread();
}
private void UpdateCofffeePrice()
{
while (true)
{
Thread.Sleep(1000);
foreach (var c in CoffeeList)
{
c.price++;
}
}
}
public void startCoffeePriceUpdateThread()
{
Thread coffeeThread = new Thread(new ThreadStart(UpdateCofffeePrice));
coffeeThread.Start();
}
}
my main window code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Drinks ourDrinks = new Drinks();
this.DataContext = ourDrinks;
}
}
and my xaml code:
<Grid x:Name="Grid" HorizontalAlignment="Left" Height="193" Margin="77,31,0,0" VerticalAlignment="Top" Width="315">
<Button x:Name="Button" Content="{Binding CoffeeList[0].Price}" HorizontalAlignment="Left" Margin="49,25,0,0" VerticalAlignment="Top" Width="75" Height="28"/>
</Grid>
So the problem is that I am not seeing anything in the button. At the moment I am not using INotifyPropertyChange as I have been advised it would not be needed.
As Clemens suggested: if everything is fixed, you won't need ObservableCollection nor PropertyChanged notification. The following code should be sufficient:
public class Stuff
{
public string Price { get; set; }
}
public class myCustomClass
{
public List<Stuff> myCollection { get; set; }
}
public partial class MainWindow : Window
{
public myCustomClass myCustomInstance = new myCustomClass();
public MainWindow()
{
InitializeComponent();
myCustomInstance.myCollection = new List<Stuff>();
myCustomInstance.myCollection.Add(new Stuff() { Price = "1200$" });
myCustomInstance.myCollection.Add(new Stuff() { Price = "5.5$" });
this.DataContext = myCustomInstance;
}
}
And the simplified XAML
<Button Content="{Binding myCollection[0].Price, Mode=OneWay}"/>
<Button Content="{Binding myCollection[1].Price, Mode=OneWay}" />
NB: I specified an instance of myCustomClass as the DataContext. If you really need to bind it to the class, let me know and I will update the code.

WPF MVVM Navigate betweel views from the same hierarchical level

I am trying to make a small program mainly to learn MVVM. Its a small Book Library.
I have 4 views(and 4 viewmodels).
MainWindow is the parent view, where i display the other 3 view in a content control.
The other 3 child views are HomeView, BookManagingView, ReaderManagingView.
In HomeView, i display 2 ListViews(one with readers, one with books), and in the other 2 views i edit/add books or readers.
In my HomeView i also have 2 buttons. When i click the buttons i want to switch from the HomeView, to BookManagingView or ReaderManagingView.
If i am trying to switch to any of the Views from the MainWindow, it works.
What i am trying to do is to switch from the HomeView, to BookManagingView or ReaderManagingView. How can i achieve that?
MainWindow:
<Grid>
<ContentControl Content="{Binding CurrentView}" Height="340" Width="500" />
<Button x:Name="btnHomeView" Content="Home" Command="{Binding ChangeViewToHomeView, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="16,70,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="btnBookManagingView" Content="Reader Options" Command="{Binding ChangeViewToReaderManagView,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="96,70,0,0" VerticalAlignment="Top" Width="92"/>
<Button x:Name="btnReaderManagingView" Content="Books Options" Command="{Binding ChangeViewToBookManagView,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="193,70,0,0" VerticalAlignment="Top" Width="92"/>
</Grid>
MainWindowVM:
public class MainWindowViewModel : ViewModelBase
{
private object currentView;
private HomeViewModel homeVM;
private ReaderManagingViewModel readerManagingVM;
private BookManagingViewModel bookManagingVM;
public MainWindowViewModel()
{
homeVM = new HomeViewModel();
readerManagingVM = new ReaderManagingViewModel();
bookManagingVM = new BookManagingViewModel();
CurrentView = homeVM;
ChangeViewToHomeView = new DefCommand(DisplayHomeView);
ChangeViewToReaderManagView = new DefCommand(DisplayReaderManagingView);
ChangeViewToBookManagView = new DefCommand(DisplayBookManagingView);
}
public DefCommand ChangeViewToHomeView { get; private set; }
public DefCommand ChangeViewToReaderManagView { get; private set; }
public DefCommand ChangeViewToBookManagView { get; private set; }
public object CurrentView
{
get { return currentView; }
set { currentView = value; RaisePropertyChanged(); }
}
public void DisplayHomeView()
{
CurrentView = homeVM;
}
public void DisplayReaderManagingView()
{
CurrentView = readerManagingVM;
}
public void DisplayBookManagingView()
{
CurrentView = bookManagingVM;
}
HomeView:
<Grid>
<ListView x:Name="listviewReaders" ItemsSource="{Binding ReadersList}" SelectedItem="{Binding SelectedReader, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="160" Margin="25,23,315,40">
...
<ListView x:Name="listviewBooks" ItemsSource="{Binding BookList, Mode=OneWay}" SelectedItem="{Binding SelectedBook, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="160" Margin="316,50,24,117">
...
<Button x:Name="btnEditReader" Command="{Binding EditReaderSwitch, UpdateSourceTrigger=PropertyChanged}" Content="EditR" HorizontalAlignment="Left" Margin="316,305,0,0" VerticalAlignment="Top" Width="74"/>
<Button x:Name="btnEditBook" Command="{Binding EditBookSwitch, UpdateSourceTrigger=PropertyChanged}" Content="EditB" HorizontalAlignment="Left" Margin="402,305,0,0" VerticalAlignment="Top" Width="74"/>
</Grid>
HomeVM:
private Reader selectedReader;
private Book selectedBook;
private BookListFilter selectedFilter;
private ObservableCollection<Book> bookList;
private ObservableCollection<Reader> readerList;
private IEnumerable<BookListFilter> bookLstItemSrc;
public HomeViewModel()
{
SelectedReader = new Reader();
SelectedBook = new Book();
SelectedFilter = BookListFilter.AllBooks;
BookDBDataContext rdb = new BookDBDataContext();
ReadersList = new ObservableCollection<Reader>(rdb.Readers);
GetBookList();
EditReaderSwitch = new DefCommand(EditReaderInfo);
EditBookSwitch = new DefCommand(EditBookInfo);
}
public DefCommand EditReaderSwitch { get; private set; }
public DefCommand EditBookSwitch { get; private set; }
private void EditBookInfo()
{
var tmpBook = new BookManagingViewModel(this);
var tmpMwvm = new MainWindowViewModel();
tmpMwvm.DisplayBookManagingView();
}
private void EditReaderInfo()
{
var tmpReader = new ReaderManagingViewModel(this);
var tmpMwvm = new MainWindowViewModel();
tmpMwvm.DisplayReaderManagingView();
}
Book & Reader ManagingViews have a bunch of textboxes and buttons for adding, deleting to/from database.
Book & Reader ManagingVM have methods for adding/deleting to/from database(right now they are empty and i will finish them if i manage to solve this problem first)
I have tried to navigate from HomeView to Book/ReaderManagingView with the EditBook/ReaderSwitch commands and EditBook/ReaderInfo() methods, but it doesnt work.
What am i doing wrong, and what should i do to fix it?
Sorry for the long post.
You need to set the CurrentView property of the existing MainWindowViewModel instance. Right now you are creating a new instance of the class.
You could inject the HomeViewModel with a MainWindowViewModel:
private readonly MainWindowViewModel _x;
public HomeViewModel(MainWindowViewModel x)
{
_x = x;
SelectedReader = new Reader();
...
}
private void EditBookInfo()
{
_x.DisplayBookManagingView();
}
MainWindowViewModel:
public MainWindowViewModel()
{
homeVM = new HomeViewModel(this);
}

Filling a ListBox from two TextBoxes with DataBinding

I have a ListBox I want to fill with data from two TextBoxesby clicking a Button. I think the problem comes from the differents textblock i have in my listbox. Here is what i want in image :
TheUI
The MainWindow.xaml of my listbox :
<ListBox x:Name="listBox"
ItemsSource="{Binding Issues}" Grid.Column="1" HorizontalAlignment="Left" Height="366" VerticalAlignment="Top" Width="453" Margin="0,0,-1,0">
<StackPanel Margin="3">
<DockPanel >
<TextBlock FontWeight="Bold" Text="Issue:"
DockPanel.Dock="Left"
Margin="5,0,10,0"/>
<TextBlock Text=" " />
<TextBlock Text="{Binding Issue}" Foreground="Green" FontWeight="Bold" />
</DockPanel>
<DockPanel >
<TextBlock FontWeight="Bold" Text="Comment:" Foreground ="DarkOrange"
DockPanel.Dock="Left"
Margin="5,0,5,0"/>
<TextBlock Text="{Binding Comment}" />
</DockPanel>
</StackPanel>
</ListBox>
My MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public sealed class ViewModel
{
public ObservableCollection<Issue> Issues { get; private set; }
public ViewModel()
{
Issues = new ObservableCollection<Issue>();
}
}
private void addIssue_Click(object sender, RoutedEventArgs e)
{
var vm = new ViewModel();
vm.Issues.Add(new Issue { Name = "Jon Skeet", Comment = "lolilol" });
DataContext = vm;
InitializeComponent();
}
}
My Issue.cs :
public sealed class Issue
{
public string Name { get; set; }
public string Comment { get; set; }
}
I follow this tutorial but i don't want to implement a Database :
Tuto
I also try to use this stackoverflow question
The error i have is 'System.InvalidOperationException' The Items collection must be empty to use ItemsSource
But not sure this is the heart of the problem.
Remove whatever you have inserted between <ListBox> and </ListBox>, as it is treated as part of Items collection.
Instead shift that content between <ListBox.ItemTemplate>...</ListBox.ItemTemplate>.
You don't need to update Context and InitializeComponent every time, atleast to your case.
public partial class MainWindow : Window
{
ViewModel vm = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = vm;
}
public sealed class ViewModel
{
public ObservableCollection<Issue> Issues { get; private set; }
public ViewModel()
{
Issues = new ObservableCollection<Issue>();
}
}
private void addIssue_Click(object sender, RoutedEventArgs e)
{
vm.Issues.Add(new Issue { Name = "Jon Skeet", Comment = "lolilol" });
}
}

Categories