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.
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'm learning WPF with MVVM pattern. My app is counting Body Mass Index, so it's really simple - just to help me understand the foundations of this pattern.
I was experimenting a little bit and decided to implement TextChanged event via Commands to allow user see changes in overall BMI label while he's typing a height or weight.
My textBoxes in which I use the TextChanged command are binded to ViewModel properties in TwoWay mode, so I thought that if I raise INotifyPropertyChanged event on properties binded to these textBoxes when TextChanged event occurs it will automatically update View, but it doesn't.
So question is, what am I doing wrong and how can I implement it properly?
PS. Everything else excepting View update is working (command is used, I checked with breakpoint it just doesn't change the View)
Thanks in advance
CustomCommand class:
public class CustomCommand : ICommand
{
Action<object> action;
Predicate<object> predicate;
public CustomCommand(Action<object> execute, Predicate<object> canExecute)
{
action = execute;
predicate = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public bool CanExecute(object parameter)
{
if (predicate(parameter))
return true;
else
return false;
}
public void Execute(object parameter)
{
action(parameter);
}
}
One of two textBoxes:
<TextBox HorizontalAlignment="Left" Height="23" Margin="148,83,0,0" TextWrapping="Wrap" Text="{Binding Person.Weight, Mode=TwoWay}" VerticalAlignment="Top" Width="76">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding Path=textChangedCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
And ViewModel, where TextChanged method is passed to a command
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler propertyChanged = PropertyChanged;
if (propertyChanged != null)
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public ICommand textChangedCommand { get; set; }
//public List<float> BMI_Changed;
private PersonInfo person;
public PersonInfo Person
{
get
{
return person;
}
set
{
person = value;
OnPropertyChanged("Person");
}
}
public MainWindowViewModel()
{
//BMI_Changed = new List<float>();
textChangedCommand = new CustomCommand(TextChanged, CanBeChanged);
person = Data.personInfo;
}
private void TextChanged(object obj)
{
OnPropertyChanged("BMI");
OnPropertyChanged("Weight");
OnPropertyChanged("Height");
}
private bool CanBeChanged(object obj)
{
return true;
}
}
Rest of my View code, for general overview:
<Window x:Class="SportCalculators_MVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SportCalculators_MVVM"
xmlns:enum="clr-namespace:SportCalculators_MVVM.Model"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
Title="MainWindow" Height="340.278" Width="260.256" Loaded="Window_Loaded"
DataContext="{Binding Source={StaticResource viewModelLocator}, Path=mainWindowViewModel}">
<Grid x:Name="grid">
<Slider x:Name="mass" HorizontalAlignment="Right" Margin="0,128,58,0" VerticalAlignment="Top" Width="155" Value="{Binding Person.Weight, Mode=TwoWay}" Maximum="150" Minimum="20"/>
<Slider x:Name="height" HorizontalAlignment="Left" Margin="40,210,0,0" VerticalAlignment="Top" Width="155" Minimum="100" Maximum="230" Value="{Binding Person.Height, Mode=TwoWay}"/>
<RadioButton x:Name="sex" Content="Kobieta" HorizontalAlignment="Left" Margin="45,41,0,0" VerticalAlignment="Top" IsChecked="{Binding Person.Sex, Converter={StaticResource ResourceKey=genderConverter}, ConverterParameter={x:Static enum:Sex.Female}}"/>
<RadioButton x:Name="sex1" Content="Mężczyzna" HorizontalAlignment="Left" Margin="150,41,0,0" VerticalAlignment="Top" IsChecked="{Binding Person.Sex, Converter={StaticResource ResourceKey=genderConverter}, ConverterParameter={x:Static enum:Sex.Male}}"/>
<Label x:Name="massLabel" Content="Waga" HorizontalAlignment="Left" Margin="40,80,0,0" VerticalAlignment="Top"/>
<Label x:Name="heightLabel" Content="Wzrost" HorizontalAlignment="Left" Margin="39,167,0,0" VerticalAlignment="Top"/>
<Label x:Name="label" Content="{Binding Person.BMI}" HorizontalAlignment="Left" Margin="39,274,0,0" VerticalAlignment="Top"/>
<Button Content="Statystyki" HorizontalAlignment="Left" Margin="149,274,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="0.325,-0.438"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="148,83,0,0" TextWrapping="Wrap" Text="{Binding Person.Weight, Mode=TwoWay}" VerticalAlignment="Top" Width="76">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding Path=textChangedCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<TextBox HorizontalAlignment="Left" Height="23" Margin="148,170,0,0" TextWrapping="Wrap" Text="{Binding Person.Height, Mode=TwoWay}" VerticalAlignment="Top" Width="76">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding Path=textChangedCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</Grid>
Ed Plunkett gave the simplest solution:
There is no need to write whole bunch of code to implement command while TextChanged occurs, there is a Binding property UpdateSourceTrigger which determines when there should be the update, by default it's set to LostFocus so it is for example when you click on another control, if you'd like to update it while user is typing, you need to set value to PropertyChanged and that's it!
<TextBox Text="{Binding Person.Weight, UpdateSourceTrigger=PropertyChanged}">
I am trying to bind a click on button event in WPF to a command defined in a View Model, here is how I am doing that for now :
In the xaml code :
<Grid>
<Button Content="Module A" Background="Green" FontWeight="Bold">
<i:Interaction.Triggers>
<i:EventTrigger EventName="click">
<i:InvokeCommandAction Command="{Binding ChargeModuleDCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
and in the ViewModel class :
class ModuleAViewModel
{
public DelegateCommand<object> ChargeModuleDCommand { get; set; }
public ModuleAViewModel()
{
ChargeModuleDCommand = new DelegateCommand<object>(LaunchDModule);
}
private void LaunchDModule(object parm)
{
Console.WriteLine("I am in the function");
}
}
but it does not work. I've tried to do it as specified in this question : How to trigger ViewModel command for a specific button events
but it does not work either.
Is there any way that I can make it work ?
<Button
Command="{Binding ChargeModuleDCommand}"
Content="Module A"
Background="Green"
FontWeight="Bold"
/>
If ModuleAViewModel is the Button's DataContext, that should work.
I am trying to implement modal dialog in the WPF Prism Desktop application.
From Prism guidance I can see that proper way should be using Interaction:
<i:Interaction.Triggers>
<prism:InteractionRequestTrigger
SourceObject="{Binding ConfirmCancelInteractionRequest}">
<prism:PopupChildWindowAction
ContentTemplate="{StaticResource ConfirmWindowTemplate}"/>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
But PopupChildWindowAction is not available in the Microsoft.Practices.Prism.Interactivity.DLL library for Desktop, only Silverlight?
I could google for many different implementations of the Modal Dialog in WPF (Prism), but just wondering why this feature is missing from Prism Desktop DLL and is available in Silverlight DLL?
I could use Interaction Service but Interaction Request is suggested as more appropriate approach for MVVM application.
That's true it only exists in the Silverlight prism library ,
What you can do is create your own .
CS :
public class OpenPopupWindowAction : TriggerAction<FrameworkElement>
{
protected override void Invoke(object parameter)
{
var popup = (ChildWindow)ServiceLocator.Current.GetInstance<IPopupDialogWindow>();
popup.Owner = PlacementTarget ?? (Window)ServiceLocator.Current.GetInstance<IShell>();
popup.DialogResultCommand = PopupDailogResultCommand;
popup.Show();
}
public Window PlacementTarget
{
get { return (Window)GetValue(PlacementTargetProperty); }
set { SetValue(PlacementTargetProperty, value); }
}
public static readonly DependencyProperty PlacementTargetProperty =
DependencyProperty.Register("PlacementTarget", typeof(Window), typeof(OpenPopupWindowAction), new PropertyMetadata(null));
public ICommand PopupDailogResultCommand
{
get { return (ICommand)GetValue(PopupDailogResultCommandProperty); }
set { SetValue(PopupDailogResultCommandProperty, value); }
}
public static readonly DependencyProperty PopupDailogResultCommandProperty =
DependencyProperty.Register("PopupDailogResultCommand", typeof(ICommand), typeof(OpenPopupWindowAction), new PropertyMetadata(null));
}
XAML :
<i:EventTrigger SourceObject="{Binding}" EventName="NavigatedFrom">
<popup:OpenPopupWindowAction PopupDailogResultCommand="{Binding OnNavigationConfirmed}"/>
</i:EventTrigger>
And if you need here is the Code for the DialogWindow it self .
cs:
public partial class ChildWindow : Window, IPopupDialogWindow
{
public ChildWindow()
{
InitializeComponent();
DataContext = this;
}
public new PopupDialogResult DialogResult
{
get;
set;
}
public System.Windows.Input.ICommand DialogResultCommand
{
get;
set;
}
}
xaml :
<Window x:Class="Utils.ActionPopupWindow.ChildWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="400" WindowStartupLocation="CenterOwner"
xmlns:popup="clr-namespace:Utils.ActionPopupWindow"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
x:Name="popUpWindow"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="30">
This is a child window <LineBreak/> launched from the <LineBreak/>main window
</TextBlock>
<StackPanel Grid.Row="1" Background="#FFA6A6A6">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Ok"
MinWidth="100"
Command="{Binding DialogResultCommand}"
CommandParameter="{x:Static popup:PopupDialogResult.OK}"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction MethodName="Close" TargetObject="{Binding ElementName=popUpWindow}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="Cancel"
MinWidth="100"
Command="{Binding DialogResultCommand}"
CommandParameter="{x:Static popup:PopupDialogResult.Cancel}"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction MethodName="Close" TargetObject="{Binding ElementName=popUpWindow}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</StackPanel>
</Grid>
Here is an example made in WPF:
http://blogs.southworks.net/dcherubini/2012/05/24/popupwindowaction-using-custom-views-instead-of-windows-in-wpf-and-prism/
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.