It is stated in MSDN that
Starting with Windows 10, version 1809, you can use the x:Bind markup extension anywhere you use TemplateBinding in a ControlTemplate.
However, when I try to replace TemplateBinding with {x:Bind} whilst defining the style of a custom control, as so,
<Style TargetType="local:PomodoroTimer" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:PomodoroTimer">
<Grid Width="300" Height="300" Background="{x:Bind Background}">
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I get the following error: Unable to resolve symbol 'Background'. What am I missing?
x:Bind needs code-behind. (see here)
So, thanks to MainWindow.xaml.cs, this works:
<Window
x:Class="Bindings.MainWindow"
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:local="using:Bindings"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.Resources>
<Style
x:Key="CustomButtonStyle"
TargetType="Button">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
BorderBrush="{x:Bind BorderBrush, Mode=OneWay}"
BorderThickness="{x:Bind BorderThickness, Mode=OneWay}">
<ContentControl Content="{x:Bind Content, Mode=OneWay}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</Grid.Resources>
<Button
BorderBrush="SkyBlue"
BorderThickness="1"
Content="Custom Button"
Style="{StaticResource CustomButtonStyle}" />
</Grid>
</Window>
For custom (templated) controls, I'd go with:
Text="{TemplateBinding Text}"
or
Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
for TwoWay bindings.
If you want to do x:Bind inside the ControlTemplate, this answer might help.
Custom Control.cs
public class CustomButtons: Control
{
public static readonly DependencyProperty CmdExecProperty = DependencyProperty.Register(nameof(CmdExec), typeof(bool), typeof(CustomButtons), new PropertyMetadata("True"));
public bool CmdExec
{
get => (bool)GetValue(CmdExecProperty);
set => SetValue(CmdExecProperty, value);
}
Generic.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:v="clr-namespace:ServicePageKit"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Theme/CompoundControlStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Control template for a CustomButtons -->
<ControlTemplate x:Key="CustomButtonsTemplate"
TargetType="{x:Type v:CustomButtons}">
<Grid Width="128"
d:DesignHeight="200">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition MaxHeight="52" />
</Grid.RowDefinitions>
<Button x:Name="LoadButton"
Grid.Row="1"
Height="50"
HorizontalAlignment="Stretch"
Command="{Binding CopyCommand}"
CommandParameter="{Binding Path=Critical,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type v:CustomButtons}},
Mode=OneWay}"
Content="Copy"
IsEnabled="true" />
</Button>
</Grid>
</ControlTemplate>
<Style x:Key="CustomButtonsStyle"
TargetType="{x:Type v:CustomButtons}">
<Setter Property="Template" Value="{StaticResource CustomButtonsTemplate}" />
</Style>
<Style TargetType="{x:Type v:CustomButtons}" BasedOn="{StaticResource CustomButtonsStyle}" />
</ResourceDictionary>
Usage
<kit:CustomButtons x:Name="SyskonButtons"
CmdExec="True"/>
This CustomControl works fine but I want that when CmdExec DepenpencyProperty is True, then the command (command names is used in Generic.xaml under Button) should execute, regardless the button is pressed or not.
I am building a chat application in which i have below xaml code -
<Page
x:Class="MyProject1.MainPage"
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:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d" Background="Black">
<Grid Background="White" Name="mainGrid">
<Border BorderBrush="Cyan" BorderThickness="0.2" Margin="3,0,3,3">
<ListView x:Name="ListView" VerticalAlignment="Bottom" SelectionMode="None" IsItemClickEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<controls:MarkdownTextBlock Name="markdownBlock" Text="{Binding Text}" TextWrapping="Wrap" FontFamily="Segoe-UI">
</controls:MarkdownTextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="Black" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Border>
</Grid>
</Page>
I use below code in my code behind to send text to the MarkdownTextBlock control
messages.Add(new Message() { Text = "**Person 1:** " + message });
and the response -
messages.Add(new Message() { Text = "**Person 2:** " + activity.Text });
Right now the format is plain background like below -
Person 1: Hello, How are you doing?
Person 2: Hi, I am doing great!
How can i format these plain messages to get conversation feel like we have in skype as
I am new to Windows Application development, I am not sure how to format the text as conversations within markdown text block, could you guide me?
Do I need to create a table within markdown control and pass the messages by having background color on rows? not sure how to do this. Any help?
Updated view -
<Page
x:Class="MyProject1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gif="using:XamlAnimatedGif"
xmlns:local="using:LISA_Speech1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d" Background="Black">
<Page.Resources>
<Style x:Key="MessageItemStyle" TargetType="SelectorItem">
<Setter Property="Height" Value="Auto" />
<Setter Property="Width" Value="450" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Padding" Value="10" />
<Setter Property="Margin" Value="5" />
</Style>
<Style
x:Key="RightAlignedMessageStyle"
BasedOn="{StaticResource MessageItemStyle}"
TargetType="SelectorItem">
<Setter Property="Background" Value="LightGray" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style
x:Key="LeftAlignedMessageStyle"
BasedOn="{StaticResource MessageItemStyle}"
TargetType="SelectorItem">
<Setter Property="Background" Value="Orange" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<styleSelectors:MessageContainerStyleSelector
x:Key="MessageContainerStyleSelector"
ReceivedStyle="{StaticResource LeftAlignedMessageStyle}"
Sender="{x:Bind CurrentUser, Mode=OneWay}"
SentStyle="{StaticResource RightAlignedMessageStyle}" />
<DataTemplate x:Key="MessageTemplate" x:DataType="messages:Message">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind Message, Mode=OneWay}"
TextWrapping="WrapWholeWords" />
<StackPanel
Grid.Row="1"
Margin="0,5,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock
HorizontalAlignment="Right"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind SentDate, Mode=OneWay}" />
</StackPanel>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Key="MessageItemPanelTemplate">
<ItemsStackPanel VerticalAlignment="Bottom" ItemsUpdatingScrollMode="KeepLastItemInView" />
</ItemsPanelTemplate>
</Page.Resources>
<Grid Background="Black" Name="mainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<Border BorderBrush="Cyan" BorderThickness="0.2" Margin="3,0,3,3">
<ListView
x:Name="Messages"
Margin="10"
CanDrag="False"
CanReorderItems="False"
IsItemClickEnabled="False"
IsTapEnabled="False"
ItemContainerStyleSelector="{StaticResource MessageContainerStyleSelector}"
ItemTemplate="{StaticResource MessageTemplate}"
ItemsPanel="{StaticResource MessageItemPanelTemplate}"
ItemsSource="{x:Bind Text, Mode=OneWay}" />
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="35"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox x:Name="text" KeyUp="TextBox_KeyDown" Grid.Column="0" PlaceholderText="Type something or say 'Start Listening'" FontSize="17" BorderBrush="Purple" Margin="0,10,0,-7" Height="58" VerticalAlignment="Top">
</TextBox>
<Button x:Name="button" Click="Button_Click" Grid.Column="1" Height="58" Width="35" Padding="0" Background="Purple" Margin="0,10,0,-7">
<SymbolIcon x:Name="symbol" Symbol="Microphone" Width="35" HorizontalAlignment="Center" Foreground="White" Margin="-2,-8,-2,-2"/>
</Button>
</Grid>
<MediaElement x:Name="Media"></MediaElement>
</Grid>
</Page>
You can achieve this quite simple using an ItemContainerStyleSelector. What this will do is allow you to create some logic that takes your chat message object and determine if it was sent or received.
For example, your model may look like this:
public class Message
{
public Guid Id { get; set; }
public string UserTo { get; set; }
public string UserFrom { get; set; }
public string Message { get; set; }
public DateTime SentDate { get; set; }
}
You then will create the StyleSelector like this:
public class MessageContainerStyleSelector : StyleSelector
{
public Style SentStyle { get; set; }
public Style ReceivedStyle { get; set; }
public string Sender { get; set; }
protected override Style SelectStyleCore(object item, DependencyObject container)
{
var message = item as Message;
if (message != null)
{
return message.UserFrom.Equals(this.Sender, StringComparison.CurrentCultureIgnoreCase)
? this.SentStyle
: this.ReceivedStyle;
}
return base.SelectStyleCore(item, container);
}
}
From here, we then need to create the styles that will be used with this style selector and they are very simple. They will also give you flexibility for the colors you're looking to use for the sent or received messages.
In your view, you may have styles set up like this:
<Page.Resources>
<Style x:Key="MessageItemStyle" TargetType="SelectorItem">
<Setter Property="Height" Value="Auto" />
<Setter Property="Width" Value="450" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Padding" Value="10" />
<Setter Property="Margin" Value="5" />
</Style>
<Style
x:Key="RightAlignedMessageStyle"
BasedOn="{StaticResource MessageItemStyle}"
TargetType="SelectorItem">
<Setter Property="Background" Value="LightGray" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style
x:Key="LeftAlignedMessageStyle"
BasedOn="{StaticResource MessageItemStyle}"
TargetType="SelectorItem">
<Setter Property="Background" Value="Orange" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<styleSelectors:MessageContainerStyleSelector
x:Key="MessageContainerStyleSelector"
ReceivedStyle="{StaticResource LeftAlignedMessageStyle}"
Sender="{x:Bind CurrentUser, Mode=OneWay}"
SentStyle="{StaticResource RightAlignedMessageStyle}" />
<DataTemplate x:Key="MessageTemplate" x:DataType="messages:Message">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind Message, Mode=OneWay}"
TextWrapping="WrapWholeWords" />
<StackPanel
Grid.Row="1"
Margin="0,5,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock
HorizontalAlignment="Right"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind SentDate, Mode=OneWay}" />
</StackPanel>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Key="MessageItemPanelTemplate">
<ItemsStackPanel VerticalAlignment="Bottom" ItemsUpdatingScrollMode="KeepLastItemInView" />
</ItemsPanelTemplate>
</Page.Resources>
In these styles, you see that we are using a base style which the two chat message styles inherit from. We are using a right/left alignment in this scenario so your messages will show on either side of the screen but here you can customize each style to your own needs.
A few other things to point out here, we are also declaring the DataTemplate that will be used to show layout the message. Notice here we aren't doing anything custom. Every message will layout the same, it's the container style that will alter how they appear in the ListView.
Also the ItemsPanelTemplate at the bottom allows the ListView to present the messages bottom up in a chat style format.
In regards to how this all ties together with your ListView in the page, you would now use the MessageContainerStyleSelector like this:
<ListView
x:Name="Messages"
Margin="10"
CanDrag="False"
CanReorderItems="False"
IsItemClickEnabled="False"
IsTapEnabled="False"
ItemContainerStyleSelector="{StaticResource MessageContainerStyleSelector}"
ItemTemplate="{StaticResource MessageTemplate}"
ItemsPanel="{StaticResource MessageItemPanelTemplate}"
ItemsSource="{x:Bind Messages, Mode=OneWay}" />
When you're running the app, you'll get something that looks similar to this:
Hopefully this is something to go off and you can take this further with this detail. Feel free to ask any questions, I'm happy to help.
The first thing I would do is a custom control called MessageViewer. In this one you could have a parameter that tells you what's the direction of the message, or just two another classes MessageViewerIn and MessageViewerOut that could be like this:
XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="1" Fill="LightBlue" RadiusX="15" RadiusY="15"></Rectangle>
<TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="10" Text="Some dummy text here"></TextBlock>
</Grid>
Now, via code you could understand if you need an image on the LEFT or RIGHT column of this grid. Everything will depend if the text you're showing is from an user or if YOU are sending this text.
So, you could add some methods to check it (or directly do in in the constructor of this class like:
MessageViewer(String message, bool orientation)
MessageViewer msgVwr = new MessageViewer("Your Text", true/false)
...and if its true your icon will be on the left, and when it's false on the right. Inside of the control you can access various element, so for example, if you'll give a name for a grid
<Grid Name="grdMain">
you can acces his properties via code, like grdMain.Background, and set it and change it.
For the space on the left/right you could use margins of the interlat textbox, setted on "10, 10, 30, 10" for right-space (yours) messages and "30, 10, 10, 10" for left-space (incoming) messages.
For doing some text work, like bold or other, check out elements you can put inside a grid: everything you want :)
All this elements you could put in a simple ListView to show them like a chat.
I have a question regarding styles in xaml wpf.
I have a Default style which should apply for all Objects. But for some of them I want to set a second style overriding a few attributes.
Now if I give my second style a x:key="style2" and set this as style, my first Default style is not applied, but the Default WPF style is. I can not/want not Change anything at my first Default style
How can I fix this behaivor?
To ensure that your default style is still applied, you add
BasedOn={StaticResource ResourceKey={x:Type ControlType}}
Where ControlType is the type of object the default style was applied to.
Here's an example:
<Window x:Class="StyleOverrides.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="Comic Sans MS" />
</Style>
<Style x:Key="Specialization"
TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource ResourceKey={x:Type TextBlock}}"
>
<Setter Property="FontStyle" Value="Italic" />
<Setter Property="Foreground" Value="Blue" />
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Viewbox Grid.Row="0" >
<TextBlock>This uses the default style</TextBlock></Viewbox>
<Viewbox Grid.Row="1">
<TextBlock Style="{StaticResource Specialization}">
This is the specialization
</TextBlock>
</Viewbox>
</Grid>
</Window>
I'm trying to add a ToolTip to a Grid using a Style (as follows):
<ResourceDictionary>
<Style x:Key="ToolTipGrid" TargetType="{x:Type Grid}" x:Shared="False">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ItemsControl ItemsSource="{Binding ElementName=this, Path=Right}"
ItemTemplate="{StaticResource KeyValueDataTemplate}" />
<ItemsControl ItemsSource="{Binding ElementName=this, Path=Left}"
ItemTemplate="{StaticResource KeyValueDataTemplate}" />
</Grid>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
However, at runtime I get the following error:
Cannot add content of type
'System.Windows.Controls.ToolTip' to
an object of type 'System.Object'.
Error at object
'System.Windows.Controls.ToolTip' in
markup file
'InnoFit;component/controls/fittingdetails.xaml'
Line 24 Position 26.
What's wrong here?