WPF - Set propeties of child controls of custom style - c#

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.

Related

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

How to bind a button command in wpf style

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.

How to bind commands(for example hotkeys like F7) dynamically in xaml

I have the following XAML that loads the menus and menuitems, but is there a way to bind a command/inputgesture without having to use a StackPanel? CmdParam is the property in my VM that has the command. I initially thought of setting it in the resource section like below, but the command doesnt show up
<Window>
<Window.Resources>
<Style TargetType="{x:Type MenuItem}" x:Key="menuSeparatorStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Separator HorizontalAlignment="Stretch" IsEnabled="false"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="InputGestureText" Value="{Binding CmdParam}"/>
</Style>
<HierarchicalDataTemplate DataType="{x:Type projectBusinessLayer:MenuDataItem}">
<ContentPresenter Content="{Binding Path=MenuText}" Loaded="OnMenuDataItemLoaded" RecognizesAccessKey="True" />
<HierarchicalDataTemplate.ItemsSource>
<Binding Path="MenuItemID">
<Binding.Converter>
<converters:MenuDataItemConverter />
</Binding.Converter>
</Binding>
</HierarchicalDataTemplate.ItemsSource>
</HierarchicalDataTemplate>
<projectBusinessLayer:MenuSeparatorStyleSelector x:Key="menuSeparatorStyleSelector"/>
</Window.Resources>
<DockPanel>
<Menu x:Name="mnuMainMenu" ItemsSource="{Binding}" VerticalAlignment="Top" DockPanel.Dock="Top" ItemContainerStyleSelector="{StaticResource menuSeparatorStyleSelector}"/>
</DockPanel>
I don't fully understand what you mean with dynamically, but what about...
<Window.InputBindings>
<KeyBinding Key="F7" Command="{Binding CmdParam}" />
</Window.InputBindings>
ViewModel:
private ICommand _cmdParam;
public ICommand CmdParam
{
get
{
if (_cmdParam== null)
_cmdParam= new DelegateCommand(DoSomething);
return _cmdParam;
}
}
private void DoSomething(object obj)
{
}

Binding a WPF Button CommandParameter to the Button itself in DataTemplate

I have a DataTemplate that represents AppBar buttons that I declare through a collection of custom AppBarCommand objects.
public AppBarCommand(RelayCommand command, string buttonstyle)
{
Command = command;
ButtonStyle = buttonstyle;
}
<DataTemplate>
<Button Command="{Binding Command}"
Style="{Binding ButtonStyle, Converter={StaticResource StringNameToStyleConverter}}"/>
</DataTemplate>
I would like to add a CommandParameter binding, but the parameter has to be the Button itself. This is so I can set the PlacementTarget of a Callisto flyout. Is this possible?
<Button Command="{Binding Command}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}" />
Your Command property should be the generic version of the RelayCommand: RelayCommand<object> for instance.
Answer like Miklós Balogh said, or you can:
<Button x:Name="MyButton" Command="{Binding Command}" CommandParameter={Binding ElementName=MyButton ... />
I had the same problem but I used it in a bit different context:
<MenuItem ItemsSource="{Binding MyList}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding RelativeSource={ RelativeSource FindAncestor, AncestorType={ x:Type Window}}, Path= DataContext.MyListItemCommand}"/>
<Setter Property="CommandParameter" Value="{Binding}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
so I assume that even if you write it like this
<Button Command="{Binding Command}" CommandParameter="{Binding}" />
it should work.
I also recommend reading this post to understand it better.

Categories

Resources