Need to draw something similar with WPF enter image description here

The application interface is similar to the chat that in the application Vk. so that there are messages from one user, and on the other hand - from another.

(I don’t need to implement the chat mechanism itself), It will load the correspondence from the source and form stories. One page - one story.

In general, dear gurus, I really need your advice on what tools to use in WPF for these purposes.

Tell me in which direction to look, and I will try to move independently. After an independent search, which did not give much, the following questions were formed:

  1. What controls can be redrawn in the form of these white and green figures? How do normal people actually do (control of custom form)?
  2. how to put the text inside?
  3. how to calculate the number of messages that fit on one page.

One more thing. An application should have a page navigation (if I understand the meaning of this concept correctly). You need a button that will go to the next page and the previous one. like when you click NEXT and the next slide opens.

  • "draw using WPF ... these white and green shapes" - you can create a shape using Path . displayed in the control Canvas - Stack

3 answers 3

You do not need a custom form control. You just need to draw a cloud with a tail of the desired size, and put the text inside.

Take the original image and remove the text from it:

bubble

This will be our background. Only it is necessary that he resized not equally. The standard idea is to select several areas:

bubble with areas

The angular areas should not change at all, the upper and lower side should stretch horizontally, the left and right side - vertically, and the center - in both directions. Since the top and bottom side images will still stretch in width, you can make them one pixel wide, and just like the left and right side bars - one pixel high. The central area can be done at all 1x1.

To implement this in WPF, let's get UserControl :

 <UserControl x:Class="ChatInterface.Bubble" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid> <!-- сетка 3х3 --> <Grid.ColumnDefinitions> <ColumnDefinition Width="11"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="17"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="11"/> <RowDefinition Height="*"/> <RowDefinition Height="11"/> </Grid.RowDefinitions> <!-- левый верхний уголок --> <Image Source="bubbleNW.png" Grid.Row="0" Grid.Column="0" RenderOptions.EdgeMode="Aliased" Stretch="None"/> <!-- верхняя полоса --> <Image Source="bubbleN.png" Grid.Row="0" Grid.Column="1" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <!-- правый верхний уголок --> <Image Source="bubbleNE.png" Grid.Row="0" Grid.Column="2" RenderOptions.EdgeMode="Aliased" Stretch="None"/> <!-- левая полоса --> <Image Source="bubbleW.png" Grid.Row="1" Grid.Column="0" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <!-- центр --> <Image Source="bubbleC.png" Grid.Row="1" Grid.Column="1" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <!-- и т. д. --> <Image Source="bubbleE.png" Grid.Row="1" Grid.Column="2" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <Image Source="bubbleSW.png" Grid.Row="2" Grid.Column="0" RenderOptions.EdgeMode="Aliased" Stretch="None"/> <Image Source="bubbleS.png" Grid.Row="2" Grid.Column="1" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <Image Source="bubbleSE.png" Grid.Row="2" Grid.Column="2" RenderOptions.EdgeMode="Aliased" Stretch="None"/> </Grid> </UserControl> 

Now, you need to impose on this text. An absolutely correct way would be to make a decorator with a newly created control in the background, but this requires advanced knowledge of WPF, so we will go in a simpler way: we will create another UserControl . A small trick is that the cloud must be the same size as the text, so you have to use Binding, and so that Bubble does not affect the layout itself, stick it, for example, in Canvas :

 <UserControl x:Class="ChatInterface.BubbleWithText" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ChatInterface" Name="root"> <Grid> <Canvas> <local:Bubble Height="{Binding ActualHeight, ElementName=tb}" Width="{Binding ActualWidth, ElementName=tb}"/> </Canvas> <TextBlock Name="tb" Padding="11" TextWrapping="Wrap" Text="{Binding Text, ElementName=root}"/> </Grid> </UserControl> 

