I want to add a method to my custom control which I can call from a button using command binding, in my MainWindow.xaml. I've come across a few solutions online, however one of them didn't appear to work and the other did. Can someone explain to me the correct way to set this up. The first solution produces and error as mentioned below. The second solution works but I'm not sure of any pros/cons.
Solution 1 - broken
public partial class MyControl : Control
{
...
public static readonly RoutedCommand AlignLeftCommand = null;
static MyControl()
{
binding = new CommandBinding();
binding.Command = AlignLeftCommand;
binding.Executed += new ExecutedRoutedEventHandler(AlignLeft_Executed);
CommandManager.RegisterClassCommandBinding(typeof(MyControl), binding);
}
}
Error:
Severity Code Description Project File Line
Error CS0120 An object reference is required for the non-static field, method, or property...
Solution 2
public partial class MyControl : Control
{
...
public static readonly RoutedCommand AlignLeftCommand = new RoutedCommand();
public MyControl()
{
this.CommandBindings.Add(new CommandBinding(MyControl.AlignLeftCommand, AlignLeft_Executed, null));
}
}
Here is the button calling the method.
<StackPanel Orientation="Horizontal">
<Button Content="Left Edges" FontSize="8"
Command="{x:Static JM:MyControl.AlignLeftCommand}"
CommandTarget="{Binding ElementName=mycontrol}"/>
</StackPanel>
At first, you should define a command binding on the Window like that(create handlers for Executed and CanExecuteevents):
<Window x:Class="CommandBindingWPF.MainWindow"
...The code omitted for the brevity...
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.New" Executed="CommandBinding_Executed" CanExecute="CommandBinding_CanExecute" />
</Window.CommandBindings>
and declare your Button ix xaml:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Command="ApplicationCommands.New">New</Button>
</StackPanel>
Handlers should be created in code-behind after you command binding created:
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Hello from Command");
}
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{ }
Update:
For MVVM application:
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
Then create a property in your viewModel. For instance:
public class YourViewModel
{
public RelayCommand YourCommand { get; set; }
public YourViewModel()
{
YourCommand = new RelayCommand(DoSmth, CanDoSmth);
}
private void DoSmth(object obj)
{
Message.Box("Hello from viewModel");
}
private bool CanDoSmth(object obj)
{
//you could implement your logic here. But by default it should be
//set to true
return true;
}
}
And XAML should be look like:
<Button Content="Click me!" Command="{Binding YourCommand}"/>
To get acquainted with MVVM, I recommend you to read Rachel Lim's blog. She has a talent to teach people and she can explain by simple terms. Read Rachel Lim's blog.
To get acquainted with MVVM commands see that post
Related
So I'm currently looking into commands and what I've done as of right now is that I made a command, bound it to a button and I've passed in a bool property which will indicate whether or not the button can execute the command.
The issue is that the button starts off as enabled, and as soon as I click it, it turns disabled, and then the person gets added to the ListView, but the button stays disabled.
I'm not sure if I need to add a UpdateSourceTrigger to the command, I thought the whole point of implementing a ObservableObject was to not have to do that.
What's the proper way of achieving what I'm trying to achieve?
The Command
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
The MainWindow (DataContext)
<Window x:Class="Commands.MainWindow"
...
Title="MainWindow"
Height="450"
Width="800">
<Window.DataContext>
<viewmodel:MainViewModel />
</Window.DataContext>
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center">
<ListView MinHeight="100"
ItemsSource="{Binding PeopleCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="Add"
Width="100"
Height="25"
Command="{Binding AddPersonCommand}" />
</StackPanel>
</Window>
The MainViewModel
internal class MainViewModel : ObservableObject
{
public ObservableCollection<PersonModel> PeopleCollection { get; set; }
/* A slow working command */
public RelayCommand AddPersonCommand { get; set; }
private bool _canExecute;
public bool CanExecute
{
get { return _canExecute; }
set
{
_canExecute = value;
NotifyPropertyChanged("CanExecute");
}
}
public MainViewModel()
{
CanExecute = true;
PeopleCollection = new ObservableCollection<PersonModel>();
AddPersonCommand = new RelayCommand(o => AddPersonToCollection(o), (p) => CanExecute);
}
private async void AddPersonToCollection(object o)
{
CanExecute = false;
await Task.Factory.StartNew(() =>
{
/* Simulate a heavy workload*/
Thread.Sleep(5000);
Application.Current.Dispatcher.BeginInvoke(() =>
{
PeopleCollection.Add(new PersonModel
{
Id = 0,
Name = "Foo bar"
});
});
/* Property needs to be updated from the main thread? */
//CanExecute = false;
});
CanExecute = false;
}
}
The ObservableObject
internal class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I'm failing to see how your Button is actually being marked as disabled. I see the CanExecute bool being manipulated, but your button doesn't have IsEnabled bound. Even if that is the case, as #PaulSinnema said, you are only setting CanExecute to false (besides the first set in the constructor). I would suggest trying to set CanExecute = true inside of your Task and inside your lambda function (in the BeginInvoke) so then you can ensure the timing is correct. As you currently have it, your AddPersonToCollection method is doing the following:
Sets CanExecute to false
Fires off a task and waits for it to complete
Sets CanExecute to false
Here's my suggestion, hopefully it helps:
private async void AddPersonToCollection(object o)
{
CanExecute = false;
await Task.Factory.StartNew(() =>
{
/* Simulate a heavy workload*/
Thread.Sleep(5000);
Application.Current.Dispatcher.BeginInvoke(() =>
{
PeopleCollection.Add(new PersonModel
{
Id = 0,
Name = "Foo bar"
});
// Setting it here ensures we flip it as soon as the collection has a person added
CanExecute = true;
});
});
// Remove this line
///CanExecute = false;
}
I`m trying to do a simple WPF application using MVVM pattern. I wrote a class implementing ICommand interface:
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
then I use it, when I click on the button in the view, to show a new page, by assigning a page to the current page
public ICommand bFirst_Click
{
get
{
return new RelayCommand(o => CurrentPage = first);
}
}
XAML code in view
<StackPanel>
<Button Command="{Binding bFirst_Click}" Content="First"/>
</StackPanel>
<Frame
Grid.Column="1"
Content="{Binding CurrentPage}"
NavigationUIVisibility="Hidden"
Opacity="{Binding FrameOpacity}"
/>
But nothing happens. Please help me, did I miss something, or doing it in the wrong way?
I have set a bool property and have bound it to the IsEnabled in the xaml but the ICommand CanExecute method overrides the IsEnabled in xaml, so my bool property is ineffective.
When I define the conditions within the CanExecute method in the view model, It either disables all buttons in which the method is bound to, or enables all of them.
Its a grid that displays 3 different buttons for each row, and each button goes to a new xaml screen. If there is no data for the particular condition on the row the button is on then the button needs to be disabled.
How do i go about setting this so that buttons are disabled upon a condition?
Custom Command:
public class CustomCommand : ICommand
{
private Action<object> execute;
private Predicate<object> canExecute;
public CustomCommand(Action<object> execute, Predicate<object> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
}
remove
{
}
}
public bool CanExecute(object parameter)
{
//throw new NotImplementedException();
bool b = canExecute == null ? true : canExecute(parameter);
return b;
}
public void Execute(object parameter)
{
execute(parameter);
}
}
xaml
<DataTemplate>
<Button Command="{Binding Source={StaticResource VM},
Path=Command}" CommandParameter="{Binding}" >
<SymbolIcon Symbol="Edit" Foreground="AliceBlue" />
</Button>
</DataTemplate>
CanExecute in VM
private bool CanGetDetails(object obj)
{
return true;
}
You can always do your conditional statement within the CanExecute function of your custom command, no need for you to bind IsEnabled property with your button that is bound to a command. Here's a sample implementation, hope this helps.
Custom Command:
public class CustomCommand<T> : ICommand
{
private readonly Action<T> _action;
private readonly Predicate<T> _canExecute;
public CustomCommand(Action<T> action, Predicate<T> canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute((T)parameter);
}
public void Execute(object parameter)
{
_action((T)parameter);
}
public event EventHandler CanExecuteChanged;
}
As you can see here, I created an object that implements the ICommand interface, this custom command accepts a generic type parameter which is used to evaluate a condition (CanExecute: this tells whether to enable or disable a command (in UI, the button), normally use to check for permissions, and other certain conditions) this parameter is also used to execute the action (Execute: the actual logic/action to be performed), The command contructor accepts delegate parameters that contain signatures for these 2 methods, the caller may choose lambda or standard methods to fillup these parameters.
Sample ViewModel:
public class ViewModel1: INotifyPropertyChanged
{
public ViewModel1()
{
// Test Data.
Items = new ObservableCollection<ItemViewModel>
{
new ItemViewModel{ Code = "001", Description = "Paint" },
new ItemViewModel{ Code = "002", Description = "Brush" },
new ItemViewModel{ Code = "003", Description = "" }
};
EditCommand = new CustomCommand<ItemViewModel>(Edit, CanEdit);
}
public CustomCommand<ItemViewModel> EditCommand { get; }
private bool CanEdit(ItemViewModel item)
{
return item?.Description != string.Empty;
}
private void Edit(ItemViewModel item)
{
Debug.WriteLine("Selected Item: {0} - {1}", item.Code, item.Description);
}
private ObservableCollection<ItemViewModel> _items { get; set; }
public ObservableCollection<ItemViewModel> Items
{
get => _items;
set
{
_items = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<Page x:Name="root"
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vms="using:App1.ViewModels"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
d:DesignHeight="450" d:DesignWidth="800">
<Page.DataContext>
<vms:ViewModel1 x:Name="Model"/>
</Page.DataContext>
<Grid>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0 0 0 15">
<TextBlock Text="{Binding Code}" />
<TextBlock Text="{Binding Description}" />
<Button Content="Edit" Command="{Binding DataContext.EditCommand, ElementName=root}" CommandParameter="{Binding}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Page>
I think you can pick a lot of code from the RelayCommand of MVVMLight. Try to change your event to
public event EventHandler CanExecuteChanged
{
add
{
if (canExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if (canExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
and add also a function
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
Then, whatever you put as your Predicate on the command, at the Predicate's boolean setter do:
SomeCustomCommand.RaiseCanExecuteChanged()
Hope I helped.
i am new to wpf and xaml and try to change the content of a window (Login -> Main content and main content -> Login) in an WindowsApplication (Xaml, WPF). So far i have the following for this simple login/logout scenario:
BaseViewModel
public class BaseViewModel : DependencyObject, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
BaseMainViewViewModel (Base class for setting the MainViewType Property in the MainWindow. It also contains the command to change the property via the button in the MainViews.)
public class BaseMainViewViewModel : BaseViewModel
{
private static MainViewType _CurrentMainView;
private ICommand _SwitchMainViewCommand;
public BaseMainViewViewModel()
{
SwitchMainViewCommand = new RelayCommand(SwitchMainView);
}
public MainViewType CurrentMainView
{
get { return _CurrentMainView; }
set
{
if (value != _CurrentMainView)
{
_CurrentMainView = value;
OnPropertyChanged(nameof(CurrentMainView));
}
}
}
public ICommand SwitchMainViewCommand
{
get { return _SwitchMainViewCommand; }
set { _SwitchMainViewCommand = value; }
}
#region Test
public void SwitchMainView(object param)
{
Debugger.Break();
switch (CurrentMainView)
{
case MainViewType.Login:
CurrentMainView = MainViewType.Main;
break;
case MainViewType.Main:
CurrentMainView = MainViewType.Login;
break;
default:
break;
}
MessageBox.Show("Login/Logout");
}
#endregion Test
LoginViewModel inherites from BaseMainViewViewModel to get access to the CurrentMainView-Property
public class LoginViewModel : BaseMainViewViewModel {}
MainViewModel her the same
public class MainViewModel : BaseMainViewViewModel {}
MainWindowViewModel
public class MainWindowViewModel: BaseMainViewViewModel {}
LoginMainView
public partial class LoginMainView : UserControl
{
public LoginMainView()
{
InitializeComponent();
DataContext = new LoginViewModel();
}
}
Currently i have only one button (Login-Button) in the LoginMainView. If I click this button, the current LoginMainView should be exchanged with the MainMainView.
<Grid>
<Button Content="Main" Background="Red" Command="{Binding SwitchMainViewCommand}" />
</Grid>
MainMainView
public partial class MainMainView : UserControl
{
public LoginMainView()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
here the same (Logout-Button) correspond to LoginMainView...
<Grid>
<Button Content="Logout" Background="Green" Command="{Binding SwitchMainViewCommand}" />
</Grid>
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
In the MainWindow-View i bind the CurrentMainView-Property (MainViewType) from the BaseMainViewViewModel to the contentpresenter, which i will change by clicking the button in the MainMainView/LoginMainView and the ValueConverter shold do the rest.
<Grid>
<StackPanel>
<Label Content="Test" />
<ContentPresenter Content="{Binding CurrentMainView, Converter={view:MainViewValueConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Grid>
MainViewType
public enum MainViewType
{
Login = 0,
Main = 1
}
BaseValueConverter
public abstract class BaseValueConverter<T> : MarkupExtension, IValueConverter
where T : class, new()
{
private static T _Converter = null;
public override object ProvideValue(IServiceProvider serviceProvider)
{
return _Converter ?? (_Converter = new T());
}
public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}
RelayCommand
public class RelayCommand : ICommand
{
private Action<object> _Execute;
private Predicate<object> _CanExecute;
private event EventHandler CanExecuteChangedInternal;
public RelayCommand(Action<object> execute) : this(execute, DefaultCanExecute) { }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
_Execute = execute ?? throw new ArgumentNullException("execute");
_CanExecute = canExecute ?? throw new ArgumentNullException("canExecute");
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
CanExecuteChangedInternal += value;
}
remove
{
CommandManager.RequerySuggested -= value;
CanExecuteChangedInternal -= value;
}
}
public bool CanExecute(object parameter)
{
return (_CanExecute != null) && _CanExecute(parameter);
}
public void Execute(object parameter)
{
_Execute(parameter);
}
public void OnCanExecuteChanged()
{
EventHandler eventHandler = CanExecuteChangedInternal;
if (eventHandler != null)
{
eventHandler.Invoke(this, EventArgs.Empty);
}
}
public void Destroy()
{
_CanExecute = _ => false;
_Execute = _ => { return; };
}
private static bool DefaultCanExecute(object parameter)
{
return true;
}
}
When i start the application, the ValueConverter is called and the correct View (LoginMainView) is loaded. I then click on the button in the LoginMainView, the command (SwitchMainView) is executed, but then the content of MainWindow is not changed into MainMainView because the ValueConverter is not used.
What am i doing wrong? Do i have a fundamental understanding problem? Or is it not possible in this way to map the simple login/logout scenario? Or did i simply overlook something? Can someone please tell me what i have forgotten?
Many thanks in advance to the helpers!
You don't need ValueConverter for that. You are on a right track thoug. Take a look here - this is sample application for ReactiveUI framework (which is my favourite).
It has AppBootrsapper (ViewModel of the application). As the framework does some magick around it, the basic idea is:
MainWindow.Xaml:
<Window x:Class="ReactiveUI.Samples.Routing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:rx="clr-namespace:ReactiveUI;assembly=ReactiveUI"
Title="MainWindow" Height="350" Width="525">
<Grid UseLayoutRounding="True" >
<ContentControl Content="{Binding ActiveViewModel}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="{x:Type LoginViewModel}">
<!-- here you put your content wof login screen, prefereably as seperate UserControl -->
</DataTemplate>
<DataTemplate DataType="{x:Type MainViewModel}">
<!-- here you put your content main screen, prefereably as seperate UserControl -->
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</Window>
Then you just set AppBootstrapper.ActiveViewModel = new LoginViewModel() and you have login screen.
If you login, AppBootstrapper.ActiveViewModel = new MainViewModel() and WPF displays main screen.
All that and much more is done by ReactiveUI framwork - only there instead of putting DataTemplates for ViewModels, you register UserControls as views and RoutedViewHost does all the magick. Don't do that on your own, it's inventing the wheel again.
EDIT to answer the comment:
You put AppBootstrapper.ActiveViewModel = new MainViewModel() in your NavigationService. Navigation meaning the thing that changes displayed view. Most common version is a stack, which top is active ViewModel. When you press Back button, you just pop the stack.
This all applies to MVVM model with Model First navigation, which means you first instantiate ViewModel, and navigation service finds the proper view.
You can do this in the other way: View First navigation. There are some tutorials for WPF page navigation. It works exactly the same, but instead of ViewModel, you create a page (a view) which then creates underlying data.
MVVM app model is so popular, because it allows very clean logic and presentation separation (XAML is ONLY about view, ViewModels contain all logic, Models persist the data), which in turn makes it very easy to share logic between platforms. In fact, if you do that correctly, you can use all your ViewModels in apps written in Xamarin, WPF or UWP, just by creating platform-specific views.
To wrap up, WPF allows you to switch in a property data and it will find a view for it automatically (via DataTemplates). Remember about INotifyPropertyChanged and everything will work
Hi i want to bind button with other listView.Item. What i want is to have something like we have on stackoverflow.
But i have problem with having increasing/decreasing value. I have event Click but i dont knew how to get corresponding item on list and increase/decrease value.
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Label Width="706" Height="75" Content="{Binding feedback}"/>
<StackPanel Orientation="Vertical">
<Button Name="buttonUp" Content="^" Command="{Binding upVoteCommand}" />
<Label HorizontalContentAlignment="Center" Width="50" Content="{Binding grade}"/>
<Button Name="buttonDown" Content="v" Command="{Binding upVoteCommand}"/>
</StackPanel>
</StackPanel>
<Label>-</Label>
</StackPanel >
EDIT
class A {
public string feedback {
get;
set;
}
public int grade {
get;
set;
}
private ICommand _upVoteCommand;
private ICommand _downVoteCommand;
public ICommand upVoteCommand {
get {
return _upVoteCommand;
}
set {
_upVoteCommand = value;
}
}
public ICommand downVoteCommand {
get {
return _downVoteCommand;
}
set {
_downVoteCommand = value;
}
}
}
EDIT I used this button.Commmand but still it not working. I dont knew what to do with this commands.
First you'll need your implementation of ICommand so you can bind commands from view model to controls, something like this:
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute) : this(execute, null) { }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null) throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter) { _execute(parameter); }
}
then in you class, where you publish Feedback, you'll need to publish 2 new RelayCommand for up/down vote that will modify Feedback property accordingly. Below you can find my class that I used for tests:
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private int _feedback = 0;
public int Feedback
{
get { return _feedback; }
set
{
if (_feedback == value) return;
_feedback = value;
OnPropertyChanged("Feedback");
}
}
private RelayCommand _upVoteCmd;
public ICommand UpVoteCmd
{
get
{
if (_upVoteCmd == null) _upVoteCmd = new RelayCommand(o => Feedback += 1);
return _upVoteCmd;
}
}
private RelayCommand _downVoteCmd;
public ICommand DownVoteCmd
{
get
{
if (_downVoteCmd == null) _downVoteCmd = new RelayCommand(o => Feedback -= 1);
return _downVoteCmd;
}
}
}
and then you bind your new commands in XAML like this:
<Button Content="+" Command="{Binding Path=UpVoteCmd}"/>
<TextBlock Text="{Binding Path=Feedback}"/>
<Button Content="-" Command="{Binding Path=DownVoteCmd}"/>
RoutedEvents don't work so easily with DataTemplates, because you don't have a code behind where your event code could be placed. While there are ways to do that, you can just use Commands to do the same. In the view model for each item (i just assume you use MVVM) create properties called UpVoteCommand and DownVoteCommand of type ICommand, DelegateCommands are quiet handy for this. Bind them to the Command property and remove the Click handler in your DataTemplate.
[EDIT]
Small example of a possible Viewmodel for one entry in the list, which can be up or downvoted.
class MyEntryViewModel : INotifyPropertyChanged
{
public MyEntryViewModel()
{
UpVoteCommand = new DelegateCommand(OnUpVoteCommand);
}
public int Votes
{
get {return mVotes;}
set {mVotes = value; RaiseProperty("Votes");}
}
public ICommand UpVoteCommand
{
get; private set;
}
void OnUpVoteCommand(object aParameter)
{
Votes++;
}
}
i left the implementation of INotifyPropertyChanged and the down vote command for sake of simplicity.