Emoticons in TextBlock in WPF application - c#

I want to add emoticons to WPF chat application. I know that wpf don't supports emoticons for that reason I am replacing emoticons with image. I am using inline property of textBlock to add images to textBlock but, I having problem with alignment of images. I am not able to make emoticon images to get properly aligned. I am sharing a screenshot of how it is looking.
Screenshot of app window
This is how emoticon is looking
the example is just a demo where I am adding elements in constructor only to see how it will look. I am sharing my code as well.
#out.Inlines.Add(new Run("Hii, my name is Ajay!!"));
Image emo = new Image();
emo.Height = 15;
emo.Width = 15;
emo.VerticalAlignment = VerticalAlignment.Bottom;
emo.Margin = new Thickness(3, 0, 0, 0);
emo.Source = new BitmapImage(new Uri(#"C:\Users\admin\Desktop\test1.jpg", UriKind.RelativeOrAbsolute));
// InlineUIContainer container = new InlineUIContainer(emo);
#out.Inlines.Add(emo);
Is there any way I can make emoticon image properly align? Is it OK to use textblock or I should use any other control for this?
Any help is highly appreciated.

A few potential options may be:
set the Top margin on the Image. it's in the format of LEFT, TOP, RIGHT, BOTTOM
emo.Margin = new Thickness(3, 4, 0, 0);
Another option is to wrap the image in a Run and set the BaselineAlignment. https://msdn.microsoft.com/en-us/library/system.windows.baselinealignment
var imageRun= new Run(emo);
imageRun.BaselineAlignment = BaselineAlignment.TextBottom; //experiment with the other enum options
#out.Inlines.Add(imageRun);
adjust the text rather than the image (though i would keep trying with the image and use this as a last resort).
var textRun = new Run("Hii, my name is Ajay!!");
textRun.Margin = experiment;
textRun.BaselineAlignment = experiment;
#out.Inlines.Add(textRun );

I tried as #Bill Tarbell suggested and it worked for me.
Final working code is as follows:
var textRun = new Run("Hii, my name is Ajay!!");
textRun.BaselineAlignment = BaselineAlignment.Center;
#out.Inlines.Add(textRun);
Image emo = new Image();
emo.Height = 20;
emo.Width = 20;
emo.VerticalAlignment = VerticalAlignment.Bottom;
emo.Margin = new Thickness(3, 0, 0, 0);
emo.Source = new BitmapImage(new Uri(#"C:\Users\admin\Desktop\test1.jpg", UriKind.RelativeOrAbsolute));
// InlineUIContainer container = new InlineUIContainer(emo);
#out.Inlines.Add(emo)

Related

How to find the position of an Image in WPF C#?

I have an array which stores many images within in. I am trying to figure out how to get the position of the image (x,y) within the window. I aim to put it in a timer so I can get the updated location as the program runs.
The images are added with the following code:
arrayName[p] = new Image();
arrayName[p].Source = new BitmapImage(new Uri(#"imgPlaneSprite.png", UriKind.Relative));
arrayName[p].Width = 50;
arrayName[p].Height = 50;
arrayName[p].Stretch = Stretch.Fill;
LayoutRoot.Children.Add(arrayName[p]);
try this:
arrayName[p].PointToScreen(new Point(0, 0));

UWP Composition - Grid with rounded corners DropShadow

I have a UWP app, which I should start by pointing out that it uses very little XAML. The views are built from JSON object recieved from an API. This means that the vast majority of everything is done in C#, and therefore adds a little complexity to my problem.
I basically want to have a panel (e.g. Grid) that can have rounded corners and have a drop shadow applied to it. The drop shadow should also have the rounded corners, this can be seen in the sample below.
I have looked at the DropShadowPanel as part of the Windows Community Toolkit, but this from what I can tell doesn't do the rounded corners unless I change the content to be a rectangle or some other shape.
To use this as a solution would mean the XAML equivalent of something like:
<Grid>
<toolkit:DropShadowPanel>
<Rectangle />
<toolkit:DropShadowPanel>
<Grid CornerRadius="30">
<!-- My Content -->
</Grid>
</Grid>
To me, this seems like an inefficient use of XAML!
I have also discovered the Composition Pro Toolkit, which to me looks bery interesting as it is all code behind. In particular the ImageFrame control looks to achieve the basis of what I require - although far more advanced than my needs.
The below has been based on the ImageFrame, but doesn't work (content is my grid):
protected FrameworkElement AddDropShadow(FrameworkElement content)
{
var container = new Grid { HorizontalAlignment = content.HorizontalAlignment, VerticalAlignment = content.VerticalAlignment, Width = content.Width, Height = content.Height };
var canvas = new Canvas { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch };
content.Loaded += (s, e) =>
{
var compositor = ElementCompositionPreview.GetElementVisual(canvas).Compositor;
var root = compositor.CreateContainerVisual();
ElementCompositionPreview.SetElementChildVisual(canvas, root);
var shadowLayer = compositor.CreateSpriteVisual();
var frameLayer = compositor.CreateLayerVisual();
var frameContent = compositor.CreateShapeVisual();
root.Children.InsertAtBottom(shadowLayer);
root.Children.InsertAtTop(frameLayer);
frameLayer.Children.InsertAtTop(frameContent);
var rectangle = root.Compositor.CreateRoundedRectangleGeometry();
rectangle.Size = new Vector2((float)content.ActualWidth, (float)content.ActualHeight);
rectangle.CornerRadius = new Vector2(30f);
var shape = root.Compositor.CreateSpriteShape(rectangle);
shape.FillBrush = root.Compositor.CreateColorBrush(Colors.Blue);
//var visual = root.Compositor.CreateShapeVisual();
frameContent.Size = rectangle.Size;
frameContent.Shapes.Add(shape);
//create mask layer
var layerEffect = new CompositeEffect
{
Mode = Microsoft.Graphics.Canvas.CanvasComposite.DestinationIn,
Sources = { new CompositionEffectSourceParameter("source"), new CompositionEffectSourceParameter("mask") }
};
var layerEffectFactory = compositor.CreateEffectFactory(layerEffect);
var layerEffectBrush = layerEffectFactory.CreateBrush();
//CompositionDrawingSurface
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, new Microsoft.Graphics.Canvas.CanvasDevice(forceSoftwareRenderer: false));
var frameLayerMask = graphicsDevice.CreateDrawingSurface(new Size(0, 0), Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized, Windows.Graphics.DirectX.DirectXAlphaMode.Premultiplied);
layerEffectBrush.SetSourceParameter("mask", compositor.CreateSurfaceBrush(frameLayerMask));
frameLayer.Effect = layerEffectBrush;
var shadow = root.Compositor.CreateDropShadow();
//shadow.SourcePolicy = CompositionDropShadowSourcePolicy.InheritFromVisualContent;
shadow.Mask = layerEffectBrush.GetSourceParameter("mask");
shadow.Color = Colors.Black;
shadow.BlurRadius = 25f;
shadow.Opacity = 0.75f;
shadow.Offset = new Vector3(0, 0, 0);
shadowLayer.Shadow = shadow;
content.Opacity = 0; //hiding my actual content to see the results of this
};
container.Children.Add(canvas);
container.Children.Add(content);
return container;
}
In these tests, I am doing the same inefficient use of object, creating another container that has both the composition canvas, and also the grid. If possible, I'd like to apply the composition directly to the original content grid.
I am completely new to composition, so any thoughts, pointers, glaring errors or solutions would be most welcomed.
A Hack Solution?
I have changed my method to the following, visually it works - but is it right?
protected FrameworkElement AddDropShadow(FrameworkElement content)
{
var container = new Grid { HorizontalAlignment = content.HorizontalAlignment, VerticalAlignment = content.VerticalAlignment };
var rectangle = new Rectangle { Fill = new SolidColorBrush(Colors.Transparent) };
content.Loaded += (s, e) =>
{
rectangle.Fill = new SolidColorBrush(Colors.Black);
rectangle.Width = content.ActualWidth;
rectangle.Height = content.ActualHeight;
rectangle.RadiusX = 30;
rectangle.RadiusY = 30;
var compositor = ElementCompositionPreview.GetElementVisual(rectangle).Compositor;
var visual = compositor.CreateSpriteVisual();
visual.Size = new Vector2((float)content.ActualWidth, (float)content.ActualHeight);
var shadow = compositor.CreateDropShadow();
shadow.BlurRadius = 30f;
shadow.Mask = rectangle.GetAlphaMask();
shadow.Opacity = 0.75f;
visual.Shadow = shadow;
ElementCompositionPreview.SetElementChildVisual(rectangle, visual);
};
container.Children.Add(rectangle);
container.Children.Add(content);
return container;
}
The concept here is that my container grid holds a rectangle and my content grid (or other element).
The first error of this method is that is assumes my input FrameworkElement will be rectangular. I imagine that this could be improved upon by creating a bitmap render of the content as highlighted in this blog - but this will likely be quite costly. I also have to ensure that the rectangle size and shape exactly matches that of my main content!
It feels very wrong that there is a rectangle drawn on the screen (even though hidden by my main content). The rectangle is purely there to create the alpha mask so I guess it could be scrapped if the mask is created from the renderof the content.
I've tried setting the visibility of the rectangle to collapsed to remove it from the visual tree. This means that I can attach the visual to the container instead:
ElementCompositionPreview.SetElementChildVisual(container, visual)
However, doing this means that the shadow displays in front of the main content, which means I need some other ui element to attach it too - may as well be the rectangle!
Your solution to use Rectangle is my current workaround everywhere I need rounded shadow under Grid or Border. It's simple and it's plain, why should I complain :)
But if it's not your choice you can draw a rounded rectangle and blur it:
GraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(Compositor, CanvasDevice.GetSharedDevice());
var roudRectMaskSurface = GraphicsDevice.CreateDrawingSurface(new Size(SurfaceWidth + BlurMargin * 2, SurfaceHeight + BlurMargin * 2), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(roudRectMaskSurface))
{
ds.Clear(Colors.Transparent);
ds.FillRoundedRectangle(new Rect(BlurMargin, BlurMargin, roudRectMaskSurface.Size.Width + BlurMargin, roudRectMaskSurface.Size.Height + BlurMargin), YourRadius, YourRadius, Colors.Black);
}
var rectangleMask = Compositor.CreateSurfaceBrush(roudRectMaskSurface);
Now you can apply this surface in the EffectBrush with blur effect to obtain custom shadow.
BlurMargin - corresponds to the blur amount, you need it because your blurred surface will be bigger than initial source rectangle (to avoid blur clip).

I want to set a caption or description position in galleryitem control of devexpress

My Image Item
I'm create a GalleryItem and attached a image to GalleryControl.
by the way, description position is always right of image.
I want to change the position to bottom of image.
How can I move it?
List<GalleryItem> galleryItemList = new List<GalleryItem>();
GalleryItem gi = new GalleryItem();
BitmapImage bmpImg = new BitmapImage();
bmpImg.BeginInit();
bmpImg.UriSource = newUri(#"C:\temp\2.jpg");
bmpImg.EndInit();
gi.Glyph = bmpImg;
gi.Description = Path.GetFileName(bmpImg.UriSource.LocalPath);
galleryItemList.Add(gi);
myGalleryItemGroup.ItemSource = galleryItemList;
It is my code.
Set Gallery.ItemGlyphLocation to Top.
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
<dxb:GalleryControl>
<dxb:Gallery ItemGlyphLocation="Top">
<dxb:GalleryItemGroup x:Name="myGalleryItemGroup">
<!--...-->
</dxb:GalleryItemGroup>
</dxb:Gallery>
</dxb:GalleryControl>
Also, it might be best to direct your questions to DevExpress the next time you have one. Their customer support is awesome.

FormatConvertedBitmap with alpha

I've a problem in WPF. I'm making a delete button with an image in it. When the button is disabled, however, I wanted to display a greyscale image.
I found the Thomas Lebrun implementation, but I don't want to add the whole class in my program. Instead I tried to mimic the behavior in this way:
BitmapImage img_Delete = new System.Windows.Media.Imaging.BitmapImage(new Uri("the png URI", UriKind.RelativeOrAbsolute));
ImageSource img_DeleteDisabled = null;
[...]
Button btDel = new Button() { Width = 20, Height = 20, ToolTip = "Delete", Margin = new Thickness(5), HorizontalAlignment = System.Windows.HorizontalAlignment.Right };
btDel.IsEnabled = isdeletable(obj);
if (!btDel.IsEnabled && (img_DeleteDisabled == null))
{
img_DeleteDisabled = new FormatConvertedBitmap(img_Delete, PixelFormats.Gray32Float, null, 0);
}
btDel.Content = (new System.Windows.Controls.Image()
{
Width = 16,
Height = 16,
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
Source = btDel.IsEnabled ? img_Delete : img_DeleteDisabled
});
It behaves in the expected way, except.. Well, I'll show you:
The left one is enabled, the right one is disabled
As you can see the alpha channel is gone. How can I integrate it back?
Helped by the comments, I figured out I was thinking about the wrong place where to apply the opacity mask.
The OpacityMask should be applied to the button, not to the image. This is because the opacity applies to the whole image rather than its source.
For this reason, the correct way to implement this is
btDel.Content = (new System.Windows.Controls.Image()
{
Width = 16,
Height = 16,
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
Source = btDel.IsEnabled ? img_Delete : img_DeleteDisabled,
OpacityMask = new ImageBrush(img_Delete)
});
This way the mask is applied to the button image. The result is what I needed:

Label Image mode to stretch

I wrote this code to add my Labels:
JArray a = JArray.Parse(temp);
Label[] labels = new Label[100];
foreach (JObject o in a.Children<JObject>())
{
foreach (JProperty p in o.Properties())
{
string name = p.Name;
string value = p.Value.ToString();
if (name == "name")
{
labels[counter] = new Label();
//Image i = Image.FromFile("item.jpg");
labels[counter].Text = value;
labels[counter].Image =Image.FromFile("item.jpg");
//labels[counter].Image
//labels[counter].BackColor = Color.Blue;
labels[counter].TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
labels[counter].Top = height;
height += 50;
Controls.Add(labels[counter]);
}
}
}
The Image should stretch to the Label Size. How can I do this?
The abilities to show and manipulate images and text are spread out in a rather wild fashion among Winforms controls.
A Label can not stretch its Image.
A PictureBox and a Panel can but they don't show their Text
A Button can do both but will always be a Button, no matter how you style it..
So to get a combination you will need to either owner-draw something:
DrawImage in an overload to get the right size of the image, then add Image to Label
Or DrawString the Text onto a Panel to show it alongside the Image
or you could combine two controls with the right abilities:
You can create a Panel and set its BackgroundImage to your Image and its BackgroundImageLayout=Stretch. Then you can add your Label with its Text set to the Panel's controls collection:
// preparation for testing:
Image image = Image.FromFile("D:\\stop32.png");
Size size = new Size(77, 77);
// create the combined control
// I assume your Label is already there
Panel pan = new Panel();
pan.Size = size;
// or, since the Label has the right size:
pan.Size = label.Size; // use Clientsize, if borders are involved!
pan.BackgroundImage = image;
pan.BackgroundImageLayout = ImageLayout.Stretch;
label.Parent = pan; // add the Label to the Panel
label.Location = Point.Empty;
label.Text = "TEXT";
label.BackColor = Color.Transparent;
// add to (e.g.) the form
pan.Parent = this;
Set Borders as you like..
One more option: If all Images should have the same Size and if it is 256x256 pixels or less you could add them to an ImageList. This will stretch them to the ImageList.ImageSize in a very simple way and you can add them to your Label..
Very simple:
VB
Label1.Image = New Bitmap(Image.FromFile("Screenshot.jpg"), Label1.Size)
C#
Label1.Image = new Bitmap(Image.FromFile("Screenshot.jpg"), Label1.Size);
If you are using WinForms you try try below:
labels[counter].Size =
new Size(labels[counter].Image.Width, labels[counter].Image.Height);
This works perfect for me:
Just set the image in design mode (don't use imagelist) use the "Image" option
if we have label1 as the label where we want the image, put the next line inside the constructor:
label1.Image = new Bitmap(label1.Image, label1.Size);
I was trying the solution of Zibri, but deform the image in my case.

Categories

Resources