C
C#2y ago
frknztrk

Wpf Button CommandParameter

<Button Command="{Binding ClickCommandEvent}" CommandParameter="Jack"/> How commandParemeter value get wpf ?
20 Replies
twiner
twiner2y ago
A command parameter is the same as other dependency properties. You bind it to the value you want to pass, otherwise it will pass as a string And then assuming that your ClickCommandEvent is an ICommand you can receive that parameter through the Execute methods parameter
SuperBrain
SuperBrain2y ago
@frknztrk you should use CommunityToolkit.Mvvm, it provides all the basic stuff you'll ever need.
frknztrk
frknztrk2y ago
i want a simple build
SuperBrain
SuperBrain2y ago
It can't get any simpler than using CommunityToolkit.Mvvm. It provides a ready-made RelayCommand / AsyncRelayCommand implementations, as well as generic versions RelayCommand<T>/AsyncRelayCommand<T> (which are the ones you want when using CommandParameter) Docs reference: https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/introduction Feel free to write everything on your own, but this would both save your time and provide best-in-class implementations.
frknztrk
frknztrk2y ago
What I want is to get the CommandParameter data when I click the button in the dynamically created data source. Mainwindow.xaml
<Window x:Class="lestplay.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:lestplay"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">

<Window.Resources>

<Style TargetType="ItemsControl" x:Key="den2">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<Button x:Name="lestplaybutton" Command="{Binding DisplayMessageCommand}" CommandParameter="{Binding Id}" Width="100" Height="50" Content="Furkan" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>

<ItemsControl x:Name="le2" Style="{DynamicResource den2}">
</ItemsControl>
</Grid>
</Window>
<Window x:Class="lestplay.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:lestplay"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">

<Window.Resources>

<Style TargetType="ItemsControl" x:Key="den2">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<Button x:Name="lestplaybutton" Command="{Binding DisplayMessageCommand}" CommandParameter="{Binding Id}" Width="100" Height="50" Content="Furkan" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>

<ItemsControl x:Name="le2" Style="{DynamicResource den2}">
</ItemsControl>
</Grid>
</Window>
MessageViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace lestplay
{
public class MessageViewModel
{
public List<Person> Persons { get; set; }

public MessageCommand DisplayMessageCommand { get; set; }

public MessageViewModel()
{
DisplayMessageCommand = new MessageCommand(DisplayMessage);
}

public void DisplayMessage(string messagetext)
{
MessageBox.Show(messagetext);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace lestplay
{
public class MessageViewModel
{
public List<Person> Persons { get; set; }

public MessageCommand DisplayMessageCommand { get; set; }

public MessageViewModel()
{
DisplayMessageCommand = new MessageCommand(DisplayMessage);
}

public void DisplayMessage(string messagetext)
{
MessageBox.Show(messagetext);
}
}
}
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lestplay
{
public class Person
{
public string Id { get; set; }
public string Name { get; set; }

public Person(string id, string name)
{
this.Id = id;
this.Name = name;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lestplay
{
public class Person
{
public string Id { get; set; }
public string Name { get; set; }

public Person(string id, string name)
{
this.Id = id;
this.Name = name;
}
}
}
MessageCommand.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace lestplay
{
public class MessageCommand : ICommand
{
public event EventHandler? CanExecuteChanged;

public Action<string> _execute;

public MessageCommand(Action<string> execute)
{
_execute = execute;
}

public bool CanExecute(object? parameter)
{
return true;
}

public void Execute(object? parameter)
{
_execute.Invoke(parameter as string);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace lestplay
{
public class MessageCommand : ICommand
{
public event EventHandler? CanExecuteChanged;

public Action<string> _execute;

public MessageCommand(Action<string> execute)
{
_execute = execute;
}

public bool CanExecute(object? parameter)
{
return true;
}

public void Execute(object? parameter)
{
_execute.Invoke(parameter as string);
}
}
}
twiner
twiner2y ago
Seems like what you wrote here should work, though I think your message command class is gonna have problems
SuperBrain
SuperBrain2y ago
Yeah, your MessageCommand is basically ignoring the string parameter.
twiner
twiner2y ago
Huh? I was referring to him not connecting back to CommandManager
twiner
twiner2y ago
ICommand and RelayCommand in WPF
This article provides a basic overview of commands in WPF. Here ICommand RelayCommand will be discussed.
twiner
twiner2y ago
Only because I can't figure out where more official docs are I believe your mistaken Oh well. Can execute isn't checking the param
frknztrk
frknztrk2y ago
Works when using outside of data template
frknztrk
frknztrk2y ago
frknztrk
frknztrk2y ago
Klarth
Klarth2y ago
The issue is that your Command binding is incorrect. It doesn't have to do with the CommandParameter. I suggest not putting the <DataTemplate> into your resources if you can avoid it, so you can have a simpler ElementName binding instead of RelativeSource ancestor binding. Currently, the binding is looking for the command on Person because that's the local DataContext within the <DataTemplate>.
<Window x:Class="lestplay.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:lestplay"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">

<Window.Resources>
<Style TargetType="ItemsControl" x:Key="den2">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="UseLayoutRounding" Value="True" />
</Style>
</Window.Resources>

<Grid>
<ItemsControl x:Name="le2" Style="{StaticResource den2}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding DataContext.DisplayMessageCommand, ElementName=le2}" CommandParameter="{Binding Id}" Width="100" Height="50" Content="Furkan" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
<Window x:Class="lestplay.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:lestplay"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">

<Window.Resources>
<Style TargetType="ItemsControl" x:Key="den2">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="UseLayoutRounding" Value="True" />
</Style>
</Window.Resources>

<Grid>
<ItemsControl x:Name="le2" Style="{StaticResource den2}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding DataContext.DisplayMessageCommand, ElementName=le2}" CommandParameter="{Binding Id}" Width="100" Height="50" Content="Furkan" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
This is how I would rewrite it so the Button command works. I'd probably get rid of the style altogether.
frknztrk
frknztrk2y ago
I think it's okay, thank you, but I have to use style because I'm getting my data dynamically. but why does it not see the element name in such a render
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<Person> prn = new List<Person>();
prn.Add(new Person() { Name = "furkan", Id = "ui-dyanmic" });

ItemsControl itemsControl = new ItemsControl();
itemsControl.Style = (Style)FindResource("le1");
itemsControl.Name = "le1";

itemsControl.ItemsSource = prn;

maingrid.Children.Add(itemsControl);
DataContext = new MessageViewModel();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<Person> prn = new List<Person>();
prn.Add(new Person() { Name = "furkan", Id = "ui-dyanmic" });

ItemsControl itemsControl = new ItemsControl();
itemsControl.Style = (Style)FindResource("le1");
itemsControl.Name = "le1";

itemsControl.ItemsSource = prn;

maingrid.Children.Add(itemsControl);
DataContext = new MessageViewModel();
}
frknztrk
frknztrk2y ago
Klarth
Klarth2y ago
Because you didn't follow the advice. There's no reason this needs to be a style. You can't access element names like that when you're in .Resources, AFAIK. Which means you now have to write a RelativeSource ancestor binding which looks something like:
<Button Command="{Binding DataContext.DisplayMessageCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}}"
CommandParameter="{Binding Id}" Width="100" Height="50" Content="Furkan" />
<Button Command="{Binding DataContext.DisplayMessageCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}}"
CommandParameter="{Binding Id}" Width="100" Height="50" Content="Furkan" />
frknztrk
frknztrk2y ago
sorry i am new to .net i am missing some points
Klarth
Klarth2y ago
It's a complicated binding, but you need that indirection if the data isn't located on the current DataContext.