WPF : get value from user control to parent window - c#

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

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.

How can I bind this Textblock inside ControlTemplate in button style?

I have a Button style and this style contains an icon and a text. I would like to bind the text.
How can I achieve that?
<Style TargetType="{x:Type Button}" x:Key="ConnectedButton">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="FlowDirection" Value="LeftToRight"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Padding="5 0"
Width="80"
Height="30"
Margin="5">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="{Binding Connect}"
Margin="3 0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="{StaticResource ConnectIcon}"
Style="{StaticResource Icon_Text}" Margin="3 0"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Use the style in MainWindow.xaml:
<Button Style="{StaticResource ConnectedButton}" Margin="10,15,0,10" x:Name="cnct_btn" Content="{StaticResource Connect}" Height="40" Width="80 " HorizontalAlignment="Left" VerticalAlignment="Center" Click="Cnct_Click"/>
MainWindow.xaml.cs
bool test = false;
//...
if (test)
{
cnct_btn.Content = "Connect";
}
else
{
cnct_btn.Content = "Not Connected";
}
I have tried Text={Binding Connect} but it doesn't work.
In a control template, you have to use a TemplateBinding to access a property on a templated control. In case of a Button, it is the Content property that you want to bind.
Implements a markup extension that supports the binding between the value of a property in a template and the value of some other exposed property on the templated control.
<TextBlock Text="{TemplateBinding Content}"
Margin="3 0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
A simple Binding will resolve a property on the current data context. You can also make this work, but you need to specify a RelativeSource using TemplatedParent.
TemplatedParent - Refers to the element to which the template (in which the data-bound element exists) is applied. This is similar to setting a TemplateBindingExtension and is only applicable if the Binding is within a template.
<TextBlock Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
Margin="3 0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
Please note that in this scenario a TemplateBinding is sufficient, as it is only one way. In a two-way binding you would have to use the variant using RelativeSource and TemplatedParent.
A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}. A TemplateBinding is always a one-way binding, even if properties involved default to two-way binding. Both properties involved must be dependency properties. In order to achieve two-way binding to a templated parent use the following binding statement instead {Binding RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, Path=MyDependencyProperty}.

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.

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.

WPF - Change a style in code behind

I have a list box that displays the results of a TFS Query. I want to change the style of the ListBoxItem in the code behind to have the columns that are included in the query results.
The style for the ListBoxItem is defined in my Windows.Resoruces Section. I have tried this:
public T GetQueryResultsElement<T>(string name) where T : DependencyObject
{
ListBoxItem myListBoxItem =
(ListBoxItem)(lstQueryResults.ItemContainerGenerator.ContainerFromIndex(0));
// Getting the ContentPresenter of myListBoxItem
ContentPresenter myContentPresenter =
myListBoxItem.Template.LoadContent().FindVisualChild<ContentPresenter>();
// Finding textBlock from the DataTemplate that is set on that ContentPresenter
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate; <------+
T myControl = (T)myDataTemplate.FindName(name, myContentPresenter); |
|
return (T)myControl; |
} |
|
ContentTemplate is null ----------------------------------------------+
But the ContentTemplate is null. I got that code from here, then modified it with the LoadContent call (the orginal code gave null for the ContentPresenter).
Anyway. If you know a way to change an existing style in the code behind I would love to see it.
Specifics if you want them:
I am going for WrapPanel in my ListBoxItem Style. This is what I want to add the extra TextBlock items to.
Here is part of my style:
<!--Checkbox ListBox-->
<Style x:Key="CheckBoxListStyle" TargetType="ListBox">
<Style.Resources>
<Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Tag" Value="{Binding Id}"/>
<Setter Property="Background">
<Setter.Value>
<Binding Path="Type" Converter="{StaticResource WorkItemTypeToColorConverter}" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border BorderThickness="1" BorderBrush="#D4D4FF">
<Grid Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WrapPanel}}, Path=ActualWidth}" ScrollViewer.CanContentScroll="True" Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<Grid.Background>
<Binding Path="Type" Converter="{StaticResource WorkItemTypeToColorConverter}" />
</Grid.Background>
<CheckBox VerticalAlignment="Center" Grid.Column="0" IsChecked="{Binding IsSelected,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}" Name="chkIsSelected" />
<WrapPanel Grid.Column="1" Margin="5,0,5,0" Name="QueryColumns">
<TextBlock VerticalAlignment="Center" Text="{Binding Id}" Name="txtID" />
<TextBlock VerticalAlignment="Center" Margin="5,0,5,0" Text="{Binding Title}" Name="txtTitle" />
</WrapPanel>
You're going against the grain here, trying to manipulate visual elements directly in code-behind. There's a much simple solution involving data binding.
I'll provide the general solution because I don't know the specifics of your solution.
Once you get your query results, create an enumeration that returns a column name, and a field value for each iteration.
Example:
class NameValuePair
{
public string Name { get; set; }
public object Value { get; set; }
}
public IEnumerable<IEnumerable<NameValuePair>> EnumerateResultSet(DataTable resultSet)
{
foreach (DataRow row in resultSet.Rows)
yield return EnumerateColumns(resultSet, row);
}
public IEnumerable<NameValuePair> EnumerateColumns(DataTable resultSet, DataRow row)
{
foreach (DataColumn column in resultSet.Columns)
yield return new NameValuePair
{ Name = column.ColumnName, Value = row[column] };
}
And in your code-behind, once you get your DataTable result set, do this:
myResultsList.ItemsSource = EnumerateResultSet(myDataTable);
The XAML might look like this:
<Window.Resources>
<DataTemplate x:Key="ColumnTemplate">
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="2" Padding="2">
<WrapPanel>
<TextBlock Text="{Binding Name}" Margin="0,0,5,0"/>
<TextBlock Text="{Binding Value}" Margin="0,0,10,0"/>
</WrapPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="RowTemplate">
<Grid>
<ItemsControl
ItemsSource="{Binding}"
ItemTemplate="{StaticResource ColumnTemplate}"
Margin="0,5,0,5"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox Name="myResultsList" ItemTemplate="{StaticResource RowTemplate}"/>
</Grid>
Sample output:

Categories

Resources