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";
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
Don't ask why, but I have to create a WPF Listview in the business logic part of the code (the reason is I'm dealing with legacy code, thats why.)
Anyway, so far everything works, however, I want to add a checkbox column called "PermutationItem", where only some of the items have the corresponding property. In case a property doesn't have the property (= has the wrong type), I want to set the IsEnabled flag of the Checkbox to false automatically.
This is the code so far:
ListView lvPlatformList = new ListView()
{
Name = "MyListView"
};
lvPlatformList.BorderThickness = new Thickness(1);
lvPlatformList.Margin = new Thickness(0, HeightMargin, 25, HeightMargin);
var gridView = new GridView();
DataTemplate dtEnabled = new DataTemplate() { DataType = typeof(CheckBox) };
FrameworkElementFactory cbfEnabled = new FrameworkElementFactory(typeof(CheckBox));
cbfEnabled.SetBinding(CheckBox.IsCheckedProperty, new Binding("IsEnabled"));
dtEnabled.VisualTree = cbfEnabled;
gridView.Columns.Add(new GridViewColumn()
{
Header = "Enabled",
CellTemplate = dtEnabled
});
gridView.Columns.Add(new GridViewColumn()
{
Header = "Equipment Name",
DisplayMemberBinding = new Binding("Equipment.Name")
{
FallbackValue = "Empty Platform"
},
});
DataTemplate dtPermutationItem = new DataTemplate() { DataType = typeof(CheckBox) };
FrameworkElementFactory cbfPermutationItem = new FrameworkElementFactory(typeof(CheckBox));
cbfPermutationItem.SetBinding(CheckBox.IsCheckedProperty, new Binding("Equipment.IsPermutationItem.Value")
{
FallbackValue = false
});
cbfPermutationItem.SetBinding(CheckBox.IsEnabledProperty, /* What comes here?? */);
dtPermutationItem.VisualTree = cbfPermutationItem;
gridView.Columns.Add(new GridViewColumn()
{
Header = "PermutationItem",
CellTemplate = dtPermutationItem
});
lvPlatformList.View = gridView;
I know how I would solve this in XAML, but how can it be done here in the code?
I was able to solve it using a separate Binding with a new IValueConverter class. Instead of IsEnabled I used the Visibility property, but the same procedure is applicable to any property.
Here is the new Bindig:
cbfPermutationItem.SetBinding(CheckBox.VisibilityProperty, new Binding("Equipment")
{
Converter = new DataTypeToVisibilityConverter(),
ConverterParameter = typeof(MyTargetClass)
});
And here is the corresponding Visibility Converter:
public class DataTypeToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return Visibility.Hidden;
Type compareType = parameter as Type;
Type valueType = value.GetType();
if (compareType.IsAssignableFrom(valueType))
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can obviously put whatever you want into the converter, however a thing to note here is that IsAssignableFrom() function was needed in my case to work with inherited types.
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 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;
}
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.