Catel ViewToViewModel attribute - wpf

Thank you so much for your help.
I'm trying to understand the ViewToViewModel attribute by getting a small example to work. I've go a couple of questions. My code is below.
Is the [ViewToViewModel] attribute supposed to be placed to be placed in the View, ViewModel or both?
If I try to use an attribute, MappingType, such as: [ViewToViewModel, MappingType = ...] MappingType gives me an error. Am I missing a "using" statement/Assembly Reference? Is there an example of syntax?
I'm able to get things to work the way I need, but I don't think that I'm getting the "ViewToViewModel" part to work properly. In the codebehind of the usercontrol, property changes are handled in HandleMyName(object e). Is ViewToViewModel supposed to do this?
Views:
MainWindow
UserControlView
ViewModels:
MainwindowViewModel
UserControlViewViewmodel
MainWindow
<catel:DataWindow x:Class="ViewToViewModelStudy.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"
xmlns:uc="clr-namespace:ViewToViewModelStudy.Views" >
<StackPanel x:Name="LayoutRoot">
<Label Content="{Binding Title}" />
<uc:UserControlView MyName="{Binding Title}" />
</StackPanel>
</catel:DataWindow>
.
UserControlView.xaml
<catel:UserControl x:Class="ViewToViewModelStudy.Views.UserControlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com">
<StackPanel>
<TextBlock>Innerview Model</TextBlock>
<TextBlock Text="{Binding MyName}"></TextBlock>
<TextBlock>Innerview Model</TextBlock>
</StackPanel>
</catel:UserControl>
UserControlView.xaml.cs
namespace ViewToViewModelStudy.Views
{
using Catel.Windows.Controls;
using Catel.MVVM.Views;
using System.Windows;
using System.Data;
public partial class UserControlView : UserControl
{
[ViewToViewModel]
public string MyName
{
get { return (string)GetValue(MyNameProperty); }
set { SetValue(MyNameProperty, value); }
}
public static readonly DependencyProperty MyNameProperty =
DependencyProperty.Register(
"MyName",
typeof(string),
typeof(UserControlView),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnMyName)));
static void OnMyName(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
UserControlView ic = (UserControlView)obj;
ic.HandleMyName(e.NewValue);
}
private void HandleMyName(object e)
{
ViewModels.UserControlViewModel vm = (ViewModels.UserControlViewModel)this.ViewModel;
if (vm != null)
{
vm.MyName = e.ToString(); // << Shouldn't this happen automagically?
}
}
public UserControlView()
{
InitializeComponent();
}
}
}
UserControlViewModel.cs
namespace ViewToViewModelStudy.ViewModels
{
using Catel.MVVM;
using Catel.Data;
using Catel.MVVM.Views;
using Catel.Windows.Controls;
public class UserControlViewModel : ViewModelBase
{
public UserControlViewModel()
{ }
public string MyName
{
get { return GetValue<string>(MyNameProperty); }
set { SetValue(MyNameProperty, value); }
}
public static readonly PropertyData MyNameProperty = RegisterProperty("MyName", typeof(string), null, (sender, e) => ((UserControlViewModel)sender).OnMyPropertyChanged());
private void OnMyPropertyChanged()
{
}
}
}

1) A ViewToViewModel should be located in the view (you don't want to pollute your VM with it).
2) The attribute should be used as [ViewToViewModel(MappingType = ...)]
3) The ViewToViewModel should handle the automatic mapping of property x on the view to property x on the view model. It will handle all change notifications automatically.

Related

WPF how to transfer data between windows (MVVM)?

