I wanna show an image in WPF that is created by a process,
e.g : we have a method that is named createWPFImage()
Image createWPFImage() { ... }
So, the output of createWPFImage() is an Image.
In the XAML code, we have a something like below :
<StackPanel.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Width="64" Height="64" Margin="0 2 4 0" />
<TextBlock Text="{Binding Path=Description}" VerticalAlignment="Center" />
</StackPanel>
</StackPanel.ToolTip>
Now, How can I bind the output of createWPFImage() to the Image in XAML code ?
I would be appreciate if you guide me.
Say you have class "MyClass" with method "CreateWpfImage" (see example below).
In your XAML you can create MyClass, and then call CreateWpfImage, using ObjectDataProvider in a Resources section (See Bea Stollnitz blog article ObjectDataProvider).
XAML
<Window x:Class="MyApplicationNamespace.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:MyApplicationNamespace="clr-namespace:MyApplicationNamespace"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ObjectDataProvider ObjectType="{x:Type MyApplicationNamespace:MyClass}" x:Key="MyClass" />
<ObjectDataProvider ObjectInstance="{StaticResource MyClass}" MethodName="CreateWpfImpage" x:Key="MyImage" />
</Window.Resources>
<StackPanel>
<Image Source="{Binding Source={StaticResource MyImage}, Path=Source}"/>
</StackPanel>
Example MyClass code to create an image for the XAML to use -
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace MyApplicationNamespace
{
public class MyClass
{
public Image CreateWpfImpage()
{
GeometryDrawing aGeometryDrawing = new GeometryDrawing();
aGeometryDrawing.Geometry = new EllipseGeometry(new Point(50, 50), 50, 50);
aGeometryDrawing.Pen = new Pen(Brushes.Red, 10);
aGeometryDrawing.Brush = Brushes.Blue;
DrawingImage geometryImage = new DrawingImage(aGeometryDrawing);
Image anImage = new Image();
anImage.Source = geometryImage;
return anImage;
}
}
}
If you have a path to your image and just want to be able to change the image on the fly, then bind to a dependency property of type string and in your method, set the value of the dependency property.
<Image Source="{Binding MyImagePath}" />
public static readonly DependencyProperty MyImagePathProperty = DependencyProperty.Register("MyImagePath", typeof(string), typeof(ClassName), new PropertyMetadata("pack://application:,,,/YourAssembly;component//icons/icon1.png"));
public string MyImagePath
{
get { return (string)GetValue(MyImagePathhProperty); }
set { SetValue(MyImagePathProperty, value); }
}
Related
I'm using a ListBox in combination with a ObservableCollection. The content is set via a TemplateSelector (TextBlock or Label). The text has to be formatted (f.e. with Run-Tags in Code-behind), but i can't access the Items. Is there a solution to get the elements?
I've tried the usage of OfType<>, but this works only on Panels. I searched for an children-attribute but, there isn't one for ListBoxes. Setting the Name-Property via binding is not possible for UId and Name.
An IEnumerator for the LogicalChildren doesn't work and iterate over the whole content everytime a new element is added, is not so optimal. Here a minimal example.
<Window.Resources>
<DataTemplate x:Key="TextBlockTemplate">
<StackPanel>
<TextBlock />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="LabelTemplate">
<StackPanel>
<Label/>
</StackPanel>
</DataTemplate>
<local:myTemplateSelector x:Key="myTemplateSelector" x:Name="myTemplateSelector" TextBlockTemplate="{StaticResource TextBlockTemplate}" LabelTemplate="{StaticResource LabelTemplate}"/>
</Window.Resources>
<Grid Margin="0">
<ListBox Name="mylist" Grid.Row="3"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding _listEntries}"
ItemTemplateSelector="{StaticResource myTemplateSelector}"
>
</ListBox>
</Grid>
Greetings and thanks :)
The TextBlock has an Inlines property that returns the Inline elements that comprise the contents of the TextBlock.
The Label has a Content property that you, depending on how you are using it, may cast to a Panel.
There are no inline elements for a TextBox.
Now, I found a solution. I made the TextBlock and Label as User Control and set the Name-property. In the code-behind, I have access to the DataContext and the element can set itself.
<UserControl x:Class="Test.TextBlockControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TextBlockControl"
Loaded="UserControl_Loaded">
<Grid>
<StackPanel HorizontalAlignment="Stretch" Margin="0,0,0,0">
<TextBlock Name="textBlock"/>
</StackPanel>
</Grid>
In the Code behind i can now access the values and set:
public partial class TextBlockControl : UserControl
{
public List<string> name => DataContext as List<string>;
public TextBlockControl()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
foreach (var t in name)
{
var run = new Run(t.Text);
if (t.IsHighlighted)
{
run.Foreground = Brushes.Green;
}
else
{
run.Foreground = Brushes.Red;
}
textBlock.Inlines.Add(run);
}
}
}
}
In the MainWindow, the dataTemplate then references the UserControl (root is the namespace):
<root:PickControl />
XAML
<Page x:Class="ManufacturingWPF.ShowHardware"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ManufacturingWPF"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="ShowHardware">
<Grid Background="AliceBlue">
<ListBox x:Name="HardwareList" ItemsSource="{Binding Hardware}" HorizontalAlignment="Left" Height="122" Margin="76,36,0,0" VerticalAlignment="Top" Width="149">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Date}"/>
<TextBlock Text="{Binding Nodes}"/>
<TextBlock Text="{Binding Repeaters}"/>
<TextBlock Text="{Binding Hubs}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Code Behind C#
public partial class ShowHardware : Page
{
public ShowHardware()
{
InitializeComponent();
DisplayData();
}
public void DisplayData()
{
//Datamodel MDM used for ADO and table creation
//Test is a class used to pass the model and as the name suggest
test it
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> x = t.GetHardware();
foreach(Hardware i in x )
{
HardwareList.ItemsSource = i.Hubs.ToString();
}
}
}
}
I'm facing issues binding the data to the listbox as shown in the XAML and code-behind content.
I've tried previous answers without any luck , did my research but apparently I'm missing out something or maybe there is something I don't quite understand.
Itemsource as the name suggest should bind to the source of where my data is being held. In this case the source would be my class Hardware that holds data for Nodes, date , hubs etc etc.
And in the textblock I manually bind these properties and display the values.
But this is not working.
P.S. My DB table is populated.
That's because the ItemsSource is an IEnumerable and you assign to it the list of hardware itself. So you code should look something like this :
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> x = t.GetHardware();
HardwareList.ItemsSource = x;
//or
foreach (Hardware h in x)
HardwareList.Items.Add(h);
This code seems wrong
foreach(Hardware i in x )
{
HardwareList.ItemsSource = i.Hubs.ToString();
}
Then ItemsSource for Binding has to be a Collection (List, ObservableCollecion, IEnumerable<> ...).
Try HardwareList.ItemsSource = x; and remove the foreach loop
I hope this can help you.
I want to bind button visibility in a XAML file to a private Visibility variable in the associated C# view model code. When the code is run, the button continues to show and not hide as defined in the private visibility variable. I have tried many things after reading many responses on the internet to similar problems.
The following run-time error seen in the output window has stopped product development:
System.Windows.Data Error: 40 : BindingExpression path error: 'SaveCalButtonVisibility' property not found on 'object' ''CalibrationSet' (HashCode=40040273)'. BindingExpression:Path=SaveCalButtonVisibility; DataItem='CalibrationSet' (HashCode=40040273); target element is 'Button' (Name=''); target property is 'Visibility' (type 'Visibility')
The current object is CalibrationSetList and for some reason, it seems to try to bind the XAML Save Calibration Button Visibility property to DataItem=CalibrationSet Path=SaveCalButtonVisibility path. I believe that this should bind to the DataItem=CalibrationSetList Path=SaveCalButtonVisibility path to work properly. I am at a loss to complete this binding.
The development environment is Microsoft Visual Studio 2010 with Infragistics 2013.2. The XAML and C# code are shown below with unrelated code left out. The code is written following the MVVM pattern, WPF, and PRISM 4.0
Any help, suggestions, or continuing dialog is greatly appreciated.
XAML Code:
<!-- CalibrationSetList.xaml -->
<UserControl
x:Class="Method.Control.CalibrationSetList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:I18N="clr-namespace:I18N;assembly=I18N"
xmlns:I18NStrings="clr-namespace:I18N.Strings;assembly=I18N.Strings"
xmlns:Conv="clr-namespace:Converters;assembly=Converters"
mc:Ignorable="d"
xmlns:Local="clr-namespace:Method.Control"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:AuthInfrastructure="clr-namespace:Authorization.Components;assembly=Authorization.Components"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Visibility="{Binding Path=CalibrationSetListControl}">
<Grid Visibility="{Binding Path=CalibrationSetListVisibility}" >
<Grid.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/>
</Grid.Resources>
<DataGrid EnableRowVirtualization="False"
EnableColumnVirtualization="False"
IsReadOnly="True"
ItemsSource="{Binding CalibrationCollection, Mode=TwoWay}"
SelectedValue="{Binding Path=SelectedCalibrationSetValue}"
HorizontalGridLinesBrush="Transparent"
VerticalGridLinesBrush="Transparent" Margin="30">
<DataGrid.Columns>
<!--…………………………………->
<!--Save Calibration button-->
<DataGridTemplateColumn Width="125">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Style="{DynamicResource CustomButton}"
Visibility="{Binding Path=SaveCalButtonVisibility,Mode=TwoWay,
diag:PresentationTraceSources.TraceLevel=High}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding Path=DataContext.SaveCalibrationClick,
RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}" >
<Button.Content>
<MultiBinding Converter="{Conv:StringToLocalizedString ResourceKey=SaveCalibration}">
<Binding RelativeSource="{RelativeSource AncestorType=UserControl}"
Path="DataContext.SelectedLanguage"></Binding>
</MultiBinding>
</Button.Content>
<i:Interaction.Behaviors>
<AuthInfrastructure:ControlBehavior x:Name="btnCalibrationSetSave"
VMBounded="CalibrationSetSave" ModuleName="Calibration" />
</i:Interaction.Behaviors>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
<!--…………………………………->
<!--Calibration Set Control-->
<Grid Visibility="{Binding Path=CalibrationSetControl}" HorizontalAlignment="Left" Width="762">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Local:CalibrationSet
Grid.Row="0"
Grid.Column="0"
DataContext="{Binding CalibrationSetViewModelContext,Mode=TwoWay}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto">
</Local:CalibrationSet>
</Grid>
<!--End Calibration Set Control-->
</Grid>
</UserControl>
Matching C# code:
// CalibratonSetListViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using DataStructures;
using Framework;
using Method.Component;
using Method.Control.Calibration.Interface;
using Microsoft.Practices.Prism.Regions;
using EventAggregation;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.ServiceLocation;
using ViewModel.Base;
using Microsoft.Practices.Prism;
using CustomMessageBox;
using Chromatogram.DataDisplay.Control;
namespace Method.Control
{
/// <summary>
/// Set or Get CalibrationSetViewModelContext
/// </summary>
public class CalibrationSetListViewModel : ViewModelBase
{
#region Variables
//………………………………
/// <summary>
/// Save Cal Button Visibility
/// </summary>
private Visibility m_SaveCalButtonVisibility;
//………………………………
#endregion
#region Properties
//………………………………
/// <summary>
/// Set or Get Save Cal Button Visibility
/// </summary>
public Visibility SaveCalButtonVisibility
{
get
{
return m_SaveCalButtonVisibility;
}
set
{
m_SaveCalButtonVisibility = value;
OnPropertyChanged(() => SaveCalButtonVisibility);
}
}
//………………………………
#endregion
#region Constructor
/// <summary>
/// Initializes new instance of MethodListViewModel
/// </summary>
/// <param name="methodId">MethodId</param>
/// <param name="peakDataProvider">PeakDataProvider</param>
public CalibrationSetListViewModel(int methodId, IPeakDataProvider peakDataProvider)
{
try
{
m_DataDisplayOfflineViewModel = new DataDisplayOfflineViewModel(true); // gain access to member functions
m_MethodId = methodId;
m_PeakDataProvider = peakDataProvider;
m_CalibrationSetListVisibility = Visibility.Visible;
m_CreateButtonVisibility = Visibility.Collapsed;
m_SaveCalButtonVisibility = Visibility.Collapsed;
GetCalibrationsList();
CreateCalibrationClick = new RelayCommand(parm => this.CreateCalibration());
DeleteCalibrationClick = new RelayCommand(this.DeleteCalibration);
SaveCalibrationClick = new RelayCommand(this.SaveCalibration);
CalibrationDetailsClick = new RelayCommand(this.CalibrationDetails);
CalibrationResultClick = new RelayCommand(this.CalibrationResult);
//Publish menu clicked event
m_EventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
MenuHomePage menuHomePage = MenuHomePage.CalibrationSet;
m_EventAggregator.GetEvent<ToolBarChange>().Publish(menuHomePage);
SetCalibrationVisibility();
//Subscribe CreateNewCalibration method
m_CreateNewCalibration = m_EventAggregator.GetEvent<ToolBarCreateNewCalibrationEvent>();
m_CreateNewCalibrationToken = m_CreateNewCalibration.Subscribe(createNewCalibration);
}
catch (Exception)
{
throw;
}
}
#endregion
#region Public Methods
//………………………………
#endregion
#region Public Methods
//………………………………
#endregion
#region Private Methods
/// <summary>
/// Create New CalibrationSet
/// </summary>
/// <returns></returns>
private Entities.CalibrationSet CreateNewCalibrationSet()
{
Entities.CalibrationSet newCalibrationSet = new Entities.CalibrationSet();
newCalibrationSet.CalibrationSetId = 0;
newCalibrationSet.CalibrationSetNumber = 1;
newCalibrationSet.AmountUnits = 2;
return newCalibrationSet;
}
//………………………………
#endregion
}
}
Assuming your CalibrationSetList binds to a CalibrationSetListViewModel (which might not, it's hard to tell) the problem would be different DataContexts between the UserControl (which would be the CalibationSetListViewModel) and
a cell in the grid (which would be an individual item in the collection that the grid is bound to).
To bind these properties (which are by default bound to properties of the individual items of the collection) to the top-level ViewModel, use:
{Binding RelativeSource={RelativeSource AncestorType=DataGrid},
Path=DataContext.SaveCalButtonVisibility }
Hope that helps
I am trying to make a cryptogram puzzle for Windows 8 Phone.
.net framework is 4.5
I am encountering this following error: 'System.Windows.Controls.Grid' does not contain a definition for 'setRow' at Grid.setRow(txt, x); I want to create textboxes dynamically, without using XAML...
To the best of my knowledge, Windows.Controls.Grid has a static method Grid.setRow(UIelement, int)..
Here is MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using System.Windows.Resources;
using System.IO;
namespace CryptogramPuzzle
{
public partial class MainPage : PhoneApplicationPage
{
List<string> quotes;
List<TextBox> tb;
int length = 0;
int width;
int height;
// Constructor
public MainPage()
{
InitializeComponent();
Random r = new Random();
string encodedStr;
InitializeComponent();
getQuotes();
int rInt = r.Next(0, quotes.Count()); //generates random index for a quote selection
encodedStr = Encryption.encode(quotes[rInt]);
length = encodedStr.Length;
createTxtBox(0, 0);
}
/// <summary>
/// Loads quotes from the text file
/// </summary>
public void getQuotes()
{
quotes = new List<string>();
try
{
StreamResourceInfo sInfo = Application.GetResourceStream(new Uri("/CryptogramPuzzle;component/Resources/Puzzles.txt", UriKind.Relative));
StreamReader sr = new StreamReader(sInfo.Stream);//feeds the reader with the stream
string line;
while ((line = sr.ReadLine()) != null)
{
quotes.Add(line);
}
sr.Close();
// System.Console.WriteLine(quotes[0]);
}
catch (Exception e)
{
throw (e);
}
}
public void createTxtBox(int x, int y)
{
TextBox txt = new TextBox();
RowDefinition newRow = new RowDefinition();
newRow.Height = new GridLength(0, GridUnitType.Auto);
ContentPanel.RowDefinitions.Add(newRow);
txt.MinHeight = 10;
txt.MinHeight = 10;
ContentPanel.Children.Add(txt);
Grid.setRow(txt, x);
}
}
}
Here is my MainPage.xaml:
<phone:PhoneApplicationPage
x:Class="CryptogramPuzzle.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- LOCALIZATION NOTE:
To localize the displayed strings copy their values to appropriately named
keys in the app's neutral language resource file (AppResources.resx) then
replace the hard-coded text value between the attributes' quotation marks
with the binding clause whose path points to that string name.
For example:
Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}"
This binding points to the template's string resource named "ApplicationTitle".
Adding supported languages in the Project Properties tab will create a
new resx file per language that can carry the translated values of your
UI strings. The binding in these examples will cause the value of the
attributes to be drawn from the .resx file that matches the
CurrentUICulture of the app at run time.
-->
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
</Grid>
<!--Uncomment to see an alignment grid to help ensure your controls are
aligned on common boundaries. The image has a top margin of -32px to
account for the System Tray. Set this to 0 (or remove the margin altogether)
if the System Tray is hidden.
Before shipping remove this XAML and the image itself.-->
<!--<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0" Grid.RowSpan="2" IsHitTestVisible="False" />-->
</Grid>
Please help me to fix this error, getting pretty desperate!
Thank you.
If it's a standard framework method, I'm pretty sure standard Pascal-casing rules (the guidelines that MS follows at least) dictate it would be called SetRow and not setRow.
And indeed it is.
Using C#.Net 4.5, Visual Studio 2012 Ulti, WPF.
I've got some old win-forms code that i wanted to do in this new WPF app.
code is the following:
DataGridViewImageCell pNew = new DataGridViewImageCell();
ParetoGrid.Columns.Add(new DataGridViewImageColumn() { CellTemplate = pNew, FillWeight = 1, HeaderText = "pNew", Name = "pNew", Width = 30 });
ParetoGrid.Columns["pNew"].DisplayIndex = 18;
3 lines of code to add a column that can handle images. In WPF I've seen its a bit different. Do i need to add an "image column"? or does WPF columns support images? or is there another 3 liner solution that is simply different syntax?
Thanks for the help guys
See this answer:
Image Column in WPF DataGrid
<DataGridTemplateColumn Header="Image" Width="SizeToCells"
IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Image}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
To add a column in code after:
DataGridTextColumn textColumn1 = new DataGridTextColumn();
textColumn1.Header = "Your header";
textColumn1.Binding = new Binding("YourBindingField");
dg.Columns.Add(textColumn1);
Use DataGridTemplateColumn to add a custom column
See: How do I show image in wpf datagrid column programmatically?
Here is what I did.
Add a datatemplate in your datagrid with image control like this
<DataGridTemplateColumn Header="File Type" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Height="25" Width="50" Source="{Binding FileIcon}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
As you can see my I am binding Image with a property named "FileIcon" that is used in class Version like this
public class Version
{
public string FileIcon { get; set; }
}
Now only this you have to do is bind provide a path to "FileIcon" and update ItemSource of DataGrid like this
ObservableCollection<Version> items = new ObservableCollection<Version>();
items.Add(new Version()
{
FileIcon = "/AssemblyName;component/Images/eye.png",
});
YourDataGrid.ItemsSource = null;
YourDataGrid.ItemsSource = items;
Here is MainWindow.xaml's code just simple for better understanding
`
<Window x:Class="Pic_in_Datagrid.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Pic_in_Datagrid"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="dt1" ColumnWidth="*" AutoGenerateColumns="False">
</DataGrid>
</Grid>
</Window>
After it here is my MainWindow.xaml.cs's code for image or text for adding in datadrid dynamically...
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
namespace Pic_in_Datagrid
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public StudentData stu_data { get; set; }
public MainWindow()
{
InitializeComponent();
stu_data = new StudentData();
List<StudentData> stu = new List<StudentData>();
stu.Add(new StudentData() { image = toBitmap(File.ReadAllBytes(#"D:\1.jpg")), stu_name = "abc" });
stu.Add(new StudentData() { image = toBitmap(File.ReadAllBytes(#"D:\1.jpg")), stu_name = "def" });
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(System.Windows.Controls.Image));
Binding bind = new System.Windows.Data.Binding("image");//please keep "image" name as you have set in your class data member name
factory.SetValue(System.Windows.Controls.Image.SourceProperty, bind);
DataTemplate cellTemplate = new DataTemplate() { VisualTree = factory };
DataGridTemplateColumn imgCol = new DataGridTemplateColumn()
{
Header = "image", //this is upto you whatever you want to keep, this will be shown on column to represent the data for helping the user...
CellTemplate = cellTemplate
};
dt1.Columns.Add(imgCol);
dt1.Columns.Add(new DataGridTextColumn()
{
Header = "student name",
Binding = new Binding("stu_name") //please keep "stu_name" as you have set in class datamember name
});
dt1.ItemsSource = stu;
}
public static BitmapImage toBitmap(Byte[] value)
{
if (value != null && value is byte[])
{
byte[] ByteArray = value as byte[];
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = new MemoryStream(ByteArray);
bmp.EndInit();
return bmp;
}
return null;
}
}
public class StudentData
{
public BitmapImage image { get; set; }
public string stu_name { get; set; }
}
}
The above all code is taken from different resources... Thanks to them who developed and shared these codes...
You may try add Image to DataGridTextColumn via pattern bellow. You may sorting and copy to clipboard works well. Use your converter, or binding to your property.
<DataGridTextColumn Header="Level" IsReadOnly="True" Binding="{Binding Level,Converter={StaticResource LogLevelStringConverter}}" >
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<Grid Background="{TemplateBinding Background}" >
<ContentPresenter VerticalAlignment="Center" Margin="20,0,0,0" HorizontalAlignment="Left" />
<Image Grid.Column="0" Width="18" Height="18" Source="{Binding Level,Converter={StaticResource LogLevelIconConverter}}" HorizontalAlignment="Left" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>