Relay Command not firing on menu item click - wpf

My View
<Button.ContextMenu>
<ContextMenu x:Name="Conn_Context_button" Style="{StaticResource LeftContextMenuStyle}">
<MenuItem Style="{StaticResource LeftContextMenuItemStyle}" Header="{x:Static properties:ResourceWrapper.Dashboard_Connection_Delete}" Click="MenuItem_DeleteConnection_Click" />
<MenuItem Style="{StaticResource LeftContextMenuItemStyle}" Header="{x:Static properties:ResourceWrapper.Dashboard_Connection_Refresh}" Command="{Binding MyViewModel.RefreshCommand}" />
</ContextMenu>
MyViewModel.cs
public RelayCommand RefreshCommand { get; set; }
RefreshCommand = new RelayCommand(RefreshConnection);
private void RefreshConnection(object sender)
{
//My Logic
}
Here RefreshCommand is not firing when i click the refresh menu item

As a good example, take a look to this situation.
Here's a simple piece of code taken from one of my current projets:
private void PrepareCommands()
{
RefreshCommand = new RelayCommand(RefreshCommandMethod);
AddConfigurationCommand = new RelayCommand(AddConfigurationCommandMethod, param => CanAddConfiguration);
EditConfigurationCommand = new RelayCommand(EditConfigurationCommandMethod, param => CanEditConfiguration);
RemoveConfigurationCommand = new RelayCommand(RemoveConfigurationCommandMethod, param => CanRemoveConfiguration);
}
where the commands are
#region Commands
public ICommand AddConfigurationCommand { get; set; }
public ICommand EditConfigurationCommand { get; set; }
public ICommand RemoveConfigurationCommand { get; set; }
public ICommand RefreshCommand { get; set; }
#endregion
Bindings are
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" DockPanel.Dock="Right">
<Button Template="{StaticResource AddButton}" Command="{Binding AddConfigurationCommand}" Margin="3,0" />
<Button Template="{StaticResource EditButton}" Command="{Binding EditConfigurationCommand}" Margin="3,0" />
<Button Template="{StaticResource DeleteButton}" Command="{Binding RemoveConfigurationCommand}" Margin="3,0" />
</StackPanel>
As Jan Walczak said above, try to use ICommand instead of RelayCommand. If you have created your own RelayCommand, don't forget to inherit from ICommand.

Related

Adding Icon to Dynamic Menu item in WPF

I am trying to generate MenuItem dynamically.
How can I Bind that in Style?
Here is the code.
XAML
<Window.Resources>
<Image x:Key="Image.Icon"
Source="pack://application:,,,/DynamicMenu;component/icon.png"/>
</Window.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding MenuItems}">
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="Icon">
<Setter.Value>
<Image Source="{Binding ImagePath}" Width="12" Height="12" />
</Setter.Value>
</Setter>
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}"
ItemsSource="{Binding Path=MenuItems}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Header}"/>
</StackPanel>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
<Grid>
</Grid>
</DockPanel>
ViewModel
public class MenuItemViewModel
{
private readonly ICommand _command;
public MenuItemViewModel()
{
_command = new CommandViewModel(Execute);
}
public string Header { get; set; }
public string Param1 { get; set; }
public string ImagePath { get; set; }
public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
public ICommand Command
{
get {return _command; }
}
private void Execute()
{
MessageBox.Show("Clicked at " + Header + Param1);
}
}
Command
public class CommandViewModel : ICommand
{
private readonly Action _action;
public CommandViewModel(Action action)
{
_action = action;
}
public void Execute(object o)
{
_action();
}
public bool CanExecute(object o)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { }
remove { }
}
}
I want to add a different icon for different MenuItem.
So I am planning to pass the icon file as MenuItemViewModel property.
Need a way to bind the icon property to the MenuItem.
Thanks.
I find a solution for my question:
<MenuItem Header="{Binding Path=Header}" Command="{Binding PresentationTripLegCommand}">
<MenuItem.Icon>
<Image Source="{Binding IconFileName}" Height="16" />
</MenuItem.Icon>
</MenuItem>

Add item to selection listbox on button click

