How to add an Image and a Textblock into a WPF ContentControl - c#

I have a ContentControl in WPF,which has an image in it
ContentControl myContentControl = new ContentControl();
myContentControl.Content = image;
How do I to add a textblock next to the image inside the ContentControl?
Thank you.

You need to change the property ContentTemplate of the contentControl, as to ContentTemplate, here is some explanation:
Gets or sets the data template used to display the content of the ContentControl.
Also you need create a class to represent your data, like this:
public class ImageInfo
{
public string Caption { get; set; }
public ImageSource Image { get; set; }
}
It is better to create ContentControl in XAML, like this:
<ContentControl x:Name="cc">
<ContentControl.ContentTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Image}" />
<TextBlock Text="{Binding Caption}" />
</StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
Then, assign the data to the ContentControl:
cc.Content = new ImageInfo() { Caption = "Hello", Image = new BitmapImage(new System.Uri("/Assets/User.jpg", UriKind.Relative)) };

What you are doing looks like you are not familiar with MVVM:
Please check here
Easy Solution
But if you want the ugly solution and create UIElements in your code behind - go like this:
public static ContentControl CreateControl(string title, Uri path)
{
//Create your image
BitmapImage bitmapImage = new BitmapImage(path);
Image image = new Image()
{
Source = bitmapImage
};
//Create your Text
TextBlock textB = new TextBlock()
{
Text = title
};
//Put them together
StackPanel content = new StackPanel();
content.Children.Add(image);
content.Children.Add(textB);
//Add this to the content control
return new ContentControl()
{
Content = content
};
}

Related

C# bin new Textblock object to Textblock control in XAML file

I want to show in my C#-WPF application a text containing links. The texts are static and known during compile time.
The following is doing want i want when working directly on the XAML file:
<TextBlock Name="TextBlockWithHyperlink">
Some text
<Hyperlink
NavigateUri="http://somesite.com"
RequestNavigate="Hyperlink_RequestNavigate">
some site
</Hyperlink>
some more text
</TextBlock>
Since using MVVM i want to bind the Textblock to a newly constructed Textblock object, through a dependency property. The XAML then looks like this:
<StackPanel Grid.Row="1" Margin="5 0 0 0">
<TextBlock Height="16" FontWeight="Bold" Text="Generic Text with link"/>
<TextBlock Text="{Binding Path=TextWithLink, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
In my ViewModel i place
private void someMethod(){
...
TextWithLink = CreateText();
...
}
private TextBlock(){
TextBlock tb = new TextBlock();
Run run1 = new Run("Text preceeding the hyperlink.");
Run run2 = new Run("Text following the hyperlink.");
Run run3 = new Run("Link Text.");
Hyperlink hyperl = new Hyperlink(run3);
hyperl.NavigateUri = new Uri("http://search.msn.com");
tb.Inlines.Add(run1);
tb.Inlines.Add(hyperl);
tb.Inlines.Add(run2);
return tb;
}
private TextBlock _textWithLink;
public TextBlock TextWithLink {
get => _textWithLink;
set{
_textWithLink = value;
OnPropertyChanged();
}
}
The dependency property setup is working i see a new TextBlock getting assigned to the XAML control, however there is no content shown, just the displayed text reads
System.Windows.Controls.TextBlock
rather than the content. I cannot get my head around what i have to change to show the desired mixed text. Happy for an help.
Instead of using a TextBlock instance in a view model, you should instead use a collection of Inline elements with a UI element that accept it as the source of a Binding.
Since the Inlines property of a TextBlock is not bindable, you may create a deribed TextBlock with a bindable property like this:
public class MyTextBlock : TextBlock
{
public static readonly DependencyProperty BindableInlinesProperty =
DependencyProperty.Register(
nameof(BindableInlines),
typeof(IEnumerable<Inline>),
typeof(MyTextBlock),
new PropertyMetadata(null, BindableInlinesPropertyChanged));
public IEnumerable<Inline> BindableInlines
{
get { return (IEnumerable<Inline>)GetValue(BindableInlinesProperty); }
set { SetValue(BindingGroupProperty, value); }
}
private static void BindableInlinesPropertyChanged(
DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var textblock = (MyTextBlock)o;
var inlines = (IEnumerable<Inline>)e.NewValue;
textblock.Inlines.Clear();
if (inlines != null)
{
textblock.Inlines.AddRange(inlines);
}
}
}
Now you may use it like
<local:MyTextBlock BindableInlines="{Binding SomeInlines}"/>
with a view model property like this:
public IEnumerable<Inline> SomeInlines { get; set; }
...
var link = new Hyperlink(new Run("Search"));
link.NavigateUri = new Uri("http://search.msn.com");
link.RequestNavigate += (s, e) => Process.Start(e.Uri.ToString());
SomeInlines = new List<Inline>
{
new Run("Some text "),
link,
new Run(" and more text")
};

