How to bind a button command in wpf style - c#

I am using a style with button in a radgridview header as HeaderCellStyle.Button is placed properly but command is not invoking
Below is my code:
<telerik:GridViewImageColumn Header=""
Width="30"
ImageHeight="30"
IsResizable="False"
DataMemberBinding="{Binding Image}"
HeaderCellStyle="{StaticResource ButtonStyle}" >
</telerik:GridViewImageColumn>
Button style:
<Style TargetType="telerik:GridViewHeaderCell" x:Key="ButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="telerik:GridViewHeaderCell">
<telerik:RadButton x:Name="ClearButton" Content="{Binding ClearButton,Source={StaticResource FrameworkInfrastructureResources}}"
ToolTip="{Binding ClearTooltip,Source={StaticResource FrameworkInfrastructureResources}}" Margin="5"
IsEnabled="True"
HorizontalContentAlignment="Center"
Command="{Binding ClearMessagesCommand}"
</telerik:RadButton>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Below is my command in viewmodel:
public ICommand ClearMessagesCommand { get; set; }
ClearMessagesCommand = new DelegateCommand(() => { this.Messages.Clear(); });

You can use RelativeSource for binding to datacontext of your cell:
<telerik:RadButton x:Name="ClearButton" Content="{Binding ClearButton,Source={StaticResource FrameworkInfrastructureResources}}"
ToolTip="{Binding ClearTooltip,Source={StaticResource FrameworkInfrastructureResources}}" Margin="5"
IsEnabled="True"
HorizontalContentAlignment="Center"
Command="{Binding Path=DataContext.ClearMessagesCommand,,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type telerik:GridViewHeaderCell}}}"
</telerik:RadButton>
There is detailed SO question about RelativeSource. You can also try to bind via ElementName.

Related

Textbox filter in WPF Datagrid columns headers

I have a WPF Datagrid defined like this in my XAML :
<DataGrid x:Name="DtgPoshResults" Style="{StaticResource DatagridResults}" ItemsSource="{Binding Path=PoshResults, UpdateSourceTrigger=PropertyChanged}" ClipboardCopyMode="{Binding ClipBoardCopyMode}" CellStyle="{StaticResource CenterDatagridCell}" SelectedValue="{Binding SelectedItemPoshResults, Mode=TwoWay}" ColumnHeaderStyle="{DynamicResource DataGridColumnHeaderStyle1}"/>
To get a textbox in each column header (in order to filter by column), I use a Template.
My Datagrid has a dynamic number of columns (that can vary each time I start a command) :
<Style x:Key="DataGridColumnHeaderStyle1" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<StackPanel Orientation="Vertical" Background="#FF444444">
<TextBlock x:Name="DtgResultsColumnName" VerticalAlignment="Center" Text="{TemplateBinding Content}" Foreground="White" Margin="5,5,5,0"/>
<StackPanel Orientation="Horizontal">
<TextBox Width="100" Margin="5" Text="{Binding DataContext.TextFilterColumn, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Margin="0,0,5,0" VerticalAlignment="Center">
<Hyperlink Foreground="White" Command="{Binding DataContext.FilterColumnName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding ElementName=DtgResultsColumnName, Path=Text}">
Filter
</Hyperlink>
</TextBlock>
</StackPanel>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
After starting my command, the Datagrid displays results and looks like this :
When typing "lo" in the first textbox and clicking on "Filter", it works and I only get the line which is "localhost" but when the Datagrid is refreshed, all the textboxes are filled with the word "lo" :
I can't define a different Text Binding for each textbox as I have a dynamic number of columns so I don't know how to avoid that all textboxes in the headers get the same text when filter is applied.
Do you know how can I fix this?
Thanks and regards.

Button inside ListView not respond to ItemClick