I have setup a WPF with several listboxes and an add button:
<Window x:Class="QuickSlide_2._0.Window1"
x:Name="load_style"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:QuickSlide_2._0"
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
Title="Load_style" Height="300" Width="300" MinHeight="720" MinWidth="1280" WindowStyle="None" AllowsTransparency="True" Background="#B0000000" AllowDrop="True" WindowStartupLocation="CenterScreen" ShowInTaskbar="False">
<Grid>
<Rectangle Height="720" HorizontalAlignment="Left" Name="rectangle1" Stroke="#00000000" VerticalAlignment="Top" Width="1280" MinHeight="320" MinWidth="380" Fill="DarkGray"/>
<ListBox Height="241" HorizontalAlignment="Left" Margin="502,371,0,0" Name="Presentation_slide_items" VerticalAlignment="Top" Width="199" />
<ListBox Name="subjects_list" Margin="74,154,1039,171" ItemsSource="{Binding ElementName=styles_list, Path=SelectedItem.subjects}"/>
<ListBox Name="sub_subjects_list" Margin="264,154,849,171" ItemsSource="{Binding ElementName=subjects_list, Path=SelectedItem.sub_subjects}"/>
<ComboBox x:Name="styles_list" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Margin="74,112,0,0"/>
<ListBox Name="user_inputs" Margin="502,154,565,421" ItemsSource="{Binding ElementName=sub_subjects_list, Path=SelectedItem.possible_input, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding input}" BorderThickness="0" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="button_add_input" Content="Add" HorizontalAlignment="Left" Margin="502,279,0,0" VerticalAlignment="Top" Width="106" Command="{Binding ElementName=sub_subjects_list.add_input} />
</Grid>
Now I want to add an additional user_input to the list in the user_inputs listbox when clicking on the button "button_add_input". I have been searching and it looks like using the "command" option of the button could be the way to go.
This is my class "sub_subject"
public class sub_subject
{
public string short_name { get; set; }
public string name { get; set; }
public bool read_from_db { get; set; }
public string table_name { get; set; }
//public ObservableCollection<string> possible_input { get; set; }
public ObservableCollection<possible_input> possible_input { get; set; }
public sub_subject(string name)
{
this.name = name;
possible_input = new ObservableCollection<possible_input>();
//possible_input = new ObservableCollection<string>();
}
public override string ToString()
{
return this.name;
}
public void add_input()
{
possible_input input = new possible_input();
input.input = "";
possible_input.Add(input);
}
}
I was thinking I can add a function to the class that adds a possible_input to the ObservableCollection and calling this function in the command of the button. But I just cannot figure out how to setup the proper command. Any suggestions?
I assume that sub_subject is the viewmodel (the datacontext) of the window (the view).
In this case you should add a Command class to your project. This is an implementation of the ICommand. You can find an implementation of the ICommand here: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx
After that you will have to create a property in your viewmodel for the command that calls the add_input method. Then, bind your command property to the Command property of the button.

Accessing UI controls in Viewmodel

I have Stackpanel with Buttons as follows,
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 10 0 0" Name="mystack">
<Button Width="30" Name="btn1" Height="30" Content="1" Margin="10"/>
<Button Width="30" Height="30" Content="2" Margin="10"/>
<Button Width="30" Height="30" Content="3" Margin="10"/>
<Button Width="30" Height="30" Content="4" Margin="10"/>
</StackPanel>
How to make these buttons as single object and use that in viewmodel?
because I have to check each and every buttons "Content" with my viewmodel property..
You would have to create a binding.
Content={Binding SomePropertyInYourViewModel, UpdateSourceTrigger=PropertyChanged}}
you need to add button command and button command parameter to the button
<Button Content="Button1" Command="{StaticResource DoSomethingCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
this link may help you How to get the Content of Button in ViewModel?
this is how to add command in MVVM
public class ViewModelBase
{
public ViewModelBase()
{
_canExecute = true;
}
private ICommand _doSomethingCommand;
public ICommand DoSomethingCommand
{
get
{
return _doSomethingCommand ?? (_doSomethingCommand = new CommandHandler(() => MyAction(), _canExecute));
}
}
private bool _canExecute;
public void MyAction()
{
}
}
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}

Raise usercontrol commands from a parent window using mvvm pattern

