I try to bind my CheckBox into my commnd.
Base view model
public ViewModelBase()
{
SelectedFileCommand = new SelectedFileCommand(this);
}
<Page.DataContext>
<viewmodel:ViewModelBase/>
</Page.DataContext>
Command
public class SelectedFileCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public ViewModelBase ViewModel { get; set; }
public SelectedFileCommand(ViewModelBase viewModel)
{
ViewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
}
}
}
My CheckBox
<CheckBox IsChecked="{Binding IsSelected}"
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding SelectedFileCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
I also Try:
<CheckBox DataContext="{Binding}"
<i:Interaction.Triggers>
<i:EventTrigger EventName="IsChecked">
<i:InvokeCommandAction Command="{Binding SelectedFileCommand}"
CommandParameter="CheckBox.IsChecked"/>
</i:EventTrigger>
</i:Interaction.Triggers>
But my Execute function not called.
EDIT
I forgot to mention that this CheckBox is inside ListViewItem
Working solution
<CheckBox IsChecked="{Binding IsSelected}"
Command="{Binding DataContext.CheckBoxSelectedFileCommand, ElementName=mainView}"
CommandParameter="{Binding IsChecked}"/>
If the checkbox is in a listview when you say Command="{Binding SelectedFileCommand}" you will bind to the listview item's datacontext. If yor command is in the viewmodel of your window this won't work. Something like this will bind to the command that is in your main viewmodel.
Command="{Binding DataContext.SelectedFileCommand, ElementName=mainView}"
Here I gave the window x:Name=mainView. This way I can bind to properties of it's dataContext.
And, IsChecked is not an event you should use "Checked".
Last, the command parameter issue. Since there are two different events for checkbox (Checked/Unchecked) you can use two commands and not pass any parameters. Or you can put a property in the list item viewmodel like;
public bool IsChecked { get; set; }
and you can bind your checkbox's IsChecked property to this property. And finally you can bind command parameter to this new property.
Edit: Full example
<Window x:Class="WpfApp2.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:i="http://schemas.microsoft.com/expression/2010/interactivity"
x:Name="mainView"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsChecked}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding DataContext.SelectedFileCommand, ElementName=mainView}"
CommandParameter="{Binding IsChecked}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
Codebehind:
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
public class MainViewModel
{
public ObservableCollection<ItemViewModel> Items { get; set; } = new ObservableCollection<ItemViewModel>();
public ICommand SelectedFileCommand { get; set; }
public MainViewModel()
{
SelectedFileCommand = new SelectedFileCommand(this);
this.Items.Add(new ItemViewModel() { Text = "Item 1" });
this.Items.Add(new ItemViewModel() { Text = "Item 2" });
this.Items.Add(new ItemViewModel() { Text = "Item 3" });
this.Items.Add(new ItemViewModel() { Text = "Item 4" });
}
}
public class ItemViewModel
{
public string Text { get; set; }
public bool IsChecked { get; set; }
}
public class SelectedFileCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public MainViewModel ViewModel { get; set; }
public SelectedFileCommand(MainViewModel viewModel)
{
ViewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var x = parameter;
}
}
}
Related
I have implement the command Binding on Text Box and implement the command for click action in Button. Initially focus is persists in the Text Box only. My issue is me tried to click the button on view through mouse. In this case my text box lost focus command triggered first that is fine but that the button click command is not invoked. Text Box lost focus event handled the event to traverse.
public partial class MainWindow : Window
{
public MainWindow()
{
this.DataContext = new ViewModel();
InitializeComponent();
txtServer.Focus();
}
}
public class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged;
private Action<object> execute;
private Predicate<object> canExecute;
private event EventHandler CanExecuteChangedInternal;
public RelayCommand(Action<object> execute = null, Predicate<object> canExecute=null )
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
execute.Invoke(parameter);
}
}
public class ViewModel
{
private void ActionRequestedEvent(object param)
{
}
private ICommand _ActionCommand;
public ICommand ActionCommand
{
get
{
if (_ActionCommand == null)
this._ActionCommand = new RelayCommand(param =>
{
ActionRequestedEvent(param);
});
return _ActionCommand;
}
set
{
_ActionCommand = value;
}
}
}
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Width="150" Name="txtServer" Height="25">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding ActionCommand}" CommandParameter="DataSetServerLostFocus"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<Button Content="..." Width="25" Height="25" Margin="3 0 0 0" Command="{Binding ActionCommand}"/>
</StackPanel>
Most likely your problem is not an implementation problem, but a problem of the testing method you have chosen.
As I assume, you have set breakpoints and are trying to "catch" a call to the ActionRequestedEvent (object param) method.
When the command is executed for the first time, control is transferred to Debug Studio.
You press "Continue" and the command is not executed a second time.
This is due to the fact that after activating the Studio, your Window loses the user focus and therefore the command for the button is no longer called.
Here is an example of testing - you will see the result of calling the method in the Studio's Output Window.
using System.Diagnostics;
using System.Windows.Input;
namespace LostFocusCommand
{
public class ViewModel
{
private int num;
private void ActionRequestedEvent(object param)
{
Debug.WriteLine($"{++num}: {param}");
}
private ICommand _actionCommand;
public ICommand ActionCommand => _actionCommand
?? (_actionCommand = new RelayCommand(ActionRequestedEvent));
}
}
public partial class LostFocusCommandWindow : Window
{
public LostFocusCommandWindow()
{
InitializeComponent();
}
}
<Window x:Class="LostFocusCommand.LostFocusCommandWindow"
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:LostFocusCommand"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
Title="LostFocusCommandWindow" Height="450" Width="800"
FocusManager.FocusedElement="{Binding ElementName=txtServer}">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Width="150" x:Name="txtServer" Height="25">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding ActionCommand}"
CommandParameter="DataSetServerLostFocus"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<Button Content="..." Width="25" Height="25" Margin="3 0 0 0"
Command="{Binding ActionCommand}"
CommandParameter="Button"/>
</StackPanel>
</StackPanel>
</Window>
I also wanted to point out to you the incorrect implementation of ICommand.
In some cases, such an implementation may not work correctly.
Use the implementation at this link: BaseInpc, RelayCommand and RelayCommand<T> classes.
I have very interesting scenario here, look:
MainWindow XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TabControl Grid.Row="0"
Grid.Column="0"
SelectionChanged="Selector_OnSelectionChanged">
<TabItem Header="First"/>
<TabItem Header="Second"/>
</TabControl>
<ContentPresenter Grid.Column="1"
Content="{Binding SelectedUserControl}">
</ContentPresenter>
</Grid>
UserControlOne XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<DataGrid Grid.Row="0"
ItemsSource="{Binding DataSource}"
SelectedItem="{Binding SelectedItem}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<Command:EventToCommand Command="{Binding SelectionChangedCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
<Button Grid.Row="1"
Content="SetSource"
Height="50"
Command="{Binding SetSourceCommand}"/>
<Button Grid.Row="2"
Content="RemoveSource"
Height="50"
Command="{Binding RemoveSourceCommand}"/>
</Grid>
UserContolTwo XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0"
Content="SetSource"
Height="50"
Command="{Binding SetSourceCommand}"/>
<Button Grid.Row="1"
Content="RemoveSource"
Command="{Binding RemoveSourceCommand}"
Height="50"/>
</Grid>
CodeBehind:
public class GridItem
{
public String Name { get; set; }
public override string ToString()
{
return Name;
}
}
public partial class Window1 : Window, INotifyPropertyChanged
{
private List<GridItem> _items;
private GridItem _selectedItem;
private List<GridItem> _dataSource;
private readonly List<UserControl> _userControlList;
private UserControl _selectedUserControl;
public UserControl SelectedUserControl
{
get { return _selectedUserControl; }
set
{
_selectedUserControl = value;
RaisePropertyChanged("SelectedUserControl");
}
}
public GridItem SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
public List<GridItem> DataSource
{
get { return _dataSource; }
set
{
_dataSource = value;
RaisePropertyChanged("DataSource");
}
}
public Window1()
{
InitializeComponent();
DataContext = this;
_items = new List<GridItem>
{
new GridItem { Name = "Igor" },
new GridItem { Name = "Vasya"},
new GridItem { Name = "Vladlen"}
};
_userControlList = new List<UserControl>
{
new UserControl1(),
new UserControl2()
};
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(String propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion INotifyPropertyChanged
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedUserControl = _userControlList[((TabControl)sender).SelectedIndex];
}
#region SetSourceCommand
private RelayCommand<Object> _setSourceCommand;
public RelayCommand<Object> SetSourceCommand
{
get
{
return _setSourceCommand ?? (_setSourceCommand =
new RelayCommand<Object>(SetSourceMethod));
}
}
private void SetSourceMethod(Object obj)
{
DataSource = _items;
SelectedItem = _items.FirstOrDefault();
}
#endregion SetSourceCommand
#region RemoveSourceCommand
private RelayCommand<Object> _removeSourceCommand;
public RelayCommand<Object> RemoveSourceCommand
{
get
{
return _removeSourceCommand ?? (_removeSourceCommand =
new RelayCommand<Object>(RemoveSourceMethod));
}
}
private void RemoveSourceMethod(Object obj)
{
DataSource = null;
}
#endregion RemoveSourceCommand
#region SelectionChangedCommand
private RelayCommand<Object> _selectionChangedCommand;
public RelayCommand<Object> SelectionChangedCommand
{
get
{
return _selectionChangedCommand ?? (_selectionChangedCommand =
new RelayCommand<Object>(SelectionChangedMethod));
}
}
private void SelectionChangedMethod(Object obj)
{
Debug.WriteLine("Event have been rised! Selected item is {0}", ((DataGrid)obj).SelectedItem ?? "NULL");
}
#endregion RemoveSourceCommand
}
I have MainWindow, that contains UserControl. UserControl is being set dinamically, so if you pick up FirstTabItem, then UserControlOne will be loaded and if you pick up SecondTabItem - UserControlTwo will be loaded into ContentPresenter of MainWindow.
If I click button SetSource on FirstTabItem (actually on UserControlOne) - then SelectionChanged event of DataGrid fires as usually. But if I click button SetSource on SecondTabItem (actually on UserControlTwo) - then SelectionChanged event of DataGrid doesn't fire at all. Despite on bouth buttons bound to the same command (SetSourceCommand).
If buttons don't placed on other controls, for example, only on different tabitems of the same TabControl - bouth buttons invokes SelectionChange event. So problem really in markup, in using UserControls.
Has anyone encoutered with that problem? How can I fix it? I don't want invoke eventhandler programmatically.
I posted all the required code here, so you can copy-paste it and try by yourself very quickly. Or I can load example project if someone interested.
Okay so here is the actual problem in your code.
The UserControl1 has a grid in which you have used the SelectedItem Dependency Property. On this specific DP you have a Command SelectionChangedCommand.
In you commands SetSourceCommand and RemoveSourceCommand you are updating SelectedItem of the data grid which fires the SelectionChangedCommand because of the event SelectionChanged.
In your UserControl2 there is no data grid nor any control which fires SelectionChanged event to call SelectionChangedCommand. Hence it is never executed.
I am having problem with the following code. I have a TreeView Control which is bound to a Collection. The TreeView does get populated with the desired results. HOwever the "IsSelected" property and ContextMenu's click Command is not firing. Following is the XAML code.
<UserControl x:Class="Plan.Views.PadView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:v="clr-namespace:Planner.Views"
xmlns:vm="clr-namespace:Planner.ViewModels"
<Grid>
<StackPanel Orientation="Vertical">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" OpacityMask="#FFECF5F5">
<TreeView ItemsSource="{Binding Pads}" Name="tree_View" Width="190">
<TreeView.ItemContainerStyle >
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding WellPadViewModel.IsSelected}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Rename" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeView}}, Path=DataContext.RenameCommand}" />
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Members}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" >
<TextBlock.InputBindings>
<KeyBinding Key="F2" Command="{Binding RenameCommand}"/>
</TextBlock.InputBindings>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
</UserControl>
And here is my ViewModel
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
using System.ComponentModel;
using WPFApplication;
namespace FieldPlanner.ViewModels
{
public class PlanViewModel : BaseViewModel
{
Collection<Pads> pads = new Collection<Pads>();
public PlanViewModel()
{
IsSelected = true;
pads = new Collection<Pad>();
}
private ICommand _RenameCommand;
public ICommand RenameCommand
{
get
{
if (_RenameCommand == null)
{
_RenameCommand = new RelayCommand1((o) =>
{
// Your logic should go here
MessageBox.Show("Please rename me");
});
}
return _RenameCommand;
}
}
public ObservableCollection<PadInfo> Members { get; set; }
private static object _selectedItem = null;
// This is public get-only here but you could implement a public setter which also selects the item.
// Also this should be moved to an instance property on a VM for the whole tree, otherwise there will be conflicts for more than one tree.
public static object SelectedItem
{
get { return _selectedItem; }
private set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnSelectedItemChanged();
}
}
}
public static void OnSelectedItemChanged()
{
// Raise event / do other things
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
_isSelected = value;
OnPropertyChanged("IsSelected");
if (_isSelected)
{
SelectedItem = this;
}
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
/// <summary>
/// Class to hold the Pads info for a tree
/// </summary>
public class Pad
{
/// <summary>
/// Default Constructor
/// </summary>
public Pad()
{
this.Members = new ObservableCollection<PadInfo>();
}
/// <summary>
/// Name of the pad
/// </summary>
public string Name { get; set; }
/// <summary>
/// Members of the pad
/// </summary>
public ObservableCollection<PadInfo> Members { get; set; }
}
/// <summary>
/// Class to hold the well and slot IDs snapped to a pad
/// </summary>
public class PadInfo
{
/// <summary>
/// Slot ID
/// </summary>
public string SlotID { get; set; }
/// <summary>
/// Well ID
/// </summary>
public string WellID { get; set; }
}
public class RelayCommand1 : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand1(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand1(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
// [DebuggerStepThrough]
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
}
}
How can I identify the issue?
You have two problems:
IsSelected:
<Setter Property="IsSelected" Value="{Binding WellPadViewModel.IsSelected}" />
In TreeViewItem DataContext is set to instance of Pad and Pad doesn't have property IsSelected You have to do sth like this:
<Setter Property="IsSelected" Value="{Binding DataContext.IsSelected, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}" />
Problem with ContextMenu is much more sirious. ContextMenu isn't in VisualTree so you cannot bind to RelativeSource. Solution is here WPF Relative source- Cannot find source for binding with reference
Best regards
Please set the Tag property in your DataTemplate to TreeViewItem. I have sth like this:
<DataTemplate>
<Grid Width="270" Height="20" Tag="{Binding DataContext, RelativeSource = {RelativeSource AncestorType={x:Type UserControl}}}">
...
<Grid.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Edit">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<command:EventToCommand Command="{Binding Tag.YOURCOMMAND}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
</DataTemplate>
It should work.
I have a CellTemplate for a column in a ListView. The CellTemplate contains a ComboBox which has an ItemTemplate. Both ItemsSource and SelectedItem is bound to another ViewModel.
The ListView is bound to an ObservableCollection on a ViewModel. Above the ListView there is a toolbar with the buttons to move the selected item up and down. I buttons a bound to and ICommand which will make a Move on the ObservableCollection.
The view is updated fine, but the selected item in the ComboBox is not using the DataTemplate and is just showing the type name.
I found out that everything is working fine if IsEditable = false, but I need this to be true.
I have created a small project that verifies the problem. Perhaps this is an issue in WPF.
Here is XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfApplication3="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type WpfApplication3:Item}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate x:Key="cellTemplate">
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" Width="100" IsEditable="true" TextSearch.TextPath="Name"/>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<ToolBar>
<Button Content="Add" Command="{Binding AddItemCommand}"/>
<Button Content="Up" Command="{Binding MoveItemUpCommand}" CommandParameter="{Binding ElementName=listView, Path=SelectedItem}"/>
<Button Content="Down" Command="{Binding MoveItemDownCommand}" CommandParameter="{Binding ElementName=listView, Path=SelectedItem}"/>
</ToolBar>
<ListView x:Name="listView" ItemsSource="{Binding Collection}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" CellTemplate="{StaticResource cellTemplate}"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
public class ViewModel
{
public ICommand AddItemCommand { get; private set; }
public ICommand MoveItemUpCommand { get; private set; }
public ICommand MoveItemDownCommand { get; private set; }
public ObservableCollection<Row> Collection { get; set; }
public ViewModel()
{
Collection = new ObservableCollection<Row>();
AddItemCommand = new RelayCommand(AddItem);
MoveItemUpCommand = new RelayCommand<Row>(MoveItemUp, CanMoveItemUp);
MoveItemDownCommand = new RelayCommand<Row>(MoveItemDown, CanMoveItemDown);
}
private bool CanMoveItemDown(Row arg)
{
if (arg == null)
return false;
return Collection.Last() != arg;
}
private void MoveItemDown(Row obj)
{
var index = Collection.IndexOf(obj);
Collection.Move(index, index + 1);
}
private bool CanMoveItemUp(Row arg)
{
if (arg == null)
return false;
return Collection.First() != arg;
}
private void MoveItemUp(Row row)
{
var index = Collection.IndexOf(row);
Collection.Move(index, index - 1);
}
private void AddItem()
{
Collection.Add(new Row());
}
}
public class Row
{
public Row()
{
Items = new List<Item> { new Item { Name = "Test1" }, new Item { Name = "Test2" } };
}
public List<Item> Items { get; set; }
public Item SelectedItem { get; set; }
}
public class Item
{
public string Name { get; set; }
public int Order { get; set; }
}
I have a simple View that I want to bind to my ViewModel. I am currently using the Source= format for the data binding, but would like to convert that into specifying the DataContext in code.
This is what I have and it is working ...
XAML:
<Window.Resources>
<local:ViewModel x:Key="ViewModel" />
</Window.Resources>
<Button Content="Click">
<local:EventToCommand.Collection>
<local:EventToCommandCollection>
<local:EventToCommand Event="Click" Command="{Binding Source={StaticResource ViewModel}, Path=ClickCommand, diag:PresentationTraceSources.TraceLevel=High}" />
<local:EventToCommand Event="GotFocus" Command="{Binding Source={StaticResource ViewModel}, Path=GotFocusCommand}" />
</local:EventToCommandCollection>
</local:EventToCommand.Collection>
</Button>
</Window>
ViewModel Code:
public class ViewModel
{
public Command ClickCommand { get; set; }
public Command GotFocusCommand { get; set; }
public ViewModel()
{
ClickCommand = new Command((obj) => { Execute(obj); return null; });
GotFocusCommand = new Command((obj) => { Execute(obj); return null; });
}
void Execute(object param)
{
if (param != null)
System.Windows.MessageBox.Show(param.ToString());
else
System.Windows.MessageBox.Show("Execute");
}
}
Now all I want to do is this in my Window's code behind :
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
and remove the Window.Resources section in XAML, but I can not figure out how I should change my Binding strings accordingly.
The DataContext is the default Source, so this should work:
<local:EventToCommand Event="GotFocus" Command="{Binding GotFocusCommand}" />