I have three buttons inside ListView.
I tried to click each of the button, however the ItemClick function was not triggered.
There is the xaml file of the ListView
<UserControl.Resources>
<DataTemplate x:Name="DefaultWideSideItemTemplate" x:DataType="ui:AppMenuItem">
<Grid>
<ui:ButtonWithIcon IconContent="{x:Bind Icon}"
Content="{x:Bind Name}"
Style="{StaticResource TransparentFontButtonStyle}"
/>
</Grid>
</DataTemplate>
<others:SideMenuItemTemplateSelector DefaultTemplate="{StaticResource DefaultWideSideItemTemplate}" x:Key="WideSideItemTemplateSelector"/>
</UserControl.Resources>
<ListView Style="{StaticResource HorizontalCenterListView}"
IsItemClickEnabled="True"
ItemsSource="{x:Bind MenuItemCollection}"
VerticalAlignment="Top"
x:Name="SideMenuListView"
Loaded="SideMenuListView_Loaded"
ItemClick="SideMenuListView_ItemClick"
ItemTemplateSelector="{StaticResource WideSideItemTemplateSelector}">
</ListView>
There is the code where ItemClick was defined.
public event EventHandler<AppMenuItem> SideMenuItemClick;
private void SideMenuListView_ItemClick(object sender, ItemClickEventArgs e)
{
// DO SOMETHING HERE
}
There is the xaml file of the ui:ButtonWithIcon
<Style x:Key="TransparentFontButtonStyle" TargetType="ui:ButtonWithIcon">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="FontSize" Value="30"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,32,0,7"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ui:ButtonWithIcon">
<StackPanel>
<TextBlock
x:Name="IconContent"
Text="{Binding IconContent, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalAlignment="Center"
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="30"/>
<TextBlock
x:Name="Text"
Text="{TemplateBinding Content}"
HorizontalAlignment="Center"
FontSize="14"
Margin="0,10,0,0"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
What did I understand wrong about ListView? Buttons can not be used in ListView?
Update: ButtonWithIcon
public class ButtonWithIcon : Button
{
public static readonly DependencyProperty IconContentProperty =
DependencyProperty.Register("IconContent", typeof(string), typeof(ButtonWithIcon), new PropertyMetadata(default));
public string IconContent
{
get { return (string)GetValue(IconContentProperty); }
set { SetValue(IconContentProperty, value); }
}
}
Update 2:
<DataTemplate x:Name="DefaultWideSideItemTemplate" x:DataType="ui:AppMenuItem">
<Grid>
<StackPanel Margin="0,32,0,7">
<TextBlock Text="{x:Bind Icon}"
HorizontalAlignment="Center"
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="30"/>
<TextBlock
Text="{x:Bind Name}"
HorizontalAlignment="Center"
Margin="0,10,0,0"
FontSize="14"/>
</StackPanel>
</Grid>
</DataTemplate>
If the ui:ButtonWithIcon is a custom button control, then this is expected behavior. When you click on the custom button, the click event is captured by the button, so the ListView won't trigger the ItemClick event. A simple way to confirm is that you could click on the place that does not belong to the custom button. It should fire the ItemClick event of the ListView.
Update:
Since your code is too messy, I made a simple test using some of your code:
<ListView HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsItemClickEnabled="True"
ItemsSource="{x:Bind MenuItemCollection}"
x:Name="SideMenuListView"
Loaded="SideMenuListView_Loaded"
ItemClick="SideMenuListView_ItemClick"
>
<ListView.ItemTemplate>
<DataTemplate >
<Grid>
<StackPanel Margin="0,32,0,7">
<TextBlock
Text="{Binding}"
HorizontalAlignment="Center"
Margin="0,10,0,0"
FontSize="14"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This works correctly.
You could remove the extra parts of your code to narrow down the issue. Start with a easy sample like the above.

WPF : get value from user control to parent window

