What I am trying to do is use C# to write the code of ContentTemplate instead of XAML. Here is the XAML code that I have:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="AnyButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140"/>
<ColumnDefinition Width="310"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="/Images/AnyImage.png" Height="80" Width="80" HorizontalAlignment="Left" Margin="15,0,0,0"/>
<TextBlock Grid.Column="1" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Left" Text="AnyText" FontSize="30" FontFamily="{StaticResource PhoneFontFamilySemiLight}" Margin="0,0,0,0"/>
</Grid>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
And here is the code that I used inside my ContentPanel to use the ContentTemplate:
<Button x:Name="MyButton"
Click="MyButton_Click"
ContentTemplate="{StaticResource AnyButton}"
Width="492" Height="130"
Margin="6,0,6,-6"
Background="#003d0a"/>
Now, my question is, is it possible to write the whole code using C#?
if you are trying to do it in styling purpose do it in the following way:
<Style x:Key="MyButton" TargetType="Button">
<Setter Property="Width" Value="460"></Setter>
<Setter Property="Background" Value="/Images/AnyImage.png"></Setter>
</Style>
define this in app.xaml or PhoneApplicationPage.resources and in your button control in xaml set your style to MyButton. for example:
<Button style={StaticResource MyButton}/>
if you also want to define width and height for your image you can do it same way by defining style in value section set the value with that style. for example:
<style x:key ="MyImage" TargetType="Image">
<setter property="Width" Value="150"/>
</style>
in my button style define background value ={StaticResource MyImage}
Related
I have several controls and I want to show them only one at a time.
In QML there is a type StackLayout which does that. But I haven't found a similar control in WPF.
I want to achieve the following:
<controls:StackLayout ControlIndex="{Binding CurrentlyVisibleControlIndex}">
<controls:MyCustomControl1 />
<controls:MyCustomControl2 />
<TextBlock Text="Some text" />
<Grid/>
</controls:StackLayout>
Then, from my ViewModel I want to dynamically change which control is shown.
Answers:
Direct answer to my question
Better way of solving my problem
In this case, I would go with a ContentControl templated based on the type of content you give it in your view model (rather than based on index). As the property changes, the appropriate template will be selected and displayed.
XAML
Resources define data templates for each kind of content in the control
<Window.Resources>
<DataTemplate DataType="{x:Type local:ContentXyz}">
<controls:ControlXyz/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ContentAbc}">
<controls:ControlAbc/>
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding Content}"/>
ViewModel
The Content property holds the view model for the active control. When user actions or data changes require to display a different control, set it to the appropriate view model.
public IContent Content
{
get => this.content;
set => this.SetProperty(ref this.content, value);
}
And viewmodel classes for your inner user controls need to implement IContent (which is just a marker interface to describe the view model can be used in this place).
More
Also, frameworks like Prism help you compose views in more complex ways, giving you tools like automatic view discovery - see their documentation for more.
But, I'm afraid that "abusing" ListBox for achieving my goal is not a good idea, because ListBox handles "Ctrl+LeftMouseCLick" which will deselect the item.
The ListBox needs to be hidden. It will not render.
Only its SelecteItem will be rendered.
Example for explanation:
<Window x:Class="StackLayout.StackLayoutWindow"
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:StackLayout"
mc:Ignorable="d"
Title="StackLayoutWindow" Height="450" Width="800">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Enter the index:" Margin="5"/>
<TextBox x:Name="textBox" Grid.Column="1" Text="1" Margin="5"
HorizontalContentAlignment="Center"/>
<TextBlock Grid.Row="1" Text="Selected Item:" Margin="5" VerticalAlignment="Center"/>
<ListBox x:Name="listBox"
SelectedIndex="{Binding Text, ElementName=textBox, Mode=OneWay}"
Visibility="Collapsed">
<TextBlock Text="TextBlock" FontSize="20"/>
<Button Content="Click me!" Padding="15 5"/>
<Border Background="Blue" Width="100" Height="100"/>
<Label Content="Label" BorderBrush="SkyBlue" BorderThickness="5"/>
</ListBox>
<ContentPresenter Grid.Row="1" Grid.Column="1"
Content="{Binding SelectedItem, ElementName=listBox}"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</Window>
Do you know if it is possible to create a custom user control which will contain the list and ContentPresenter so it can be used in the way I specified in my question?
In this case (as far as I understood the task), it makes no sense.
It is enough to override the default ListBox template.
In the example, to shorten the code, the template is specified in the Window resources.
But it is better to transfer it to the dictionary and connect it to the App.
<Window x:Class="StackLayout.StackLayoutTemplateWindow"
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:StackLayout"
mc:Ignorable="d"
Title="StackLayoutTemplateWindow" Height="450" Width="800">
<FrameworkElement.Resources>
<SolidColorBrush x:Key="ListBox.Static.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Static.Border" Color="#FFABADB3"/>
<SolidColorBrush x:Key="ListBox.Disabled.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Disabled.Border" Color="#FFD9D9D9"/>
<Style x:Key="ListBoxStyle.StackLayout" TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{StaticResource ListBox.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource ListBox.Static.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
<!--<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>-->
<ContentPresenter Content="{TemplateBinding SelectedItem}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{StaticResource ListBox.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource ListBox.Disabled.Border}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</FrameworkElement.Resources>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Enter the index:" Margin="5"/>
<TextBox x:Name="textBox" Grid.Column="1" Text="1" Margin="5"
HorizontalContentAlignment="Center"/>
<TextBlock Grid.Row="1" Text="Selected Item:" Margin="5" VerticalAlignment="Center"/>
<ListBox x:Name="listBox"
SelectedIndex="{Binding Text, ElementName=textBox, Mode=OneWay}"
Style="{DynamicResource ListBoxStyle.StackLayout}"
Grid.Row="1" Grid.Column="1"
VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="TextBlock" FontSize="20"/>
<Button Content="Click me!" Padding="15 5"/>
<Border Background="Blue" Width="100" Height="100"/>
<Label Content="Label" BorderBrush="SkyBlue" BorderThickness="5"/>
</ListBox>
</Grid>
</Window>
Optionally, you can easily create a Custom Control from the ListBox with this template.
Although I do not see the point in this.
Thanks to #EldHasp's answer I have found a much simpler solution:
<ListBox x:Class="MyProject.StackLayout"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<ContentPresenter Content="{TemplateBinding SelectedItem}"/>
</ControlTemplate>
</ListBox.Template>
</ListBox>
And it can be used in the following way:
<controls:StackLayout SelectedIndex="{Binding CurrentlyVisibleControlIndex}">
<controls:MyCustomControl1 />
<controls:MyCustomControl2 />
<TextBlock Text="Some text" />
<Grid/>
</controls:StackLayout>
By the way, using the way you have proposed I have found that it is possible to implement the StackLayout much simpler
You can think of many options for implementation.
WPF is a very flexible tool.
And the task itself is relatively simple.
Here's an example of a Sharpe implementation:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace StackLayout
{
public class StackLayout : ListBox
{
public StackLayout()
=> Loaded += OnStackLayoutLoaded;
public static void OnStackLayoutLoaded(object sender, RoutedEventArgs e)
{
ListBox listBox = (ListBox)sender;
Border border = (Border)VisualTreeHelper.GetChild(listBox, 0);
ContentPresenter presenter = new ContentPresenter();
Binding snapsToDevicePixelsBinding = new Binding()
{
Path = new PropertyPath(SnapsToDevicePixelsProperty),
Source = listBox
};
Binding selectedItemBinding = new Binding()
{
Path = new PropertyPath(SelectedItemProperty),
Source = listBox
};
presenter.SetBinding(SnapsToDevicePixelsProperty, snapsToDevicePixelsBinding);
presenter.SetBinding(ContentPresenter.ContentProperty, selectedItemBinding);
border.Child = presenter;
}
}
}
In my example, the default ListBox border is preserved, but if desired, you can also remove it.
BUT once again I would like to draw your attention to the fact that you have most likely chosen the wrong path for the realization of your task as a whole.
I have created a custom control for the simplified usage of label: control in forms:
My problem is that, no matter what is being put into my control content, I am unable to align it, using my template code. The only way it works is when I put HorizontalAlignment="Right" into the TextBox control directly:
<local:ControlEntry Label="Enter something">
<!-- I don't like having HorizontalAlignment here! -->
<TextBox Height="20" Width="200" HorizontalAlignment="Right" />
</local:ControlEntry>
However, I would rather want to do that behind the scenes in my control template.
I'm talking about this particular XAML code:
<Border x:Name="Container"
HorizontalAlignment="Stretch"
Grid.Column="1">
<ContentPresenter Width="{Binding ActualWidth, ElementName=Container}" HorizontalAlignment="Right" />
</Border>
First, I stretch the HorizontalAlignment, so what it would fill the width of the grid column cell, then I'm trying to apply the Right HorizontalAlignment on the ContentPresenter. Unfortunately, no effect is visible.
Full control code:
<Style TargetType="{x:Type local:ControlLine}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ControlLine}">
<!-- Create bottom content border -->
<Border BorderBrush="#000" BorderThickness="0,0,0,0.5">
<StackPanel>
<Grid>
<!-- Label -> Control -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Label -->
<TextBlock Grid.Column="0"
Margin="0,12,15,12"
VerticalAlignment="Center"
Text="{Binding Label, RelativeSource={RelativeSource TemplatedParent}}"
TextWrapping="WrapWithOverflow" />
<!-- Display content -->
<Border x:Name="Container"
HorizontalAlignment="Stretch"
Grid.Column="1">
<ContentPresenter Width="{Binding ActualWidth, ElementName=Container}" HorizontalAlignment="Right" />
</Border>
</Grid>
<!-- Description -->
<TextBlock Text="The control description" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I properly keep the width stretched and at the same time align the content of ContentPresenter to right?
I have a XAML window with a TextBox, and this TextBox has an ErrorTemplate.
The ErrorTemplate is shown below, and as you can see, I have an AdornedElementPlaceholder, followed by a textbox whose Text field is bound to the ErrorContent:
<ControlTemplate x:Key="ValidationErrorTemplateTextBlock" TargetType="{x:Type Control}">
<Border BorderBrush="Red" BorderThickness="1">
<StackPanel Orientation="Vertical">
<AdornedElementPlaceholder Name="AdornedElementPlaceholder" />
<TextBlock Text="{Binding ElementName=AdornedElementPlaceholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
FontSize="10"
Background="Red"
Foreground="White"
Padding="2" />
</StackPanel>
</Border>
</ControlTemplate>
<TextBox IsEnabled="{Binding SendMessage}"
Text="{Binding AutoMessageSubject, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource StyleBase}"
Validation.ErrorTemplate="{StaticResource ValidationErrorTemplateTextBlock}"
HorizontalAlignment="Stretch"
Grid.Row="3"
Grid.Column="1"
Grid.ColumnSpan="2" />
This works fine, except for one thing: the TextBox is inside a GridRow, with a Height="Auto". The row scales itself based on the textbox, but when the ErrorTemplate appears, with an extra TextBox on the bottom - the GridRow doesn't scale up to contain the new TextBox, and the new TextBox overlaps the elements below it.
How can I solve this?
Validation.ErrorTemplate: Gets or sets the ControlTemplate used to generate validation error feedback on the adorner layer.
This means that if you use Validation.ErrorTemplate, the validation errors are displayed on the layer above usual content, so the "second" TextBlock is displayed over the grid, not within the grid cell.
I would implement INotifyDataErrorInfo instead of semi-obsolete IDataErrorInfo, use a custom textbox style, and bind the visibility of the second TextBlock to HasErrors property. The example below uses a ToolTip instead of the second TextBlock:
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<ItemsControl DisplayMemberPath="ErrorContent" ItemsSource="{Binding Path=(Validation.Errors)}" />
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
You might want to try adding Row/Column Definitions:
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
So, I have a datagrid that has different colour cells depending on the cell's value.
I also have a tooltip that displays some further information. This all works fine.
I, however, would like to alter the tooltip to show further information and also to be the same colour as the cell. So, I thought it would be wise to create a custom style for my tool tips. So, I have the below code.
<Style TargetType="ToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border CornerRadius="15,15,15,15"
BorderThickness="3,3,3,3"
Background="#AA000000"
BorderBrush="#99FFFFFF"
RenderTransformOrigin="0.5,0.5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"/>
<TextBlock Grid.Row="1"/>
<TextBlock Grid.Row="2"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have an object shown below that is bound to my datagrid. I want to bind the three properties to the three textboxes in my tooltip.
class MyTask
{
public string Name;
public int Code;
public string Description;
}
In my DataGrid I do the following to bind my data to my datagrid
ItemsSource="{Binding TaskList}"
Then in the DataGridTextColumn I bind to a property like below
DataGridTextColumn Header="Code" Binding="{Binding Code}"
This makes sense to me. I am however at a loss to see how I use binding when creating my custom tooltip. I read that I can use templatebinding. I still don't understand how my tooltip will bind to my object of type MyTask in my xaml above?
Update - hopefully make my question clearer
I want to know how to create the bindings in my control template (for the 3 textboxes) and then in the main part of my code how I bind to these text boxes. I then would like to know how to create a binding for the background colour of my control template, I believe this is something to do with relativesource?
When I'm reading other examples (changing the Template Property) I see lines like below. I don't really understand why you have to do it? Is it a case of if you didn't right the line below you wouldn't be able to create a binding on the Padding property?
<Border Padding="{Binding Padding}" ...>
You don't need TemplateBindng, as that is used for setting up the resulting template object to layout based on dynamically using the properties of the implementing control. See this CodePlex article for a good example of when you'd need such functionality.
You simply need to set the bindings of your TextBlock elements within your ToolTip. You don't really need a Template at all in this case, except that since you are using the same ToolTip across all your column cells, it will help you out as you don't need to copy-paste the same code three times. You are after something similar to this article, Tooltip in DataGrid in WPF.
A solution which would work specifically to your case would be like:
<DataGrid Name="TestGrid1" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}">
<TextBlock.ToolTip>
<ToolTip />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Code">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Code}">
<TextBlock.ToolTip>
<ToolTip />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Description">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}">
<TextBlock.ToolTip>
<ToolTip />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.Resources>
<Style TargetType="ToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border CornerRadius="15,15,15,15"
BorderThickness="3,3,3,3"
Background="#AA000000"
BorderBrush="#99FFFFFF"
RenderTransformOrigin="0.5,0.5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Name}"/>
<TextBlock Grid.Row="1" Text="{Binding Code}"/>
<TextBlock Grid.Row="2" Text="{Binding Description}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
</DataGrid>
You set the ToolTip property within the CellTemplate so that the resulting ToolTip that pops up has the same DataContext as the active row in the DataGrid. This way, you can simply do your property bindings as normal within your ToolTip ContentTemplate, since it has access to all the same properties as does your DataGrid for the row.
To use underlying DataGridCell Background as ToolTip Background, bind your Border Background as Background="{Binding PlacementTarget.Background, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}" .
You are trying to show all the fields in the tooltip of a cell. That doesn't make sense. But still you can do that easily using
PlacementTarget property, which gives you the underlying Visual element. ContextMenu, Popup too expose this property.
PlacementTarget.DataContext will give you the underlying MyTask object.
PlacementTarget.Content will give you the content of the corresponding DataGridCell, in your case it will be TextBlock.
So, if you want to show 3 fields in your cell's tooltip, below code will work for you using point number 2 above.
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="Tomato"/>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip>
<ToolTip.Style>
<Style TargetType="ToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border CornerRadius="15,15,15,15"
BorderThickness="3,3,3,3"
Background="{Binding PlacementTarget.Background, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}"
BorderBrush="#99FFFFFF"
RenderTransformOrigin="0.5,0.5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding PlacementTarget.DataContext.Name, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}"
/>
<TextBlock Grid.Row="0" Text="{Binding PlacementTarget.DataContext.Code, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}"
/>
<TextBlock Grid.Row="0" Text="{Binding PlacementTarget.DataContext.Description, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}"
/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToolTip.Style>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle>
And, if you want to show only corresponding cell's field in your cell's tooltip, then remove the remaining 2 textblocks, and use only one as :
<TextBlock Text="{Binding PlacementTarget.Content.Text, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}" />
If you want to show all 3 fields, then apply the ToolTip to DataGridRow using DataGrid.RowStyle. No change in code would be needed.
What about using a color property in MyTask?
class MyTask
{
public string Name { get; set; }
public int Code { get; set; }
public string Description { get; set; }
public SolidColorBrush Color { get; set; }
}
And binding to the color property:
<Style TargetType="ToolTip">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border Name="Border" Background="{Binding Color}" BorderBrush="{StaticResource SolidBorderBrush}" BorderThickness="1" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<StackPanel>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Code}" />
<TextBlock Text="{Binding Description}" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Why don't you go for DataTemplate of tool tip like give it's a key and apply it in your cell tool tip style.
<Style TargetType="ToolTip" x:Key="ToolTipStyle">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate TargetType="ToolTip">
<Border CornerRadius="15,15,15,15"
BorderThickness="3,3,3,3"
Background="#AA000000"
BorderBrush="#99FFFFFF"
RenderTransformOrigin="0.5,0.5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"/>
<TextBlock Grid.Row="1"/>
<TextBlock Grid.Row="2"/>
</Grid>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Now, you can bind your property to textblock too.
I have the following UserControl in a Windows Phone 8.1 Project:
<UserControl
x:Name="AuditItem"
x:Class="WindowsPhone.OverviewAuditItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WindowsPhone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Height="Auto"
Tapped="AuditItem_Tapped"
Style="{StaticResource MyUserControlStyle}">
<Grid x:Name="contentGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Height="160" >
<TextBlock x:Name="textAuditName" Margin="10,10,0,0" TextWrapping="Wrap" Text="Audit Name" VerticalAlignment="Top"/>
<TextBlock x:Name="textCreatedDate" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Center"/>
<TextBlock x:Name="textLastOpened" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Center" />
<!--<Button Content="This styling works but the UC style doesn't"
Height="100"
Style="{StaticResource MyButtonStyle}" />-->
<StackPanel Orientation="Horizontal" Grid.Column="2">
<TextBlock x:Name="textDeadline" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Center" Grid.Column="2"/>
<Grid x:Name="blockOverdue" Margin="10,0,0,0">
<Image Source="PNGs/alerticon.png" Stretch="None" HorizontalAlignment="Center" />
</Grid>
</StackPanel>
<TextBlock x:Name="textTemplate" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Center" Grid.Column="3"/>
</StackPanel>
</Grid>
I have defined my style in the App.xaml file:
<Style TargetType="local:OverviewAuditItem" x:Key="MyUserControlStyle" >
<Setter Property="Background" Value="Blue" />
<Setter Property="FontFamily" Value="Arial Black" />
<Setter Property="FontSize" Value="36" />
</Style>
I know that the Style is being "found" because I don't get the "Resource could not be resolved" error (which I do get if I change the name for a test)
None of the styling is being applied though. I expected the UserControl background to be blue and all textblocks on the control to use the text size and family. I'm pretty new to this so maybe it doesn't work like this.
My questions: Should it work like I'm assuming? if yes, then where am I going wrong, if no, then how do I apply styling to a UserControl?
As a test - you can see I have a commented out button, the styling for this does work.
So your Style is targeting the wrong Type to get what I think you are asking for you will need to do this:
This Targets any UserControl's that use the MyUserControlStyle key
<Style TargetType="UserControl" x:Key="MyUserControlStyle" >
<Setter Property="Background" Value="Blue" />
</Style>
This Targets all TextBlocks on the Page -
Notice no key here so it targets all textblocks. To target individual TextBlocks add a key and implement it in the TextBlocks Style property
<Style TargetType="TextBlock" >
<Setter Property="FontFamily" Value="Arial Black" />
<Setter Property="FontSize" Value="36" />
</Style>
For more info on WPF styles take a look here