XAML label to C# code for creating dynamic labels [duplicate]

This question already has answers here:
How can I dynamically create a list of label and textboxes in WPF?
(2 answers)
How to generate labels, buttons, Checkboxes and textboxes dynamically in WPF App
(1 answer)
create dynamically label at wpf
(1 answer)
Closed 3 years ago.
I created labels in XAML that are multiline and all lines are centered, tested and working perfectly fine. Now I want to create these labels dynamically but unfortunately I don't know how to do this.
tried setting LineStackingStrategy on MaxHeight, Fontfamily
tried creating new Textblock on fontfamily
XAML Code to reproduce in C# code:
<Label HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="btn_02" Height="70" Width="160" BorderBrush="#F0F2A4" BorderThickness="2" Background="Transparent" Foreground="#F0F2A4" FontFamily="Arial" FontSize="13" TextBlock.LineStackingStrategy="BlockLineHeight" TextBlock.LineHeight="17" Content="ORGEL
LADEN" TextBlock.TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,200,0,0" MouseLeftButtonDown="Btn_02_MouseLeftButtonDown"/>
C# code to create label dynamically:
Label label = new Label()
{
HorizontalAlignment = HorizontalAlignment.Center,
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top,
VerticalContentAlignment = VerticalAlignment.Center,
Name = "orgel" + i.ToString(),
Height = 70,
Width = 160,
BorderBrush = (SolidColorBrush)(new BrushConverter().ConvertFrom("#F0F2A4")),
BorderThickness = new Thickness(2),
Background = Brushes.Transparent,
Foreground = (SolidColorBrush)(new BrushConverter().ConvertFrom("#F0F2A4")),
FontFamily = new FontFamily("Arial"),
FontSize = 13,
Content = orgel,
Margin = new Thickness((columncount * 100), (rowcount * 100), 0, 0)
};
I want to add TextBlock.LineStackingStrategy="BlockLineHeight" TextBlock.LineHeight="17" Content="ORGEL
LADEN" TextBlock.TextAlignment="Center" from XAML to this C# code.
Whenever you want to create UI elements dynamically you should think of a DataTemplate first. Use a ItemsControl to create UI elements simply by adding data to the ObservableCollection that serves as the Binding.Source of ItemsControl.ItemsSource. The DataTemplate is used to define the appearance of the items (a Labelin your case).
Data Templating Overview
ViewModel.cs
class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> labelContents;
public ObservableCollection<string> LabelContents
{
get => this.labelContents;
set
{
this.labelContents = value;
OnPropertyChanged();
}
}
// Constructor
public void ViewModel()
{
// Initialize the data binding source of the ListView
this.LabelContents = new ObservableCollection<string>();
}
public void CreateLabelDynamically(string labelText)
{
this.LabelContents.Add(labelText);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
When executing CreateLabelDynamically() a new label in form of a TextBlock is added to the view.
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<ListView x:Name="SpectrumBars"
ItemsSource="{Binding LabelContents}">
<ListView.ItemTemplate>
<DataTemplate DataType="system:string">
<!-- The DataContext of the TextBlock is the string value contained in LabelContents -->
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Window>
It is also recommended to use a TextBlock instead of a Label when possible:
When data binding the Label element's Content property to the String source object, you may experience poor performance.
Avoid Databinding to the Label.Content Property

Bind image to datagrid using resources

I am trying to retrieve the image from resource file and tryin to bind it to the datagrid of my WPF application.
The datagrid is somewhat like this:
<DataGridTemplateColumn Header="Image" Width="45">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Path=Icon}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
And Image is a property of type image of my MVVm class like this:
public Image Icon
{
get { return _licenseImage; }
set { _licenseImage = value;
PropertChanged("Icon");}
}
And in the code behind Im tryin to do something like this to get image from resource file and tryin to bind it to datagrid column.
ResourceManager resourceManager =
new ResourceManager("Resources.Images", Assembly.GetExecutingAssembly());
BitMap bitmap = resourceManager.GetObject("okimage") as BitMap;
Image image = bitmap;
return image;
I can see that image is populated but it is not displaying in the grid.
You should bind to an ImageSource instead of Image.
we use this helper class:
public static class ImageSourceHelper
{
public static ImageSource GetResourceImage(string resourcePath)
{
return GetResourceImage(Assembly.GetCallingAssembly(), resourcePath);
}
public static ImageSource GetResourceImage(Assembly resourceAssembly, string resourcePath)
{
if (string.IsNullOrEmpty(resourcePath)) return null;
var assembly = resourceAssembly.GetName().Name;
const string uriFormat = "pack://application:,,,/{0};component/{1}";
if (!UriParser.IsKnownScheme("pack")) new System.Windows.Application();
var uri = new Uri(string.Format(uriFormat, assembly, resourcePath), UriKind.RelativeOrAbsolute);
return BitmapFrame.Create(uri);
}
public static ImageSource ConvertFromGdiBitmap(Bitmap bitmap)
{
return Common.SystemAbstraction.Media.ImageConverter.ConvertToBitmapSource(bitmap);
}
public static Bitmap ConvertToGdiBitmap(ImageSource imageSource)
{
return Common.SystemAbstraction.Media.ImageConverter.ConvertToBitmap(imageSource as BitmapSource);
}
}
It creates an ImageSource from Bitmap or resource images.
Usage is
img.Source = ImageSourceHelper("Path/To/Your/Image.png");
or
var resourceAssembly = // get resource assembly...
img.Source = ImageSourceHelper(resourceAssembly, "Path/To/Your/Image.png");
if the image is contained in an other assembly than the currently calling assembly.
The path of your image is the path starting at the project file root of your assembly.
Say you have an folder images your path will be "images/somepicture.png".
I think the problem is that you are binding to the wrong property. Try this:
<Image Source="{Binding Path=Icon}" />