i've a user control which contains cefsharpwpf:ChromiumWebBrowser control. this UC is loaded dynamically to the main window (in tab control).
UC gets and sets the value of var Title of class DisplayHandler which implements IDisplayHandler, INotifyPropertyChanged and it works fine for the UC.
Now I want the value of Title either from class DisplayHandler or from UC in the main class to set the Header of the Tab Item.
this code is from UC and works for Lable title
<Label x:Name="title" Content="{Binding ElementName=Browser_DisplayHandler, Path=Title, TargetNullValue=TitleHere}" />
<cefsharpwpf:ChromiumWebBrowser Name="browser" Address="google.com">
<cefsharpwpf:ChromiumWebBrowser.DisplayHandler>
<local:DisplayHandler x:Name="Browser_DisplayHandler"/>
</cefsharpwpf:ChromiumWebBrowser.DisplayHandler>
</cefsharpwpf:ChromiumWebBrowser>
but i want this title value in main class which has a Data template designed for tab control and textblock in header is named as txtTitle and is bind to Header
<TabControl Name="tabDynamic" ItemsSource="{Binding}" SelectionChanged="tabDynamic_SelectionChanged">
<TabControl.Resources>
<DataTemplate x:Key="TabHeader" DataType="TabItem">
<DockPanel Width="200" MaxWidth="200" Height="28">
<Button Name="btnDelete" DockPanel.Dock="Right" Margin="5,0,0,0" Padding="0" Click="btnDelete_Click" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Name}" Width="15" Height="15">
<Image Source="C:\Users\Faisal\source\repos\SampleWPF\SampleWPF\delete.png" Height="13" Width="13"></Image>
</Button>
<TextBlock Name="txtTitle" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Header}" />
</DockPanel>
</DataTemplate>
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border" Margin="1,0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="7,2"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
</TabControl>
if i set tab.Header = "Tab Title";from its main class that works but i want Title from class DisplayHandler
string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
OnPropertyChanged("Title");
}
}
Please help me to achieve this by using code behind technique or Binding in WPF
thanks

WPF - Set propeties of child controls of custom style

I have a custom style for a SearchTextBox. I have multiple Bindings in this control.
<Style TargetType="{x:Type controls:SearchTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:SearchTextBox}">
<Grid>
<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Command="{Binding Path=SearchCommand}" Key="Enter" />
<KeyBinding Command="{Binding Path=DeleteSearchCommand}" Key="Esc" />
</TextBox.InputBindings>
</TextBox>
<Button Style="{StaticResource WatermarkButtonCancelStyle}" HorizontalAlignment="Right" Command="{Binding DeleteSearchCommand}" Margin="0,0,22,0"/>
<Button Style="{StaticResource WatermarkButtonSearchStyle}" HorizontalAlignment="Right" Command="{Binding SearchCommand}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am using the TextBox in my view right here:
<controls:SearchTextBox Width="300" HorizontalAlignment="Left" Margin="0,0,0,6" />
How can I set the bindings in my view, not in the definition of the style. So that I can use the control in multiple Views with different bindings?
Style for the custom TextBox:
<Style TargetType="{x:Type local:SearchTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SearchTextBox}">
<DockPanel DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:SearchTextBox}}}">
<Button DockPanel.Dock="Right"
Style="{StaticResource WatermarkButtonCancelStyle}"
Command="{Binding DeleteSearchCommand}"/>
<Button DockPanel.Dock="Right"
Style="{StaticResource WatermarkButtonSearchStyle}"
Command="{Binding SearchCommand}"
CommandParameter="{Binding Text}"/>
<TextBox x:Name="InnerTextBox"
Text="{Binding Path=Text}">
<TextBox.InputBindings>
<KeyBinding Command="{Binding SearchCommand}"
CommandParameter="{Binding Text}"
Key="Enter" />
<KeyBinding Command="{Binding DeleteSearchCommand}"
Key="Escape" />
</TextBox.InputBindings>
</TextBox>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Code of the SearchTextBox.cs:
public class SearchTextBox : TextBox
{
public static readonly DependencyProperty SearchCommandProperty = DependencyProperty.Register(
"SearchCommand", typeof(ICommand), typeof(SearchTextBox), new PropertyMetadata(default(ICommand)));
public SearchTextBox()
{
DeleteSearchCommand = new Command
{
ExecuteHandler = o => Clear()
};
}
public ICommand SearchCommand
{
get { return (ICommand) GetValue(SearchCommandProperty); }
set { SetValue(SearchCommandProperty, value); }
}
public Command DeleteSearchCommand { get; private set; }
}
Because the Command for clearing the TextBox is always the same, the SearchTextBox contains the Command for clearing it.
Now it is possible to use the SearchTextBox in a View and just set the SearchCommand property.
<local:SearchTextBox Height="30" Width="200" SearchCommand="{Binding DoTheSearch}"/>
As you can see in the style for the SearchTextBox, the Text is set as the parameter for the SearchCommand, so you can use it, where the command is specified.

