Hi I'm trying to create a converter to Convert my images in a database ,datatype"Varbinary(Max)"
to populate my DataGrid in WPF but i have 2 error i show you the Converter:
public class BinaryToImageConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Binary binaryData = value;// here there is the first error .How convert BinaryData to Object??
if (binaryData == null) {
return null;
}
byte[] buffer = binaryData.ToArray();
if (buffer.Length == 0) {
return null;
}
BitmapImage res = new BitmapImage();
res.BeginInit();
res.StreamSource = new System.IO.MemoryStream(buffer);
res.EndInit();
return res;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
BitmapImage source = value;//How convert Bitmap to Object?
if (source == null) {
return null;
}
if ((source.StreamSource != null) && source.StreamSource.Length > 0) {
return GetBytesFromStream(source.StreamSource);
}
return null;
}
private Binary GetBytesFromStream(System.IO.Stream stream)
{
stream.Position = 0;
byte[] res = new byte[stream.Length + 1];
using (System.IO.BinaryReader reader = new System.IO.BinaryReader(stream)) {
reader.Read(res, 0, (int)stream.Length);
}
return new Binary(res);
}
}
Cab you advice me if it is right or there is a better way to do this?
Thanks for your help.
Have a good Day
If the value parameter does contain an object of the type BinaryData then you can just typecast it:
Binary binaryData = (Binary)value;
or
Binary binaryData = value as Binary;
It's probably better to do an is-null check on the value parameter before casting, rather than doing it after the cast, as you do now.
Related
I'm having a problem binding a dictionary in a combobox as part of a column in a DataGrid.
The dictionary changes on each line so I choose to use a Converter that changes from the value of another data column. The combo presents correctly the values of the dictionary, but once an item is selected, the dictionary key is not applied (takes de value).
I show the code used and omit non-transcendent parts:
DataGridTemplateColumndatacol = new DataGridTemplateColumn();
datacol.Header = "Col1";
datacol.CanUserReorder = true;
datacol.SortMemberPath = "tablecol1";
//Part no edit
FrameworkElementFactory factory1 = new FrameworkElementFactory(typeof(TextBlock));
Binding bind1 = new Binding("tablecol1");
bind.Mode = BindingMode.OneWay;
factory1.SetValue(TextBlock.TextProperty, bind1);
DataTemplate cellTemplate1 = new DataTemplate();
cellTemplate1.VisualTree = factory1;
((DataGridTemplateColumn)datacol).CellTemplate = cellTemplate1;
//Part editable
FrameworkElementFactory factory2 = new FrameworkElementFactory(typeof(ComboBox));
Binding bind2 = new Binding("tablecol1");
bind2.Mode = BindingMode.TwoWay;
bind2.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus;
Binding bindlist = new Binding(".");
bindlist.Mode = BindingMode.Default;
//Class converter
bindlist.Converter = new CustomDictionaryRowConverter();
factory2.SetValue(ComboBox.SelectedValuePathProperty, "Key");
factory2.SetValue(ComboBox.DisplayMemberPathProperty, "Value");
factory2.SetValue(ComboBox.ItemsSourceProperty, bindlist);
DataTemplate cellTemplate2 = new DataTemplate();
cellTemplate2.VisualTree = factory2;
((DataGridTemplateColumn)datacol).CellEditingTemplate = cellTemplate2;
The converter class returns a dictionary, I simplify the code:
public class CustomDictionaryRowConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
return new Dictionary<string, string>(
{ "key1", "Valor1"},
{ "key2", "Valor2"},
{ "key3", "Valor3"}
);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
The combo has as bind the data column "tablecol1":
Binding bind2 = new Binding("tablecol1");
I hope you can help me. Thanks
I create columns in an data grid via code-behind like this:
DataGridTextColumn dgtc1 = new DataGridTextColumn();
dgtc1.Header = "Feldname";
dgtc1.Binding = new Binding("FieldName");
dataGrid.Columns.Add(dgtc1);
DataGridTextColumn dgtc2 = new DataGridTextColumn();
dgtc2.Header = "Masterwert";
dgtc2.Binding = new Binding("MasterValue");
dataGrid.Columns.Add(dgtc2);
int counter = 0;
foreach (DBManager database in databases)
{
if (!database.IsMaster)
{
DataGridTextColumn dgtc = new DataGridTextColumn();
dgtc.Header = database.DisplayName;
dgtc.Binding = new Binding("LocationValues[" + counter + "]");
dataGrid.Columns.Add(dgtc);
counter++;
}
}
I want the cells to change their background color to a specific value depending on the items property "DeltaValues".
if(DeltaValues[i] == true)
//Change the background color to x
else
//Do nothing
Is there a Binding I could set for the columns from code-behind to achieve this behaviour?
Any ideas?
I not tested codes. I'm not sure DataGridCell.ContentProperty is correct property.:
if (!database.IsMaster)
{
DataGridTextColumn dgtc = new DataGridTextColumn();
dgtc.Header = database.DisplayName;
dgtc.Binding = new Binding("LocationValues[" + counter + "]");
Setter setter = new Setter();
setter.Property = Control.BackgroundProperty;
setter.Value = Brushes.Red;
Trigger trigger = new Trigger();
trigger.Property = DataGridCell.ContentProperty;
trigger.Value = true;
trigger.Setters.Add(setter);
dgtc.CellStyle.Triggers.Add(trigger);
dataGrid.Columns.Add(dgtc);
counter++;
}
or version with converter.
{
if (!database.IsMaster)
{
DataGridTextColumn dgtc = new DataGridTextColumn();
dgtc.Header = database.DisplayName;
dgtc.Binding = new Binding("LocationValues[" + counter + "]");
Converter converter = new Converter();
Binding binding = new Binding(DeltaValues[i]);
binding.Converter = converter;
dgtc.CellStyle.Setters.Add(new Setter(Control.BackgroundProperty, binding));
dataGrid.Columns.Add(dgtc);
counter++;
}
return this;
}
and very simple converter class:
public class Converter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((bool)value) return Brushes.Red;
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
new throw Exception();
}
}
I'm trying to format and get the image, text etc.. to give a good look and feel.
The XML is something like this:
xmlns:content="http://purl.org/rss/1.0/modules/content/"
And the content is:
<content:encoded>
<![CDATA[
<p><a href="http://i2.wp.com/geekytheory.com/wp-content/uploads/2014/03/Screen-Shot- 2013-11-11-at-11.38.50.png"><img class="size-full wp-image-7447 aligncenter" alt="Screen Shot 2013-11-11 at 11.38.50" src="http://i2.wp.com/geekytheory.com/wp- content/uploads/2014/03/Screen-Shot-2013-11-11-at-11.38.5
]]>
<![CDATA[
0.png?resize=788%2C644" data-recalc-dims="1" /></a></p> <p style="text-align: justify">
</p>]]>
< /content:encoded>
At first what I will get is the image or example: he is in content:encoded/p/a/img/src
the code that I try is:
private ObservableCollection<RssItem> ParseXmlString(string xmlString)
{
XDocument xmlDoc = XDocument.Parse(xmlString);
XNamespace xmns = #"http://purl.org/dc/elements/1.1/";
XNamespace xmnsContent = #"http://purl.org/rss/1.0/modules/content/";
var itemsList = xmlDoc.Descendants("item").Select(i => new RssItem()
{
Author = i.Element(xmns + "creator").Value,
Title = i.Element("title").Value,
Description = i.Element("description").Value,
Content = i.Element(xmnsContent + "encoded").Value,
Image = i.Element(xmnsContent + "encoded").XPathSelectElement("//p//a//img[#src]").Value,
Date = DateTime.Parse(i.Element("pubDate").Value)
}).ToList();
return new ObservableCollection<RssItem>(itemsList);
}
The Content = i.Element(xmnsContent + "encoded").Value give me all the content without formatting something like this:
And for exctract the image or some other element from the CData I get a error.
Image = i.Element(xmnsContent + "encoded").XPathSelectElement("//p//a//img[#src]").Value is giving error.
I tried this way too, but giving the same error.
Image = i.Element(xmnsContent+"encoded").Element("p").Element("a").Element("img").Attribute("src").Value
Thanks for all and greetings!!
Finally with a FlowDocumentScrollViewer an the XmlToXamlConverter I get the solution:
<FlowDocumentScrollViewer
Document="{Binding Content, Converter={StaticResource HtmlToFlowDocConverter}}"/>
After we need to add a Converter like:
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
var xaml = HtmlToXamlConverter.ConvertHtmlToXaml((string)value, true);
var flowDocument = XamlReader.Parse(xaml);
if (flowDocument is FlowDocument)
SubscribeToAllHyperlinks((FlowDocument)flowDocument);
return flowDocument;
}
private void SubscribeToAllHyperlinks(FlowDocument flowDocument)
{
var hyperlinks = GetVisuals(flowDocument).OfType<Hyperlink>();
foreach (var link in hyperlinks)
link.RequestNavigate += LinkRequestNavigate;
}
private static IEnumerable<DependencyObject> GetVisuals(DependencyObject root)
{
foreach (var child in
LogicalTreeHelper.GetChildren(root).OfType<DependencyObject>())
{
yield return child;
foreach (var descendants in GetVisuals(child))
yield return descendants;
}
}
private void LinkRequestNavigate(object sender,
System.Windows.Navigation.RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
Finally we will add the XmlToXamlConverter from here and another from here.
Another helpfull article for me was this.
Greetings!
I'm using Binding to Image.SourceProperty from byte[] variable. At IValueConverter I check if value.Length > 0, if yes then I set source from it's value. Then I need to know, if it was set, so I can show or hide clear button. Image.Source always is not null. How can know, if it was set from byte[] array?
My code:
var bnd = new Binding
{
Mode = BindingMode.TwoWay,
Path = new PropertyPath("DataPath.Value"),
Converter = new ByteToImageConverter()
};
myImage.SetBinding(Image.SourceProperty, bnd);
public class ByteToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var val = value as byte[];
var bmp = new BitmapImage();
if (val.Length > 0) {
bmp.SetSource(new MemoryStream(val));
}
return bmp;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) {
return new byte[0];
}
var ms = new MemoryStream();
var bmp = new WriteableBitmap(value as BitmapSource);
bmp.SaveJpeg(ms, 150, 200, 0, 100);
return ms.ToArray();
}
}
Now I need code to check, if image source property is set:
// myImage.Source always != null even if there was no bmp.SetSource() call
var str = myImage.Source != null ? "Image is set" : "Image is empty";
something like that
if (((BitmapImage)myImage.Source).UriSource == null)
{
//Image is empty
}
or
var str = ((BitmapImage)myImage.Source).UriSource != null ? "Image is set" : "Image is empty";
I have a method that I call to create a link button. However the problem is that it passing the field name that the actual field to link button becasically giving me a dead link.
This is the method:
private static DataGridTemplateColumn CreateHyperlink(string fieldName)
{
DataGridTemplateColumn column = new DataGridTemplateColumn();
column.Header = "";
string link = #"http://www.amazon.com/gp/product/" + fieldName;
StringBuilder sb = new StringBuilder();
sb.Append("<DataTemplate ");
sb.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
sb.Append("xmlns:src='clr-namespace:Silverlight1.Classes;assembly=Silverlight1.Classes'>");
sb.Append("<HyperlinkButton ");
sb.Append("TargetName= '_blank' ");
sb.Append("Content = 'Link' ");
sb.Append("NavigateUri =" +"'"+ link +"'");
sb.Append(" />");
sb.Append("</DataTemplate>");
column.CellTemplate = (DataTemplate)XamlReader.Load(sb.ToString());
column.IsReadOnly = false;
return column;
}
Which is called by this
dgOrder.Columns.Add(CreateHyperlink("asin"));
Which is getting pulled from a WCF Silverlight enable data service.
How do I pass the content instead of field name?
You don't pass the content, you pass the field name but create a Binding. You will also need an implementation of a IValueConverter.
Lets start with an IValueConverter, you need something which take the string value of the "field" (by which I'm assuming you mean a Property of the objects bound to rows in the grid) and prefix it with #"http://www.amazon.com/gp/product/" to form a complete URL.
public class UrlPrefixConverter : IValueConverter
{
public string Prefix {get; set;}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
return new Uri(Prefix + value.ToString(), UriKind.Absolute);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Place an instance of this in the App.xaml:-
<Application.Resources>
<local:UrlPrefixConverter Prefix="http://www.amazon.com/gp/product/" x:Key="AmazonPrefixConverter" />
</Application.Resources>
Now your create method can look like this:-
private static DataGridTemplateColumn CreateHyperlink(string fieldName)
{
DataGridTemplateColumn column = new DataGridTemplateColumn();
column.Header = "";
string template = #"<DataTemplate
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" >
<HyperlinkButton TargetName=""_blank"" Content=""Link""
NavigateUri=""{{Binding {0}, Converter={{StaticResource AmazonPrefixConverter}}}}"" />
</DataTemplate>";
column.CellTemplate = (DataTemplate)XamlReader.Load(String.Format(template, fieldName));
column.IsReadOnly = false;
return column;
}