I have a control template that defines a custom floating text box.
It consists of a label, a border that serves as the visual boundary for the text box, and a text box inside that border.
The border of the text box itself is made invisible.
My problem is this: when the custom control is "tabbed" to in the UI, the control gets KeyboardFocus, but the Textbox itself does not. This causes the blinking cursor not to show.
I need to know how to pass focus to the Textbox contained within the border, named DisplayText, from a trigger in the control template.
I tried using the FocusManager to set DisplayText to be the focused element, but that didn’t work.
Any ideas, thoughts or advice would be much appreciated. If you need any more information, please let me know.
Control Template:
<Grid SnapsToDevicePixels="True"
UseLayoutRounding="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="floatingLabel"
Template="{DynamicResource LabelControlTemplate1}"
Content="{Binding LabelText, RelativeSource={RelativeSource Mode=TemplatedParent}}"
IsHitTestVisible="False"
Panel.ZIndex="2"
Background="White"
Height="15"
VerticalContentAlignment="Center"
Padding="3,0,3,0"
HorizontalAlignment="Left"
FontFamily="Segoe UI"
FontSize="{Binding LabelFontSize, RelativeSource={RelativeSource TemplatedParent}}"
Foreground="{DynamicResource FloatingLabelTextBox.Label.Foreground}"
VerticalAlignment="Center">
<Label.Tag>
<sys:Double>0.0</sys:Double>
</Label.Tag>
<Label.Margin>
<MultiBinding Converter="{StaticResource floatingLabelMarginConverter}">
<Binding Path="Tag"
RelativeSource="{RelativeSource Self}" />
<Binding ElementName="Border"
Path="ActualHeight" />
</MultiBinding>
</Label.Margin>
</Label>
<Border x:Name="Border"
Height="{Binding TextBoxHeight, RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="3"
SnapsToDevicePixels="True"
Panel.ZIndex="0"
VerticalAlignment="Bottom">
<Grid x:Name="GridContainer" Width="{Binding ElementName=Border, Path=ActualWidth}" Margin="10,0,0,0">
<TextBox x:Name="DisplayText"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FormattedPhoneNumber, StringFormat={}{0:(###)###-####}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
Width="{Binding ElementName=Border, Path=ActualWidth}">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer x:Name="PART_ContentHost"
HorizontalAlignment="Stretch"
Margin="{TemplateBinding Padding}"
Uid="ScrollViewer_1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
</Grid>
</Border>
</Grid>
Trigger:
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=DisplayText}" />
</Trigger>
Try adding Focusable="False" to the Label.
I tried to copy your XAML into a Window and run it, but there's obviously a bunch of other stuff that I would need in order to get it to work.
Related
I am using AvalonDock in my application to have a Visual Studio look and feel. I would like to add some buttons and other controls to the header of the LayoutAnchorableControl as well as add some menu items to the drop down. I only want this to affect certain controls and not the entire layout.
I've been able to add buttons and controls to specific LayoutAnchorableControls by adding methods to the LayoutAnchorable that check for certain criteria and adding the controls to the theme. However, I feel there is a more robust solution I have yet to stumble on.
If you are using MVVM approach, you don't need to add methods to LayoutAnchorableControls. You can get it simply editing AvalonDock style.
For example, you may edit the LayoutDocumentTabItem style like the following:
<Style TargetType="{x:Type avalonDockControls:LayoutDocumentTabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type avalonDockControls:LayoutDocumentTabItem}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Following border is required to catch mouse events -->
<Border Grid.ColumnSpan="5" Background="Transparent" />
<TextBlock Grid.Column="0" Visibility="{Binding LayoutItem.Model.IsStatusQuadStringVisible,
RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}"
Text="{Binding LayoutItem.Model.StatusQuadString,
RelativeSource={RelativeSource TemplatedParent}}" FontSize="{StaticResource SrkMainTouchControlFontSize}" HorizontalAlignment="Left" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"/>
<ContentPresenter HorizontalAlignment="Center"
Grid.Column="2"
VerticalAlignment="Center"
Content="{Binding Model,
RelativeSource={RelativeSource TemplatedParent}}"
ContentTemplate="{Binding DocumentHeaderTemplate,
Mode=OneWay,
RelativeSource={RelativeSource AncestorType={x:Type avalonDock:DockingManager},
Mode=FindAncestor}}"
ContentTemplateSelector="{Binding DocumentHeaderTemplateSelector,
Mode=OneWay,
RelativeSource={RelativeSource AncestorType={x:Type avalonDock:DockingManager},
Mode=FindAncestor}}" />
<!-- region TabItem Buttons -->
<StackPanel Grid.Column="4" Orientation="Horizontal"
HorizontalAlignment="Right"
VerticalAlignment="Center">
<Button Margin="2,0"
Command="{Binding LayoutItem.Model.MyCustomCommand, RelativeSource={RelativeSource TemplatedParent}}"
Style="{StaticResource ButtonAvalonDocumentStyleKey}">
<Button.ToolTip>
<PriorityBinding>
<Binding Path="LayoutItem.Model.MyCustomCommand" RelativeSource="{RelativeSource TemplatedParent}" IsAsync="True"/>
</PriorityBinding>
</Button.ToolTip>
<Path Data="{StaticResource SrkGeometryMyCustomCommand}" Stretch="Uniform" Margin="5,0" Style="{StaticResource PathAvalonDocumentStyleWithStrokeKey}" />
</Button>
</StackPanel>
<!-- endregion TabItem Buttons -->
</Grid>
</Border>
</Setter.Value>
</Setter>
</Style>
By doing this, you are adding a new custom Button to the tabbed Doc's title, binded to an ICommand named MyCustomCommand.
Furthermore, you may adding DataTrigger to the style binded to a Visibility property on the ViewModel that can handle button visibility, based on the business logic of your application.
I hope it helps.
How to wrap text in GroupBox header? This code doesn't work.
<GroupBox>
<GroupBox.Header>
<TextBlock Text="qwertyuiopasdfghjklqwertyuiopasdfghjkl" TextWrapping="Wrap"/>
</GroupBox.Header>
In-order to get the text content wrapped,You have to specify the width, other wise the with of the textblock automatically set to the length of content in the text block.
<TextBlock Width="150" Text="qwertyuiopasdfghjklqwertyuiopasdfghjkl" TextWrapping="Wrap"/>
While the solution to set the header's width by explicitly specifying the value or binding with another element works perfectly, delving into the default style of GroupBox, I found that making small modifications into the style will solve this issue.
<BorderGapMaskConverter x:Key="BorderGapMaskConverter"/>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="BorderBrush" Value="#D5DFE5"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupBox}">
<Grid SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6"/>
<!-- <ColumnDefinition Width="Auto"/> is removed because its Width="Auto" is problematic. -->
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="6"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="6"/>
</Grid.RowDefinitions>
<!-- The value of Grid.ColumnSpan is changed from 4 to 3. -->
<Border Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="3"
BorderBrush="Transparent"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="4"/>
<!-- The value of Grid.ColumnSpan is changed from 4 to 3. -->
<Border Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="3"
BorderBrush="White"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<Border.OpacityMask>
<MultiBinding Converter="{StaticResource BorderGapMaskConverter}"
ConverterParameter="7">
<Binding ElementName="Header" Path="ActualWidth"/>
<Binding RelativeSource="{RelativeSource Self}" Path="ActualWidth"/>
<Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight"/>
</MultiBinding>
</Border.OpacityMask>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3">
<Border BorderBrush="White"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="2"/>
</Border>
</Border>
<!-- HorizontalAlignment="Left" is added to adjust the surrounding line. -->
<Border x:Name="Header"
Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
HorizontalAlignment="Left"
Padding="3,1,3,0">
<ContentPresenter ContentSource="Header"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<!-- Grid.ColumnSpan="2" is removed because it is no longer necessary. -->
<ContentPresenter Grid.Column="1" Grid.Row="2"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The root cause of this issue is Width="Auto" of the 2nd ColumnDefinition of Grid. So remove the ColumnDefinition so that the header's Border is assigned to the original 3rd ColumnDefinition. Then add HorizontalAlignment="Left" to the header's Border. Some trivial edits of ColumnSpan. That's it.
This modified style lets WPF's layout engine determine the header's width automatically depending on actual width of GroupBox. No need to care about the width each time. As far as I know, there is no noticeable degradation from the default one.
I have finally managed to template my ribbon and adding everything with databinding.
However I have a very ugly "dropdownmenu" which background have become transparent (The shadowing remains though!)
1st of all what is this "dropdownmenu" called? Lastly which properties shall I edit for providing a proper background to this "dropdownmenu"?
Best Regards!
That menu is a drop-down menu of a collapsed group. Collapsed group is a combination of RibbonToggleButton + Popup. In template, the Popup looks like this:
<Popup x:Name="PART_Popup"
AllowsTransparency="true"
Placement="Bottom"
PlacementTarget="{Binding ElementName=PART_ToggleButton}"
IsOpen="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
Focusable="false"
PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}">
<classic:SystemDropShadowChrome Name="Shdw"
Color="Transparent"
SnapsToDevicePixels="true"
CornerRadius="2"
Focusable="True"
FocusVisualStyle="{x:Null}"
controls:KeyTipService.IsKeyTipScope="True"
RenderOptions.ClearTypeHint="Enabled"
>
<Grid Name="PopupGrid" Height="{TemplateBinding ActualHeight}" Margin="0,1.5,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" MinHeight="16" />
</Grid.RowDefinitions>
<Border Name="PopupBorder" Grid.RowSpan="2"
Background="{TemplateBinding Background}"
BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Ribbon.BorderBrush}"
BorderThickness="1"/>
<Border Name="PART_HotBackground"
Background="{TemplateBinding MouseOverBackground}"
BorderBrush="{TemplateBinding MouseOverBorderBrush}"
Opacity="0"
Grid.RowSpan="2"
CornerRadius="2"
BorderThickness="1"
SnapsToDevicePixels="True"/>
<Border Margin="2,3.5,2,0" Padding="3,0,3,0" x:Name="PART_RibbonControlsHostBorder">
<Grid>
<ItemsPresenter Name="ItemsPresenter" KeyboardNavigation.TabNavigation="Cycle"
KeyboardNavigation.DirectionalNavigation="Cycle"
SnapsToDevicePixels="True"
Grid.IsSharedSizeScope="true"/>
<ContentControl Name="TemplateContentControl" Visibility="Collapsed" Focusable="False"/>
</Grid>
</Border>
<Grid Margin="2,0,2,1" Grid.Row="1">
<ContentPresenter Name="PART_Header"
TextElement.Foreground="{StaticResource Ë}"
ContentSource="Header"
Margin="2,0,2,0"
MaxHeight="15"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Grid>
</classic:SystemDropShadowChrome>
</Popup>
As you can see, the Background is inherited from RibbonGroup.
So, you have few variants to fix it:
Set the Background property for your RibbonGroup that is not transparent
Retemplate
Is it possible to disable the "Select all" button in the upper left corner of the WPF DataGrid?
There is a Property HeadersVisibility in DataGrid. It has four values - All, Column, Row, None.
With HeadersVisibility = All, you will get the SelectAll Button.
With HeadersVisibility = Column, you will get only Columns. Not the SelectAll Button or Row Headers to select a complete row.
With HeadersVisibility = Row, you will get only Row headers to select whole row. Not the SelectAll Button or Columns.
With HeadersVisibility = None, you will get nothing. All the headers will be hidden.
I hope this helps you.
After using Snoop to analyze the Visual Tree of a test app I put together, I came up with this solution using the DataGrid_Loaded event):
private void TheGrid_Loaded(object sender, RoutedEventArgs e) {
var dataGrid = (DataGrid)sender;
var border = (Border)VisualTreeHelper.GetChild(dataGrid, 0);
var scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0);
var grid = (Grid)VisualTreeHelper.GetChild(scrollViewer, 0);
var button = (Button)VisualTreeHelper.GetChild(grid, 0);
button.IsEnabled = false;
}
There may be a more elegant XAML only solution out there, but this is what came to mind first, and it seems to work well enough (I'm obviously not doing any Exception handling either).
Note: I haven't played around with disabling/re-enabling the DataGrid to make sure that the select all button stays disabled. If it doesn't stay disabled, then you may want to also hook into the DataGrid_IsEnabledChanged event.
Hope this helps!!
Add a commandbinding to the SelectAll Command and return false in the CanExecute to disable the selectall button.
see: Event for Select All: WPF Datagrid
If you don't need extended selection in your DataGrid (i.e. switch to single cell selection), you may set:
<DataGrid SelectionMode="Single">
It disables also SelectAll button in top-left corner.
Based on this answer, you can keep your headers and selection mode.
Inside the resources of your user control put :
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}"
TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<!-- an empty ControlTemplate is fine -->
<ControlTemplate TargetType="{x:Type Button}" />
</Setter.Value>
</Setter>
</Style>
With a little bit of more work, you can add a ToolTip to help the user to discover Ctrl and Shift.
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}"
TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<!-- an empty ControlTemplate is fine -->
<ControlTemplate TargetType="{x:Type Button}">
<DockPanel HorizontalAlignment="Center"
IsHitTestVisible="False"
VerticalAlignment="Center">
<TextBlock FontSize="18"
FontWeight="ExtraBlack"
Text="ⓘ"
TextAlignment="Center"
ToolTip="{StaticResource DataGridHowTo}" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
For the checkbox in the row headers see this post.
I would change the Control Template of DataGrid.
Needs to disable this button inside of template.
This is DataGrid ControlTemplate:
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True">
<ScrollViewer x:Name="DG_ScrollViewer"
Focusable="false">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Command="{x:Static DataGrid.SelectAllCommand}"
Focusable="false"
Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}"
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter"
Grid.Column="1"
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
CanContentScroll="{TemplateBinding CanContentScroll}"
Grid.ColumnSpan="2"
Grid.Row="1" />
<ScrollBar x:Name="PART_VerticalScrollBar"
Grid.Column="2"
Maximum="{TemplateBinding ScrollableHeight}"
Orientation="Vertical"
Grid.Row="1"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
ViewportSize="{TemplateBinding ViewportHeight}" />
<Grid Grid.Column="1"
Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar"
Grid.Column="1"
Maximum="{TemplateBinding ScrollableWidth}"
Orientation="Horizontal"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
ViewportSize="{TemplateBinding ViewportWidth}" />
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
Disable the button it manually and assign this ControlTemplate to your DataGrid.
I currently have a custom TabItem which has a custom header, which is defined as part of a Style like this:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type t:TwitterListTabItem}">
<Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" Margin="0,-2,0,0" >
<Grid SnapsToDevicePixels="true">
<ContentPresenter x:Name="Content" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header" RecognizesAccessKey="True" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="{TemplateBinding Padding}"/>
<Button x:Name="PART_Close" HorizontalAlignment="Right" Margin="0" Padding="4" VerticalAlignment="Top" Width="16" Height="16" Style="{DynamicResource CloseableTabItemButtonStyle}" ToolTip="Close Tab">
<Path x:Name="Path" Stretch="Fill" StrokeThickness="0.5" Fill="#FFFFFF" Data="F1 M 2.28484e-007,1.33331L 1.33333,0L 4.00001,2.66669L 6.66667,6.10352e-005L 8,1.33331L 5.33334,4L 8,6.66669L 6.66667,8L 4,5.33331L 1.33333,8L 1.086e-007,6.66669L 2.66667,4L 2.28484e-007,1.33331 Z " HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Button>
<Button x:Name="PART_Number" HorizontalAlignment="Right" Padding="0" Margin="0" VerticalAlignment="Bottom" Width="16" Height="16" Style="{DynamicResource CloseableTabItemNumberStyle}" ToolTip="New Tweets" Content="{TemplateBinding NewTweetsNumber}" />
</Grid>
</Border>
<ControlTemplate.Triggers>
.....Triggers Removed for Shortness....
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter
Now I want to set the template for the content area of the TabItem. I cannot work out how to do this. I have tried setting ContentTemplate, with a <ControlTemplate> containing a ListBox, but it didn't work.
So how do i define a template to control the content?
Thanks in advance
Use the TabItem.HeaderTemplate property for your tab header, and the TabItem.Template property for your tab's contents. Example.
Looks like you need one more ContentPresenter which displays the Content. And you already have a ContentPresenter which is displays Header.
<ContentPresenter ContentSource="Content"/>