I did this like 50 times before. I really don't know why it is not working this time. I have a WPF application and my only dependency is MahApps.Metro. I'm using it's MetroWindow and Dynamic Style on my Button.
Here is the latest xaml:
<ItemsControl Grid.Column="0" Grid.Row="1" ItemsSource="{Binding ServerList}" Margin="5">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="LightGray">
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource MetroCircleButtonStyle}" Content="{StaticResource appbar_monitor}" Command="{Binding VM.ServerSelectedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Controls:MetroWindow}}" CommandParameter="{Binding .}"></Button>
<Label Content="{Binding .}" HorizontalAlignment="Center" VerticalAlignment="Center"></Label>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here is my ServerSelectedCommand in my ViewModel:
private ViewModelCommand _ServerSelectedCommand;
public ViewModelCommand ServerSelectedCommand
{
get
{
if (_ServerSelectedCommand == null)
{
_ServerSelectedCommand = new ViewModelCommand(
p => { SelectServer(p); },
p => true
);
}
return _ServerSelectedCommand;
}
set { _ServerSelectedCommand = value; }
}
private void SelectServer(object parameter)
{
}
ViewModelCommand class is like RelayCommand. Here it is:
public class ViewModelCommand : Observable, ICommand
{
public bool CanExecuteValue
{
get { return CanExecute(null); }
}
public ViewModelCommand(
Action<object> executeAction,
Predicate<object> canExecute)
{
if (executeAction == null)
throw new ArgumentNullException("executeAction");
_executeAction = executeAction;
_canExecute = canExecute;
}
private readonly Predicate<object> _canExecute;
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged;
public void OnCanExecuteChanged()
{
OnPropertyChanged(() => CanExecuteValue);
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
private readonly Action<object> _executeAction;
public void Execute(object parameter)
{
_executeAction(parameter);
}
}
Sorry for a lot of code. But I need to add them in order to find the problem which I can't see. So lets turn back to first xaml, that is the latest one I tried. Here are the codes that I tried for problematic Button line.
Command="{Binding ServerSelectedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}"
Command="{Binding ServerSelectedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:ViewModel}}}"
This also doesn't provide anything!
Command="{Binding RelativeSource={RelativeSource AncestorType=Controls:MetroWindow}}"
Thanks!
This binding looks like it is looking for ServerSelectedCommand on the ItemsControl:
Command="{Binding ServerSelectedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}"
try this instead:
Command="{Binding DataContext.ServerSelectedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}"
Assuming of course that the DataContext of the ItemsControl is your ViewModel.
Related
I'm trying to bind a method to the value changed of a slider.
I'm using devexpress poco,
XAML:
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Height="140" Margin="20">
<Slider Height="100" Width="40" Margin="5" HorizontalAlignment="Left" TickFrequency="10" TickPlacement="BottomRight" Orientation="Vertical" Minimum="0" Maximum="100" Value="{Binding VolumeLevel}">
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="ValueChanged" Command="{Binding Path=VolumeChangedCommand}" />
</dxmvvm:Interaction.Behaviors>
</Slider>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
My C# Code:
public void VolumeChanged()
{
...
}
The method never gets called.
Any suggestions?
Because you are binding the slider to a Command (this line: <dxmvvm:EventToCommand EventName="ValueChanged" Command="{Binding Path=VolumeChangedCommand}" />), and you don't have a Command so it won't fire. All you need to do is add a public Command VolumeChangedCommand
private ICommand _VolumeChangedCommand;
public ICommand VolumeChangedCommand
{
get
{
if (_VolumeChangedCommand == null)
_VolumeChangedCommand = new CommandImplement();
return _VolumeChangedCommand ;
}
set
{
_VolumeChangedCommand = value;
}
}
class CommandImplement: ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
VolumeChanged(); //Call your method or put your code here.
}
}
I have a ListView with a list of name and I want to be able to rename each value by double click or with a button.
I already did this for the doubleclick and it's working using this :
WPF
<ListView Grid.Row="0" x:Name="ListProfileView"
ItemsSource="{Binding ProfilesCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Name}" IsReadOnly="True" VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction
Command="{Binding DataContext.RenameCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource MultiConverter}">
<Binding RelativeSource="{RelativeSource AncestorType={x:Type TextBox}}"/>
<Binding Source="{x:Static classes:BooleanHelper.False}"/>
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction
Command="{Binding DataContext.RenameCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource MultiConverter}">
<Binding RelativeSource="{RelativeSource AncestorType={x:Type TextBox}}"/>
<Binding Source="{x:Static classes:BooleanHelper.True}"/>
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
c# (MVVM model with ICommand):
private ICommand _renameCommand;
/// <summary>
/// Command used to change the name of the selected profile.
/// </summary>
public ICommand RenameCommand
{
get
{
return _renameCommand ?? (_renameCommand = new RelayCommand<object>(obj =>
{
if(!(obj is object[] values)) return;
if(!(values[0] is TextBox txtBox) || !(values[1] is bool value)) return;
txtBox.IsReadOnly = value;
if (!value)
{
txtBox.Focus();
}
}));
}
}
But for the button, I don't know how to get the path to the textbox to use the same command.
I tried things like that :
<Button Grid.Column="3" Content="{x:Static dictionnaries:ColorConfigurationDictionnary.rename}"
FontWeight="SemiBold"
Command="{Binding RenameCommand}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource MultiConverter}">
<Binding ElementName="ListProfileView" Path="ItemContainerGenerator"/>
<Binding Source="{x:Static classes:BooleanHelper.False}"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
But I'm out of idea... Is that possible ?
It seems that there is some sort of misinformation going about so let me describe how MvvM works in the best way I can think of.
Model is where you store your data so let's call that a profile:
namespace Model
{
public class Profile
{
public string Name { get; set; }
}
}
Now what you need is a ViewModel which will provide Information which is manipulated data:
using VM.Commands;
namespace VM
{
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
ProfilesCollection = new List<Profile>();
for (int i = 0; i < 100; i++)
{
ProfilesCollection.Add(new Profile() {Name = $"Name {i}"});
}
RenameCommand = new TestCommand(renameCommandMethod, (o) => true);
}
void renameCommandMethod(object parameter)// to manipulate the colleciton you use the Commands which you already do but without the need for converters or any UI elements. Makes it much easier to handle.
{
string renameTo = parameter.ToString();
foreach (var profile in ProfilesCollection)
{
profile.Name = renameTo;
}
}
private List<Profile> profilesCollection;
public List<Profile> ProfilesCollection
{
get { return profilesCollection; }
set { profilesCollection = value; OnPropertyChanged(); }
}
private ICommand renameCommand;
public ICommand RenameCommand
{
get { return renameCommand; }
set { renameCommand = value; }
}
And the implementation of the RelayCommand:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace VM.Commands
{
public class TestCommand : ICommand
{
private Action<object> _execute;
private Predicate<object> _canExecute;
public TestCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
#region Implementation of ICommand
public bool CanExecute(object parameter)
{
return _canExecute?.Invoke(parameter) ?? true;
}
public void Execute(object parameter)
{
_execute?.Invoke(parameter);
}
public event EventHandler CanExecuteChanged;
#endregion
}
}
Then UI looks like this:
<Window x:Class="SO_app.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:vm="clr-namespace:VM;assembly=VM"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:converter="clr-namespace:SO_app.Converters"
xmlns:validation="clr-namespace:SO_app.Validation"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:local="clr-namespace:SO_app"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:model="clr-namespace:Model;assembly=Model"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=vm:MainViewModel, IsDesignTimeCreatable=True}"
Title="MainWindow" Height="452.762" Width="525" Closing="Window_Closing">
<Window.Resources>
<CollectionViewSource Source="{Binding ProfilesCollection}" x:Key="profiles"/>
</Window.Resources>
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Window.Background>
<VisualBrush>
<VisualBrush.Visual>
<Rectangle Width="50" Height="50" Fill="ForestGreen"></Rectangle>
</VisualBrush.Visual>
</VisualBrush>
</Window.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding Source={StaticResource profiles}}"
VirtualizingPanel.VirtualizationMode="Recycling">
<ListView.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<ToolTip x:Key="Tip">
<TextBlock>
<Run>Some text here</Run>
<LineBreak/>
<Run Text="{Binding Name, StringFormat='Actual Text: {0}'}"/>
</TextBlock>
</ToolTip>
</DataTemplate.Resources>
<TextBlock Text="{Binding Name}" ToolTip="{StaticResource Tip}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel Grid.Column="1">
<Button Content="Rename" Command="{Binding RenameCommand}" CommandParameter="NewName"></Button>
</StackPanel>
</Grid>
What this gives you is:
* Clean UI without any converters
* Every operation is done in the ViewModel without passing any UI elements.
* In UI you would do stuff like Styles with animation or setting font for text elements. But avoid handling clicks there. It is possible and sometimes it can't be avoided but try to utilise your ViewModel to manipulate the data.
BTW there are no controllers in here.
If you have any questions just ask.
Here is what I did:
that let me change the name of one value only by disabling the readonly of the textboxes in the list view.
I wrote that in the GUI code behind.
private ICommand _renameCommand;
/// <summary>
/// Command used to change the name of the selected profile.
/// </summary>
public ICommand RenameCommand
{
get
{
return _renameCommand ?? (_renameCommand = new RelayCommand<object>(obj =>
{
if(!(obj is object[] values)) return;
if(!(values[0] is TextBox || values[0] is SetConfiguration) || !(values[1] is bool value)) return;
if (values[0] is TextBox txtBox)
{
txtBox.IsReadOnly = value;
if (!value)
{
txtBox.Focus();
txtBox.SelectAll();
}
}
if (values[0] is SetConfiguration config)
{
var listView = ListProfileView.ItemContainerGenerator.ContainerFromItem(config) as ListViewItem;
var presenter = FindVisualChild<ContentPresenter>(listView);
if(!(presenter.ContentTemplate.FindName("ProfileName", presenter) is TextBox txtBoxItem)) return;
if (!value)
{
txtBoxItem.Focus();
txtBoxItem.SelectAll();
}
txtBoxItem.IsReadOnly = value;
}
}));
}
}
private static TChildItem FindVisualChild<TChildItem>(DependencyObject obj)
where TChildItem : DependencyObject
{
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
var child = VisualTreeHelper.GetChild(obj, i);
if (child is TChildItem item)
return item;
var childOfChild = FindVisualChild<TChildItem>(child);
if (childOfChild != null)
return childOfChild;
}
return null;
}
I have a gridview in UWP app and I have put a button in each gridview item in datatemplate so that it can be used to delete/remove that specific item from the gridview ( removing it from observableCollection behind). I am not using MVVM approach, because I am not much familiar with it, I am using a normal Observable Collection for binding of data and data template.
if you can suggest me a better way to do it, myabe using MVVM please suggest me how to do it. Thanks in advance
Code :
XAML GRID VIEW (button with the red back ground is the button I wanna use to delete item)
<controls:AdaptiveGridView Name="HistoryGridView" StretchContentForSingleRow="False"
Style="{StaticResource MainGridView}"
ItemClick ="HistoryGridView_SelectionChanged"
ItemsSource="{x:Bind HistoryVideos, Mode=OneWay}">
<controls:AdaptiveGridView.ItemTemplate>
<DataTemplate x:DataType="data:Video">
<StackPanel Margin="4" >
<Grid>
<Button Background="Red"
HorizontalAlignment="Right" VerticalAlignment="Top"
Height="36" Canvas.ZIndex="1"
Style="{StaticResource TransparentButton}" Width="36">
<fa:FontAwesome Icon="Close" FontSize="20" HorizontalAlignment="Center" Foreground="White"
/>
</Button>
<Image Canvas.ZIndex="0" Source="{x:Bind Thumbnail}" Style="{StaticResource GridViewImage}"/>
<Border Style="{StaticResource TimeBorder}" Height="Auto" VerticalAlignment="Bottom"
Canvas.ZIndex="1"
HorizontalAlignment="Left">
<TextBlock Text="{x:Bind Duration}" Foreground="White" Height="Auto"/>
</Border>
</Grid>
<TextBlock Text="{x:Bind Name}" Style="{StaticResource GridViewVideoName}"/>
<TextBlock Text="{x:Bind ParentName}" Style="{StaticResource GridViewParentName}"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{x:Bind Views}" Style="{StaticResource GridViewViews}"/>
<TextBlock Text="Views" HorizontalAlignment="Right"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
</controls:AdaptiveGridView>
Code Behind
public History()
{
this.InitializeComponent();
HistoryVideos = new ObservableCollection<Video>();
}
public ObservableCollection<Video> HistoryVideos { get; private set; }
I am using onnavigated to method for filling the collection and it works fine and also I guess that is not relevent here.
We can add the Command to the Button to invoke when this button is pressed and we can use parameter to pass to the Command property.
To use the Command, we should be able to define a DelegateCommand class that inherits from the ICommand.
For example:
internal class DelegateCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public DelegateCommand(Action<object> execute)
{
this.execute = execute;
this.canExecute = (x) => { return true; };
}
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute(parameter);
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
public void Execute(object parameter)
{
execute(parameter);
}
}
We can add the Id property in the Video, then we can pass the Id property to the CommandParameter. When we click the Button, the ExecuteDeleteCommand method will be fired. We can use the Id to find the Video in the HistoryVideos and use the Remove method to remove it.
The ViewModel code:
internal class ViewModel
{
private ObservableCollection<Viedo> _videos;
public ObservableCollection<Viedo> Videos
{
get
{
return _videos;
}
set
{
if (_videos != value)
{
_videos = value;
}
}
}
public ICommand DeleteCommand { set; get; }
private void ExecuteDeleteCommand(object param)
{
int id = (Int32)param;
Viedo cus = GetCustomerById(id);
if (cus != null)
{
Videos.Remove(cus);
}
}
private Viedo GetCustomerById(int id)
{
try
{
return Videos.First(x => x.Id == id);
}
catch
{
return null;
}
}
public ViewModel()
{
Videos = new ObservableCollection<Viedo>();
for (int i = 0; i < 5; i++)
{
Videos.Add(new Viedo());
Videos[i].Name = "Name";
Videos[i].Id = i;
}
this.DeleteCommand = new DelegateCommand(ExecuteDeleteCommand);
}
}
The XAML code:
<GridView Name="MyGridView" ItemsSource="{Binding Videos}">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"></TextBlock>
<Button Background="Red"
HorizontalAlignment="Right" VerticalAlignment="Top"
Height="36" Canvas.ZIndex="1"
Width="36" Command="{Binding DataContext.DeleteCommand, ElementName=MyGridView}" CommandParameter="{Binding Id}">
</Button>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The code behind:
private ViewModel myViewModel;
public MainPage()
{
this.InitializeComponent();
myViewModel = new ViewModel();
MyGridView.DataContext = myViewModel;
}
Update:
<GridView Name="MyGridView" ItemsSource="{x:Bind myViewModel.Videos}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:Viedo">
<StackPanel>
<TextBlock Text="{x:Bind Name}"></TextBlock>
<Button Background="Red"
HorizontalAlignment="Right" VerticalAlignment="Top"
Height="36" Canvas.ZIndex="1"
Width="36" Command="{Binding DataContext.DeleteCommand, ElementName=MyGridView}" CommandParameter="{Binding Id}">
</Button>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
I want to get the NamePlaylistof the Item i click on a MenuContext. But the parameter is always empty i don't know why.
It's a Menu in ListView
XML
<MenuItem Header="Add" ItemsSource="{Binding Path=ItemSourcePlaylist}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding TestCall}" CommandParameter="{Binding NamePlaylist}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<MenuItem.ItemTemplate>
<DataTemplate>
<TextBlock Name="NamePlaylistText" Text="{Binding Path=NamePlaylist}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
CommandProvider
public class CommandProvider : ICommand
{
#region Constructors
public CommandProvider(Action<object> execute) : this(execute, null) { }
public CommandProvider(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _canExecute != null ? _canExecute(parameter) : true;
}
public void Execute(object parameter)
{
if (_execute != null)
_execute(parameter);
}
public void OnCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
#endregion
private readonly Action<object> _execute = null;
private readonly Predicate<object> _canExecute = null;
}
Call
public ICommand TestCall { get { return new RelayCommand(obj => this._settingsFunction.TestFunction(obj)); } }
Function
public void TestFunction(object o)
{
var tmp = o as string;
Console.WriteLine(tmp);
Console.WriteLine("TestMdr");
}
If I understand your view model then ItemSourcePlaylist and TestCall are in one class and NamePlaylist is the property of the ItemSourcePlaylist item. If that's the case I would suggest use ItemsContainerStyle and bind Command property to parent's DataContext and CommandParameter to current item's DataContext
<MenuItem Header="Add" ItemsSource="{Binding Path=ItemSourcePlaylist}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type MenuItem}}, Path=DataContext.TestCall}"/>
<Setter Property="CommandParameter" Value="{Binding NamePlaylist}"/>
</Style>
</MenuItem.ItemContainerStyle>
<MenuItem.ItemTemplate>
<DataTemplate>
<TextBlock Name="NamePlaylistText" Text="{Binding Path=NamePlaylist}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
I have a stackpanel with image and button in it. I want to fire event when user clicks on a button in stackPanel. My code in xaml is
<StackPanel x:Uid="TemperatureMonitor" Orientation="Horizontal" HorizontalAlignment="Left" ToolTip="{DynamicResource InstrumentZweiMesswert}" Height="35">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="OnAddUserControl"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Image Width="35" Height="35" x:Uid="Image_15" Source="/Resources\png\TemperatureMonitor.png"/>
<Button x:Uid="TemperatureMonitor" Content="Temperatur Monitor" x:Name="TemperatureMonitor" IsEnabled="True" Width="135"/>
</StackPanel>
And method OnAddUserControl in my viewModel is
public void OnAddUserControl(object sender, RoutedEventArgs e)
{
//some code
}
The problem it that I don't get into OnAddUserControl. Any ideas why?
I want to fire this event when user makes leftMouseClick on a button. So I don't know why, but RelayCommand also doesn't help and not fires method OnAddUserControl. When I moved iteraction code to my button and it looks like this :
<StackPanel Background="Black" x:Uid="TemperatureMonitor" Orientation="Horizontal" HorizontalAlignment="Left" ToolTip="{DynamicResource InstrumentZweiMesswert}" Height="35">
<Image Width="35" Height="35" x:Uid="Image_15" Source="/Resources\png\TemperatureMonitor.PNG"/>
<Button x:Uid="TemperatureMonitor" Content="Temperatur Monitor" x:Name="TemperatureMonitor" IsEnabled="True" Width="135" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="OnAddUserControl"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
i've get during runtime mistake that says "For object Type"DockSite" cannot find methodname "OnAddUserControl"". I will appreciate any ideas or help
You can use RelayCommand for this purpose.
Add RelayCommand.cs to your project.
class RelayCommand : ICommand
{
private Action<object> _action;
public RelayCommand(Action<object> action)
{
_action = action;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
if (parameter != null)
{
_action(parameter);
}
else
{
_action("Hello World");
}
}
#endregion
}
And this is your ViewModel. I called this MainWindowViewModel. So, add MainWindowViewModel.cs class to your solution.
class MainWindowViewModel
{
private ICommand m_ButtonCommand;
public ICommand ButtonCommand
{
get
{
return m_ButtonCommand;
}
set
{
m_ButtonCommand = value;
}
}
public MainWindowViewModel()
{
ButtonCommand=new RelayCommand(new Action<object>(ShowMessage));
}
public void ShowMessage(object obj)
{
MessageBox.Show(obj.ToString());
}
}
And this is your xaml:
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<StackPanel>
<Button Width="220" Content="Click me" Command={Binding ButtonCommand} CommandParameter="StackOverflow" />
</StackPanel>
It will show you messageBox after clicking button. So you change your project for handing Button Click event in this way.