I know there are a lot of similar questions and I spent two hours by now trying to implementing them but can't proceed. So the problem seems simple. When I don't have a viewmodel, I can set the datacontext to a class and it is very easy to transfer data with that class. But when there is viewmodel, I have to set the datacontext to that and can't find a way to return any value after that. I tried to implement countless solutions to the problem but it seems that they are above my skill level. Thank you so much for your help!
The important parts of my code (its a simple game which i want to save, where save is named by userinput) The first window, where I want to get data from the second window
case Key.Escape: {
Thread t = new Thread(() => {
SaveGameWindow pw = new SaveGameWindow(); //the second window
if ((pw.ShowDialog() == true) && (pw.Name != string.Empty)) //pw.Name always empty
{
ILogicSaveGame l = new LogicSaveGame();
l.Write(pw.Name, "saved_games.txt");
MessageBox.Show("game saved");
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
XAML (from now on everything belongs to the SaveGameWindow):
<Window.Resources>
<local:SaveGameViewModel x:Key="my_viewmodel"/>
</Window.Resources>
<Grid DataContext="{StaticResource my_viewmodel}">
<TextBox Text="{Binding Name}"/> //i want to acces this in the first window
<Button Command="{Binding CloseCommand}"
Content="Save"/>
Code behind:
private readonly SaveGameViewModel vm;
public SaveGameWindow()
{
this.InitializeComponent();
this.vm = this.FindResource("my_viewmodel") as SaveGameViewModel;
if (this.vm.CloseAction == null)
{
this.vm.CloseAction = new Action(() => this.Close());
}
}
Viewmodel
public class SaveGameViewModel : ViewModelBase
{
public SaveGameViewModel()
{
this.CloseCommand = new RelayCommand(() => this.Close());
}
public string Name { get; set; }
public ICommand CloseCommand { get; private set; }
public Action CloseAction { get; set; }
private void Close()
{
this.CloseAction();
}
}
I use galasoft mvvmlightlibs
There are many solutions to this problem. The simplest solution is to use a shared view model for both windows and data binding. Since both windows would share the same DataContext, both have access to the same data or model instance by simply referencing their DataContext property.
But if you prefer to have individual view models, you would choose a different solution.
Solution 1
If you want to use a dedicated view model for each window, you can always use composition and make e.g. an instance SaveGameViewModel a member of MainWindowViewModel. Any class that has access to MainWindowViewModel will also have access to the SaveGameViewModel and its API, either directly or via delegating properties.
This example uses direct access by exposing SaveGameViewModel as a public property of MainWindowViewModel:
SaveGameViewModel.cs
public class SaveGameViewModel : INotifyPropertyChanged
{
private string name;
public string Name
{
get => this.name;
set
{
this.name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MainWindowViewModel.cs
public class MainWindowViewModel : INotifyPropertyChanged
{
public SaveGameViewModel SaveGameViewModel { get; set; }
// Allow to create an instance using XAML
public MainWindowViewModel() {}
// Allow to create an instance using C#
public MainWindowViewModel(SaveGameViewModel saveGameViewModel)
=> this.SaveGameViewModel = saveGameViewModel;
}
App.xaml
<Application>
<Application.Resources>
<MainWindowViewModel x:Key="MainWindowViewModel">
<MainWindowViewModel.SaveGameViewModel>
<SaveGameViewModel />
</MainWindowViewModel.SaveGameViewModel>
</MainWindowViewModel>
</Application.Resources>
</Application>
SaveGameWindow.xaml
<Window DataContext="{Binding Source={StaticResource MainWindowViewModel}, Path=SaveGameViewModel}">
<TextBox Text="{Binding Name}" />
<Window>
MainWindow.xaml
<Window DataContext="{StaticResource MainWindowViewModel}">
<Window>
MainWindow.xaml.cs
partial class MainWindow : Window
{
private void OnKeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
var mainWindowViewModel = this.DataContext as MainWindowViewModel;
string saveGameName = mainWindowViewModel.SaveGameViewModel.Name;
}
}
}
Solution 2
Since you are just showing a dialog, you can store the current instance of the SaveGameViewModel or its values of interest after the dialog has been closed:
MainWindow.xaml.cs
partial class MainWindow : Window
{
private SaveGameViewModel CurrentSaveGameViewModel { get; set; }
private bool IsSaveGameValid { get; set; }
private void ShowDialog_OnSaveButtonClick(object sender, RoutedEventArgs e)
{
var saveGameDialog = new SaveGameWindow();
this.IsSaveGameValid = saveGameDialog.ShowDialog ?? false;
this.CurrentSaveGameViewModel = saveGameDialog.DataContext as SaveGameViewModel;
}
private void OnKeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape && this.IsSaveGameValid)
{
string saveGameName = this.CurrentSaveGameViewModel.Name;
}
}
}
MainWindow.xaml
<Window>
<Window.DataContext>
<MainWindowViewModel />
</Window.DataContext>
<Window>
SaveGameWindow.xaml
<Window>
<Window.DataContext>
<SaveGameViewModel />
</Window.DataContext>
<TextBox Text="{Binding Name}" />
<Window>

Binding Data to a UserControl hosted by a DataTemplate

I have a user control which exposes a property which is a long. I'd like to instantiate this control and bind to the exposed property in a data template.
I'm seeing xaml errors in the resource file. The ambiguous "must have derivative of panel as the root element". And when I run this in a debugger, I see that the value of TeamIdx is -1 and is not being set.
<DataTemplate x:Key="TeamScheduleTemplate">
<Grid HorizontalAlignment="Left" Width="400" Height="600">
<Team:ScheduleControl TeamIdx="{Binding Idx}" />
</Grid>
</DataTemplate>
public sealed partial class ScheduleControl : UserControl
{
public static readonly DependencyProperty TeamIdxProperty =
DependencyProperty.Register(
"TeamIdx",
typeof(long),
typeof(ScheduleControl),
new PropertyMetadata((long)-1));
public long TeamIdx
{
get { return (long)GetValue(TeamIdxProperty); }
set { SetValue(TeamIdxProperty, value); }
}
public ScheduleControl()
{
this.InitializeComponent();
var team = TeamLookup.GetTeam(TeamIdx);
}
}
Edit: It turns out that the binding doesn't happen until after the control is constructed. In retrospect, this makes total sense. The solution I used is below:
public sealed partial class ScheduleControl : UserControl
{
public static readonly DependencyProperty TeamIdxProperty =
DependencyProperty.Register(
"TeamIdx",
typeof(long),
typeof(ScheduleControl),
new PropertyMetadata(
(long)-1,
OnTeamIdxChanged));
public long TeamIdx
{
get { return (long)GetValue(TeamIdxProperty); }
set { SetValue(TeamIdxProperty, value); }
}
private static void OnTeamIdxChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var target = (ScheduleControl)sender;
target.OnTeamIdxChanged((long)e.NewValue);
}
private void OnTeamIdxChanged(long id)
{
var model = FindModel(id);
this.DataContext = model;
}
public ScheduleControl()
{
this.InitializeComponent();
}
}

How do I create a new instance of a control in the view without violating MVVM

I am encountering a similar problem to what is described in this SO question. The suggested solution is to create a new WebBrowser Control for each now page (PDF) we wish to present (Overwriting the old WebBrowser control).
What is the correct way of creating a new control like that in MVVM? I trying to keep the VM ignorant about the implementation of the view.
Why does the VM need to know? Why can't the view just hook into an appropriate event (define one if you like, or just use the PropertyChanged) and recreate the control?
Create an interface in the ViewModel named IBrowserCreator, with a method called CreateBrowser().
Create a static class in the ViewModel named ViewHelper, and add to it a static property of type IBrowserCreator named BrowserCreator.
In the View layer, create a new class called BrowserCreator, which implements ViewModel.IBrowserCreator.
In the View initialization code, instantiate a BrowserCreator, and assign it to ViewModel.ViewHelper.BrowserCreator.
From your ViewModel, you should now be able to call:
ViewHelper.BrowserCreator.CreateBrowser()
Obviously this answer is a framework only, but it should give you the general idea. You'll need to implement the CreateBrowser method to suit your exact needs.
why not simply use a Datatemplate and let WPF do the rest?
create a usercontrol with the webbrowser. you have to add an attached property because you can not bind to source directly.
<UserControl x:Class="WpfBrowser.BrowserControl"
xmlns:WpfBrowser="clr-namespace:WpfBrowser" >
<Grid>
<WebBrowser WpfBrowser:WebBrowserUtility.BindableSource="{Binding MyPdf}"/>
</Grid>
</UserControl>
create a viewmodel which handle your uri
public class MyPdfVM
{
public Uri MyPdf { get; set; }
public MyPdfVM()
{
this.MyPdf = new Uri(#"mypdf path");
}
}
take your pageviewmodel, add the pdfviewmodel and take a contentcontrol in your view
public class MyPageViewmodel: INotifyPropertyChanged
{
private MyPdfVM _myPdfStuff;
public MyPdfVM MyPdfStuff
{
get { return _myPdfStuff; }
set { _myPdfStuff = value; this.NotifyPropertyChanged(()=>this.MyPdfStuff);}
}
public MyViewmodel()
{
this.MyPdfStuff = new MyPdfVM();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged<T>(Expression<Func<T>> property)
{
var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
}
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyInfo.Name));
}
}
window.xaml
<Window x:Class="WpfBrowser.MainWindow"
xmlns:WpfBrowser="clr-namespace:WpfBrowser"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type WpfBrowser:MyPdfVM}">
<WpfBrowser:BrowserControl />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="64*" />
<RowDefinition Height="247*" />
</Grid.RowDefinitions>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="32,14,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<ContentControl Grid.Row="1" Content="{Binding MyPdfStuff}"/>
</Grid>
</Window>
window.xaml.cs
public partial class MainWindow : Window
{
private MyViewmodel _data;
public MainWindow()
{
_data = new MyViewmodel();
InitializeComponent();
this.DataContext = _data;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
this._data.MyPdfStuff = new MyPdfVM() { MyPdf = new Uri(#"your other pdf path for testing") };
}
}
when ever you change the MyPdfStuff Property the webbroswer update the pdf.
attached property
public static class WebBrowserUtility
{
public static readonly DependencyProperty BindableSourceProperty =
DependencyProperty.RegisterAttached("BindableSource", typeof(string), typeof(WebBrowserUtility), new UIPropertyMetadata(null, BindableSourcePropertyChanged));
public static string GetBindableSource(DependencyObject obj)
{
return (string)obj.GetValue(BindableSourceProperty);
}
public static void SetBindableSource(DependencyObject obj, string value)
{
obj.SetValue(BindableSourceProperty, value);
}
public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
WebBrowser browser = o as WebBrowser;
if (browser != null)
{
string uri = e.NewValue as string;
browser.Source = string.IsNullOrWhiteSpace(uri) ? null:new Uri(uri);
}
}
}
EDIT: added some code so you can see that if you chane the PDFViewmodel your browsercontrol show the new pdf.

WPF: Nested DependencyProperties

I have an ObservableCollection of "Layouts" and a "SelectedLocation" DependencyProperty on a Window. The SelectedLocation has a property called "Layout", which is an object containing fields like "Name" etc. I'm trying to bind a combobox to the SelectedLayout but it's not working.
The following does not work, I've tried binding to SelectedItem instead to no avail. I believe it may be something to do with the fact that I'm binding to a subProperty of the SelectedLocation DependencyProperty (though this does implement INotifyPropertyChanged.
<ComboBox Grid.Row="2" Grid.Column="0" x:Name="cboLayout" ItemsSource="{Binding Layouts,ElementName=root}" SelectedValue="{Binding SelectedLocation.Layout.LayoutID,ElementName=root}" DisplayMemberPath="{Binding Name}" SelectedValuePath="LayoutID" />
However, the following works (Also bound to the "SelectedLocation" DP:
<TextBox Grid.Row="4" Grid.Column="1" x:Name="txtName" Text="{Binding SelectedLocation.Name,ElementName=root,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
What type property Layouts has? I suppose something like this this: IEnumerable<Layout>.
But you bind selected value to Layout.LayoutID. So you got situation, when combo box contains Layout objects, and you try to select it by Int identifier. Of course binding engine can't find any Int there.
I have no idea about details of your code, so one thing I could propose: try to reduce your binding expression: SelectedItem="{Binding SelectedLocation.Layout,ElementName=root}.
If no success, provide more code to help me understand what's going on.
====UPDATE====
As I've said, you are obviously doing something wrong. But I am not paranormalist and couldn't guess the reason of your fail (without your code). If you don't want to share your code, I decided to provide simple example in order to demonstrate that everything works. Have a look at code shown below and tell me what is different in your application.
Class Layout which exposes property LayoutId:
public class Layout
{
public Layout(string id)
{
this.LayoutId = id;
}
public string LayoutId
{
get;
private set;
}
public override string ToString()
{
return string.Format("layout #{0}", this.LayoutId);
}
}
Class SelectionLocation which has nested property Layout:
public class SelectedLocation : INotifyPropertyChanged
{
private Layout _layout;
public Layout Layout
{
get
{
return this._layout;
}
set
{
this._layout = value;
this.OnPropertyChanged("Layout");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
var safeEvent = this.PropertyChanged;
if (safeEvent != null)
{
safeEvent(this, new PropertyChangedEventArgs(name));
}
}
}
And Window class with dependency properties (actually, in my example StartupView is UserControl, but it doesn't matter):
public partial class StartupView : UserControl
{
public StartupView()
{
InitializeComponent();
this.Layouts = new Layout[] { new Layout("AAA"), new Layout("BBB"), new Layout("CCC") };
this.SelectedLocation = new SelectedLocation();
this.SelectedLocation.Layout = this.Layouts.ElementAt(1);
}
public IEnumerable<Layout> Layouts
{
get
{
return (IEnumerable<Layout>)this.GetValue(StartupView.LayoutsProperty);
}
set
{
this.SetValue(StartupView.LayoutsProperty, value);
}
}
public static readonly DependencyProperty LayoutsProperty =
DependencyProperty.Register("Layouts",
typeof(IEnumerable<Layout>),
typeof(StartupView),
new FrameworkPropertyMetadata(null));
public SelectedLocation SelectedLocation
{
get
{
return (SelectedLocation)this.GetValue(StartupView.SelectedLocationProperty);
}
set
{
this.SetValue(StartupView.SelectedLocationProperty, value);
}
}
public static readonly DependencyProperty SelectedLocationProperty =
DependencyProperty.Register("SelectedLocation",
typeof(SelectedLocation),
typeof(StartupView),
new FrameworkPropertyMetadata(null));
}
XAML of StartupView:
<UserControl x:Class="Test.StartupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:self="clr-namespace:HandyCopy"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="Root">
<WrapPanel>
<ComboBox ItemsSource="{Binding Path=Layouts,ElementName=Root}"
SelectedItem="{Binding Path=SelectedLocation.Layout, ElementName=Root}"/>
</WrapPanel>
</UserControl>

INotifyPropertyChanged not working on ObservableCollection property

I have a class called IssuesView which implements INotifyPropertyChanged. This class holds an ObservableCollection<Issue> and exposes it as a DependencyProperty called Issues for consumption by Bindings. It is defined as below -
public class IssuesView : DependencyObject, INotifyPropertyChanged
{
public Issues Issues
{
get { return (Issues)GetValue(IssuesProperty); }
set
{
SetValue(IssuesProperty, value);
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Issues"));
}
}
}
// Using a DependencyProperty as the backing store for Issues. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IssuesProperty =
DependencyProperty.Register("Issues", typeof(Issues), typeof(IssuesView), new UIPropertyMetadata(null));
public IssuesView()
{
Refresh();
}
public void Refresh()
{
this.Issues = new Issues();
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
I have a test page declared like this -
<Page x:Class="Tracker.Pages.DEMO"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cont="clr-namespace:Tracker.Controls"
Title="DEMO">
<StackPanel>
<Button Click="Button_Click">Change</Button>
<cont:IssueTimeline IssuesForTimeline="{Binding Source={StaticResource issuesView},Path = Issues}"/>
</StackPanel>
The IssuesView class is defined in Application.Resources.
Now in the event hadnler for the button i have this code -
private void Button_Click(object sender, RoutedEventArgs e)
{
IssuesView iv = Application.Current.FindResource("issuesView") as IssuesView;
if (!once)
{
foreach (Issue i in iv.Issues)
{
i.DormantFor = new TimeSpan(30, 0, 0, 0);
i.AssignedUserID = 12;
i.Name = "MyName";
i.Priority = Issue.Priorities.Critical;
i.Status = Issue.Statuses.New;
i.Summary = "NewSummary";
}
once = true;
}
else
{
iv.Refresh();
}
once is a simple boolean to test mutation of the collection versus repopulation.
The first button click alters the collection's items and the UI is updated properly since the items implement INotifyPropertyChanged but the second click repopulates the collection but does not update the UI even though the event is not null and fires properly.
Why does the UI not update on the second click? How can i make it so that repopulating the collection will cause a UI update?
You really need to simplify your repro. I can see several things wrong with it, but cannot help to solve your problem without seeing all of it. Here is my simple repro, which works just fine.
Window1.xaml:
<Window x:Name="_root" x:Class="CollectionRepro.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel DataContext="{Binding ElementName=_root}">
<ItemsControl ItemsSource="{Binding Issues}"/>
<Button x:Name="_addButton">Add</Button>
<Button x:Name="_resetButton">Reset</Button>
</StackPanel>
</Window>
Window1.xaml.cs:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
namespace CollectionRepro
{
public partial class Window1 : Window
{
public static readonly DependencyProperty IssuesProperty = DependencyProperty.Register("Issues",
typeof(ICollection<string>),
typeof(Window1));
public ICollection<string> Issues
{
get { return (ICollection<string>)GetValue(IssuesProperty); }
set { SetValue(IssuesProperty, value); }
}
public Window1()
{
InitializeComponent();
Reset();
_addButton.Click +=new RoutedEventHandler(_addButton_Click);
_resetButton.Click += new RoutedEventHandler(_resetButton_Click);
}
void _resetButton_Click(object sender, RoutedEventArgs e)
{
Reset();
}
void _addButton_Click(object sender, RoutedEventArgs e)
{
Issues.Add("Another issue");
}
private void Reset()
{
Issues = new ObservableCollection<string>();
}
}
}
First: there's no reason to implement INotifyProperty changed for DependencyProperties. DependencyProperties know when they change.
Second: I don't see an ObservableCollection in your code.
Third: it's not entirely clear to me (from the code you posted) where the issues you modify in the first click come from. I assume from another action, not posted here.
Am I correct if I assume that you want to clear the issues list with the second click (since I don't know what the Issues constructor does)?

Resources