My WCF application supports downloading books from a remote service. The user sends a request to the service to download a book, the service gets the request and downloads the book. in response, it sends the download progress for the requested book.
Each element in the BookContainer is a userControl of Book.xaml and its logic represented by bookviewmodel.cs class.
When the user clicks on each book element in the BookContainer.xaml window, the click command inside the bookviewmodel is raised as expected.
I need the help to implement "DownlaodAllCommand" inside containerviewmodel to raise each DownloadCommand of each book.
How should it be implemented using the mvvm pattern.
BookContainer view :
https://onedrive.live.com/redir?resid=3A8F69A0FB413FA4!124&authkey=!ANdfYAk6f0Vf-8s&v=3&ithint=photo%2cpng
code behind:
BookContainer.xaml:
<Window x:Name="BookContainer"
DataContext="{Binding Source={StaticResource Locator}, Path=ContainerViewModel}">
<DockPanel>
<ItemsControl DockPanel.Dock="Top" ItemsSource="{Binding Books}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate >
<Controls:BookControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button DockPanel.Dock="Bottom" Command="{Binding DownloadAllCommand}" Content="Download All" > </Button>
</DockPanel>
</Window>
ContainerViewModel
public class ContainerViewModel : ViewModelBase
{
private ObservableCollection<BookViewModel> books;
public ObservableCollection<BookViewModel> Books
{
get
{
if (books == null)
{
// Not yet created.
// Create it.
books = new ObservableCollection<BookViewModel>();
}
return books;
}
}
private ActionCommand _DownloadAllCommand;
public ICommand DownloadAllCommand
{
get
{
if (_DownloadAllCommand == null)
{
_DownloadAllCommand = new ActionCommand(OnDownloadAllCommand, CanDownloadAllCommand);
}
return _DownloadAllCommand;
}
}
private void OnDownloadAllCommand()
{
// help !
}
private bool CanDownloadAllCommand()
{
return true;
}
}
Book.xaml
<UserControl
<Label Grid.Row="0">Title</Label>
<Label Grid.Row="1">Author</Label>
<Label Grid.Row="2">Description</Label>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Title}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Author}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Description}"/>
<Button Grid.Column="2" Grid.RowSpan="3" Command="{Binding DownloadCommand}" Content="Download" />
<Ellipse Grid.Column="3"
Height="20" Width="20"
Stroke="Black"
StrokeThickness="0.5"
HorizontalAlignment="Center"
Grid.Row="1"
/>
<Controls:PieSlice Grid.Column="3" Grid.Row="1" Stroke="Black" Fill="Black"
Height="20" Width="20"
StartAngle="0" EndAngle="{Binding Percent}"
HorizontalAlignment="Center" />
</UserControl>
BookViewModel
public class BookViewModel : ViewModelBase
{
public delegate void DownloadRequest(string name);
public event DownloadRequest OnDownalodRequest;
public BookViewModel(BookModel model)
{
this.Book = model;
}
private ActionCommand _DownloadCommand;
public ICommand DownloadCommand
{
get
{
if (_DownloadCommand == null)
{
_DownloadCommand = new ActionCommand(OnDownloadCommand, CanDownloadCommand);
}
return _DownloadCommand;
}
}
protected virtual void OnDownloadCommand()
{
if (OnDownalodRequest != null)
{
OnDownalodRequest.Invoke(this.Author);
}
}
}
BookModel
public class BookModel
{
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public Status Status { get; set; }
}
Insid the ContainerViewModel, method OnSaveAllCommand():
Books.ToList().Foreach(book =>
{
if(book.SaveCommand.CanExecute() == false) return;
book.SaveCommand.Execute()
}
);
but take in account that this is a bad practice to use a viewmodel from another viewmodel, try to perform viewmodels communnication on a model level.

How to bind a grid column to a specific item in a collection

Here is what I'm attempting to do...please advise if this is possible and how to achieve?
<dxg:GridColumn x:Name="FeatureAverage" FieldName="Datas[0].FeatureAverage" Width="75" Header="Avg" />
If I change the List Datas property to a single value (not a collection), the following works properly.
<dxg:GridColumn x:Name="FeatureAverage" FieldName="Data.FeatureAverage" Width="75" Header="Avg" />
Edit:
This is a DevExpress DXGrid Control container and sample classes...
The entire grid is here...
<dxg:GridControl x:Name="gridControl1" ItemsSource="{Binding Reports}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,35">
<dxg:GridControl.Columns>
<!--Visible by default-->
<dxg:GridColumn x:Name="Name" FieldName="Name" Width="68" />
<dxg:GridColumn x:Name="Feature1" FieldName="Data.Feature1" Width="75" Header="Working" />
<dxg:GridColumn x:Name="Feature2" FieldName="Datas[0].Feature1" Width="75" Header="Not Working"/>
</dxg:GridControl.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<Custom:EventToCommand Command="{Binding GridLoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<dxg:GridControl.View>
<dxg:TableView Name="tableView1" ShowTotalSummary="True" />
</dxg:GridControl.View>
</dxg:GridControl>
public class MyViewModel
{
public ObservableCollection<Report> Reports { get; set; }
}
public class Report
{
public DateTime StartDateTime { get; set; }
public Single Duration { get; set; }
public Data Data { get; set; } //working with FieldName="Data.Feature1"
public List<Data> Datas { get; set; } //not working FieldName="Datas[0].Feature1"
}
public class Data
{
public byte Segment { get; set; }
public Single Feature1 { get; set; }
public Single Feature2 { get; set; }
}

Resources