adding an image to a label in wpf?

I am currently developing an application in C# using WPF. What I need to be able to do is on a label make their be an image to the left of the text of the label a small image of an X or a small image of a tick depending on the circumstances. I have got the images included in the project in a folder named images.
How can I assign the images to be placed on the left of the label programatically in the code and not using the XAML code.
You can either group this inside a grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding ImageSourceProperty}" />
<Label Grid.Column="1" Content="{Binding LabelTextProperty}" />
</Grid>
Or, since the label is a content control, you can simply put the image control inside a label control:
<Label>
<Image Source="{Binding ImageSourceProperty}" />
My Text
</Label>
Once you know how the xaml should look like, it is very easy to create the same elements via code.
Since you want this in code behind and not within XAML I would suggest ditching the Label and using a StackPanel coupled with an Image and TextBlock as seen below where MyGrid could be any container...
<Grid Name="MyGrid"/>
...then in your code behind...
StackPanel myStackPanel = new StackPanel();
myStackPanel.Orientation = Orientation.Horizontal;
Image myImage = new Image();
BitmapImage myImageSource = new BitmapImage();
myImageSource.BeginInit();
myImageSource.UriSource = new Uri("Images/MyImage.png");
myImageSource.EndInit();
myImage.Source = myImageSource;
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "This is my image";
myStackPanel.Children.Add(myImage);
myStackPanel.Children.Add(myTextBlock);
MyGrid.Children.Add(myStackPanel);
I don't agree with the two other answers here. There is no need for a grid to be added to wrap the content. The stackpanel is sufficient.
In the xaml add a stackpanel to where you need the content to be.
<StackPanel Name="myStack" Orientation="Horizontal"></StackPanel>
Then in the code behind, like in a button handler or when the window loads add this
Image coolPic = new Image() {
Name="pic",
Source = new BitmapImage(new Uri("pack://application:,,,/images/cool.png")),
Stretch = Stretch.None // this preserves the original size, fill would fill
};
TextBlock text = new TextBlock() {
Name = "myText",
Text = "This is my cool Pic"
};
myStack.Children.Add(coolPic); // adding the pic first places it on the left
myStack.Children.Add(text); // the text would show up to the right
You can swap the location of the image and the text by adding the text first then the image.
If you don't see the image ensure the image's build action is set to resource in the properties window of the image.
In order for the code to be more useful and or more dynamic you would need a way to change either the text or the image.
So lets say you did want to change those and you go ahead and do a
((TextBlock)FindName("myText")).Text = "my other cool pic";
You would expect the text to be changed but what happens?
Object reference not set to an instance of an object.
Drats but I gave it a name. You would need to add
// register the new control
RegisterName(text.Name, text);
So that you can access the textblock later. This is needed because you added the control to the framework after it was built and displayed. So the final code looks like this after registering the image too
Image coolPic = new Image() {
Name="pic",
Source = new BitmapImage(new Uri("pack://application:,,,/images/cool.png")),
Stretch = Stretch.None // this preserves the original size, fill would fill
};
// register the new control
RegisterName(coolPic.Name, coolPic);
TextBlock text = new TextBlock() {
Name = "myText",
Text = "This is my cool Pic"
};
// register the new control
RegisterName(text.Name, text);
myStack.Children.Add(coolPic);
myStack.Children.Add(text);