In the code-behind you need to put the Text property:

 public partial class BubbleWithText : UserControl { public BubbleWithText() { InitializeComponent(); } #region dp string Text public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(BubbleWithText)); #endregion } 

Now you can shove our items into the StackPanel :

 <StackPanel Width="150"> <local:BubbleWithText Text="Я думаю, она дала тебе неправильный номер"/> <local:BubbleWithText Text="А может быть и нет, кто их разберёт?"/> </StackPanel> 

and get the following:

result

Of course, it is better to draw the original images yourself (or request from the designer), and in no case save to JPEG.


If you want to do more correctly, use the decorator:

 public class BubbleDecorator : Decorator { Bubble bubble = new Bubble(); public BubbleDecorator() { bubble.SetBinding(Bubble.WidthProperty, new Binding("ActualWidth") { Source = this }); bubble.SetBinding(Bubble.HeightProperty, new Binding("ActualHeight") { Source = this }); } protected override Visual GetVisualChild(int index) { if (Child != null) { if (index == 0) return bubble; if (index == 1) return Child; } throw new IndexOutOfRangeException("Wrong child index"); } protected override Size ArrangeOverride(Size arrangeSize) { bubble.Arrange(new Rect(arrangeSize)); return base.ArrangeOverride(arrangeSize); } protected override int VisualChildrenCount { get { return Child == null ? 0 : 2; } } } 

We get the following XAML:

 <StackPanel Width="150"> <local:BubbleDecorator HorizontalAlignment="Right" Margin="2"> <TextBlock Padding="13" TextWrapping="Wrap" Text="Я думаю, она дала тебе неправильный номер"/> </local:BubbleDecorator> <local:BubbleDecorator HorizontalAlignment="Right" Margin="2"> <TextBlock Padding="13" TextWrapping="Wrap" Text="А может быть и нет, кто их разберёт?"/> </local:BubbleDecorator> <local:BubbleDecorator HorizontalAlignment="Right" Margin="2"> <TextBlock Padding="13" TextWrapping="Wrap" Text="Приффки!!1"/> </local:BubbleDecorator> </StackPanel> 

new result

  • one
    E ... For joint stretching, no magic is needed, it is enough to put both the bubble and the text in one grid (without rows and columns). Well and on separate it does not pull in any way, the template for any ContentControl here asks. At the same time there will be no restrictions on the content. - Athari
  • @Discord: I tried it, my bubble wanted to stretch out more than the text (I didn’t find out why the pictures seemed to be strangely rubbed off), and thus they had empty spaces under the text. - VladD
  • @Discord: I wrote there in the answer, we really need a decorator. - VladD 7:49 pm
  • one
    @Discord it is just enough for him to declare a style in which to wrap them all. And you have to either copy the style from the file to the file - or throw it into the global styles dump. - Pavel Mayorov
  • one
    @PavelMayorov Now you will tell me that it’s bad to allocate styles to shared resources? o_O You would have looked at your leisure, how standard controls are implemented. And how they are stylized. - Athari

The idea of ​​cutting the picture into 9 parts @Vlad explained. Now I will show how to do the same in the simplest way and in the vector. Drawing primitive, as an example. Pay attention to the use of exclusively styles, patterns and binding to the properties of the control. No C # code, no user controls, no decorators; the output is only ContentControl with two styles: for the left and right bubble.

 <Window x:Class="SoRu479660.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Chat" Height="500" Width="300"> <Window.Resources> <!-- Пузырь --> <Style x:Key="Bubble" TargetType="Control"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Control"> <Grid SnapsToDevicePixels="True"> <Grid.ColumnDefinitions> <ColumnDefinition Width="10"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="10"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="10"/> <RowDefinition Height="*"/> <RowDefinition Height="10"/> </Grid.RowDefinitions> <Polygon Grid.Row="0" Grid.Column="0" Points="0 10, 10 0, 10 10" Fill="{TemplateBinding Background}"/> <Rectangle Grid.Row="0" Grid.Column="1" Fill="{TemplateBinding Background}"/> <Polygon Grid.Row="0" Grid.Column="2" Points="0 0, 10 10, 0 10" Fill="{TemplateBinding Background}"/> <Rectangle Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Fill="{TemplateBinding Background}"/> <Polygon Grid.Row="2" Grid.Column="0" Points="0 0, 10 0, 10 10, 8 8, 0 10, 5 5" Fill="{TemplateBinding Background}"/> <Rectangle Grid.Row="2" Grid.Column="1" Fill="{TemplateBinding Background}"/> <Polygon Grid.Row="2" Grid.Column="2" Points="0 0, 10 0, 0 10" Fill="{TemplateBinding Background}"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Текст с переносом строк --> <Style x:Key="WrapStyle" TargetType="TextBlock"> <Setter Property="TextWrapping" Value="Wrap"/> </Style> <!-- Текст в пузыре, левая версия --> <Style x:Key="BubbleLeftStyle" TargetType="ContentControl"> <Setter Property="Margin" Value="2"/> <Setter Property="Padding" Value="8 5"/> <Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Grid Margin="{TemplateBinding Margin}"> <Control Style="{StaticResource Bubble}" Background="LimeGreen"/> <ContentPresenter Margin="{TemplateBinding Padding}"> <ContentPresenter.Resources> <Style TargetType="TextBlock" BasedOn="{StaticResource WrapStyle}"/> </ContentPresenter.Resources> </ContentPresenter> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Текст в пузыре, правая версия --> <Style x:Key="BubbleRightStyle" TargetType="ContentControl" BasedOn="{StaticResource BubbleLeftStyle}"> <Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Grid Margin="{TemplateBinding Margin}"> <Control Style="{StaticResource Bubble}" Background="DeepSkyBlue" RenderTransformOrigin=".5 0"> <Control.RenderTransform> <ScaleTransform ScaleX="-1"/> </Control.RenderTransform> </Control> <ContentPresenter Margin="{TemplateBinding Padding}"> <ContentPresenter.Resources> <Style TargetType="TextBlock" BasedOn="{StaticResource WrapStyle}"/> </ContentPresenter.Resources> </ContentPresenter> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <StackPanel> <ContentControl Style="{StaticResource BubbleLeftStyle}" Content="Hello world!"/> <ContentControl Style="{StaticResource BubbleLeftStyle}" Content="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."/> <ContentControl Style="{StaticResource BubbleRightStyle}" Content="Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."/> <ContentControl Style="{StaticResource BubbleRightStyle}" Content="Hello world!"/> <ContentControl Style="{StaticResource BubbleLeftStyle}" Content="Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."/> <ContentControl Style="{StaticResource BubbleRightStyle}" Content="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."/> </StackPanel> </Window> 

The result looks like this:

  • Comments are not intended for extended discussion; conversation moved to chat . - PashaPash

Here is an option with the decorator based on the @VladD solution (I am writing from memory, typos are possible)

 <UserControl x:Class="ChatInterface.Bubble" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <UserControl.Template> <ControlTemplate TargetType="UserControl"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="11"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="17"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="11"/> <RowDefinition Height="*"/> <RowDefinition Height="11"/> </Grid.RowDefinitions> <Image Source="bubbleNW.png" Grid.Row="0" Grid.Column="0" RenderOptions.EdgeMode="Aliased" Stretch="None"/> <Image Source="bubbleN.png" Grid.Row="0" Grid.Column="1" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <Image Source="bubbleNE.png" Grid.Row="0" Grid.Column="2" RenderOptions.EdgeMode="Aliased" Stretch="None"/> <Image Source="bubbleW.png" Grid.Row="1" Grid.Column="0" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <Image Source="bubbleC.png" Grid.Row="1" Grid.Column="1" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <Image Source="bubbleE.png" Grid.Row="1" Grid.Column="2" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <Image Source="bubbleSW.png" Grid.Row="2" Grid.Column="0" RenderOptions.EdgeMode="Aliased" Stretch="None"/> <Image Source="bubbleS.png" Grid.Row="2" Grid.Column="1" RenderOptions.EdgeMode="Aliased" Stretch="Fill"/> <Image Source="bubbleSE.png" Grid.Row="2" Grid.Column="2" RenderOptions.EdgeMode="Aliased" Stretch="None"/> <ContentPresenter Grid.Row="1" Grid.Column="1" /> </Grid> </ControlTemplate> </UserControl.Template> </UserControl> 

Using:

 <local:Bubble>Привет, мир!</local:Bubble> <local:Bubble> <TextBlock TextWrapping="Wrap" Text="Привет, мир!"/> </local:Bubble> 
  • You essentially have a trimmed version of my version. :) - Athari
  • Template UserControl is an interesting technique, did not know. - VladD
  • There will be no distortion if the entire UI changes the zoom in + or -? - Stack