StackPanel Collapsed and Visible on Button Click

I am trying to show one collapsed stackpanel on button click, but I'm having problems so I tried reverse my thoughts and I was able to collapse an visible stackpanel. But unfortunately I was unable to implement the behavior I want, show an collapsed stack panel on button click. To the code :D
XAML
<Button x:Name="sentButton" Content="Add Friend" Style="{DynamicResource FlatButtonStyle}" Margin="493,0,0,0" HorizontalAlignment="Left" Width="106"/>
<StackPanel Style="{DynamicResource stackCollapsed}" Visibility="Collapsed">
<Label Content="Invite Friends" FontWeight="Bold" Margin="0,0,477,0" Height="32" />
<StackPanel Orientation="Horizontal" Margin="26,0,0,0">
<Label Content="Enter your friend's email" Width="222" Height="25" />
<TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource MyTextBox}" x:Name="textBoxEmail" Width="298"/>
<Button x:Name="button1" Content="Send" Command="{Binding AddCommand}" Width="77" Style="{DynamicResource FlatButtonStyle}" Margin="20,0,0,0"/>
</StackPanel>
</StackPanel>
Styles
<!-- Style Collapsed-->
<Style x:Key="stackCollapsed" TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=sentButton,Path=IsPressed}" Value="true">
<Setter Property="StackPanel.Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
Instead of Button use ToggleButton and bind StackPanel.Visibility to ToggleButton.IsChecked property via BooleanToVisibilityConverter converter
<ToggleButton x:Name="sentButton" Content="Add Friend" Margin="493,0,0,0" HorizontalAlignment="Left" Width="106"/>
<StackPanel Visibility="{Binding ElementName=sentButton, Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}">
<Label Content="Invite Friends" FontWeight="Bold" Margin="0,0,477,0" Height="32" />
<StackPanel Orientation="Horizontal" Margin="26,0,0,0">
<Label Content="Enter your friend's email" Width="222" Height="25" />
<TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" x:Name="textBoxEmail" Width="298"/>
<Button x:Name="button1" Content="Send" Command="{Binding AddCommand}" Width="77" Margin="20,0,0,0"/>
</StackPanel>
</StackPanel>
where converter is defined as below
<Window.Resources>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</Window.Resources>
The problem is the Visibility property in the <StackPanel> tab takes a higher precedence than anything set in a Style or Trigger, so the Trigger never gets applied. See the Dependency Property Precedence List for more details.
To fix your current solution, move the Visibliity property out of the <StackPanel> tag and into your Style, like this :
<Style x:Key="stackCollapsed" TargetType="StackPanel">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=sentButton,Path=IsPressed}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
<StackPanel Style="{DynamicResource stackCollapsed}">
...
</StackPanel>
That said, I would personally recommend something like a Toggle Button with the StackPanel.Visibility bound to the ToggleButton.IsChecked, like this answer suggests.
I solved set the Children to null
stackPanel.Children.Clear();
this work if you need to show / hide the panel the first time, it doesn't work if you need to do runtime
Simple as Stackpanel.Visibility = Visibility.Collapsed.

Categories

Resources