Image.Location variant for WPF?

I'm a noob when it comes to WPF; In win forms I can do this:
public void blah()
{
using( var o = new OpenFileDialog())
{
if(o.ShowDialog() == DialogResult.OK)
{
PictureBox p = new PictureBox();
p.ImageLocation = o.FileName;
p.AutoSize = SizeMode.AutoSize;
this.Controls.Add(p);
}
}
}
But in WPF I have no idea at all and not even MSDN will give me any clear info on how to insert a pic onto the form at runtime! Can someone please help?
Thank you very much
Basically you need to create a System.Windows.Controls.Image and set its Source to a System.Windows.Media.Imaging.BitmapImage. Then add the image to the Children of the Container. You may want to put the image inside of another container first like a Canvas. Here's a quick translation of your code, but you'll likely need to play with it a bit to get it just right.
public void blah()
{
using( var o = new OpenFileDialog())
{
if(o.ShowDialog() == DialogResult.OK)
{
Image i = new Image();
i.Source = new BitmapImage(o.FileName);
//p.AutoSize = SizeMode.AutoSize; <= not sure about this part.
this.Children.Add(i);
}
}
}
You could use XAML and some bindings (and possibly a converter to convert a string to an image source). It's more in keeping with the WPF way of doing things.
Example without converter:
XAML
<Window
...
x:Name="this"
DataContext="{Binding ElementName=this}">
<Grid>
<ListView ItemsSource="{Binding MyImageCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
Code Behind
public class Window1 : Window {
public ObservableCollection<ImageSource> MyImageCollection { get; set; }
...
public void blah()
{
using( var o = new OpenFileDialog())
{
if(o.ShowDialog() == DialogResult.OK)
{
MyImageCollection.Add(new BitmapImage(new Uri(o.FileName)));
}
}
}
}
Here is an easier way to do it.
Image.Source = new BitmapImage(new Uri("C:\MyImage.jpg");

Categories

Resources