I a have list containing invoices. These invoices have a direction value represented by an int (incoming = 0, issued = 1). I want to differentiate these invoices by color in the list.
I tried to use ValueConverter, but when I populate the list with invoices, it's not working and background color stays default color, even though the ValueConvert method is hit when I place breakpoint in it and it revives all the objects from the list. If I replace the bounding to any color in the xaml file, it works and background changes to the specific color.
What am I missing here?
My xaml (only relevant code included):
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Views.InvoiceNumberPage"
xmlns:local="clr-namespace:MyApp.ViewModels"
xmlns:converters="clr-namespace:MyApp.Helpers">
<ContentPage.Resources>
<ResourceDictionary>
<converters:InvoiceDirectionColorConverter x:Key="InvoiceDirectionColorConverter"/>
</ResourceDictionary>
<ListView Grid.Row="4" Grid.ColumnSpan="2" ItemsSource="{Binding FoundList}" Margin="20,0">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="{Binding Direction, Converter={StaticResource InvoiceDirectionColorConverter}}">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding InvoiceNumber}" Grid.Row="0" Grid.Column="0"/>
<Label Text="{Binding IssueDate, StringFormat='{0:yyyy.MM.dd}'}" Grid.Row="0" Grid.Column="1"/>
<Label Text="{Binding Company.Name}" Grid.Row="1" Grid.Column="0"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And my ValueConverter:
class InvoiceDirectionColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
SolidColorBrush brush = new SolidColorBrush();
int invoicedirection = (int)value;
if (invoicedirection != null && invoicedirection.Equals(0))
{
brush.Color = Color.Green;
}
else
{
brush.Color = Color.Yellow;
}
return brush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
As Jason mentioned in his comment, you should return a Color type instead of a Brush type.
class InvoiceDirectionColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int invoicedirection = (int)value;
if (invoicedirection != null && invoicedirection.Equals(0))
{
return Color.Green;
}
else
{
return Color.Yellow;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Related
Here is my DataTemplate:
<UserControl.Resources>
<converter:PlaceholderConverter x:Key="_placeholderConverter"/>
<!-- Data(Display)Template for data objects of x:Type Customer-->
<DataTemplate DataType="{x:Type model:Customer}">
<!-- Customer Properties will be vertically stacked -->
<ContentControl >
<StackPanel>
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding LastName}"/>
<TextBlock Text="{Binding Phone}"/>
</StackPanel>
</ContentControl>
</DataTemplate>
<UserControl.Resources>
And the two different 'container's:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0"
Content="Delete"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="75"
Command="{Binding DeleteCommand}"/>
<DataGrid Grid.Row="1"
ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer}"
AutoGenerateColumns="True"/>
<ListBox
Grid.Row="2"
ItemsSource="{Binding Customers, Mode=OneWay}"/>
</Grid>
And the app:
How to remove the {NewItemPlaceholder}? [Done, solution below].
How to prevent the binding error that mention "{NewItemPlaceholder}" when clicking in one of the empty rows in the table above intending on adding a new row (I can still add rows).
The errors:
...Cannot convert '{NewItemPlaceholder}' from type 'NamedObject' to type 'CustomerExample.Model.Customer'...
...ConvertBack cannot convert value '{NewItemPlaceholder}' (type 'NamedObject'). BindingExpression:Path=SelectedCustomer; DataItem='CustomerViewModel'...
I can write an IConverter implementation, but how to tie it in to the XAML?
thanks in advance :-)
Here is the implementation of the IConverter:
public class PlaceholderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value.ToString() == "{NewItemPlaceholder}")
return DependencyProperty.UnsetValue;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
and to bind to individual items, the XAML goes something like:
<TextBlock Text="{Binding Name, Converter={StaticResource PlaceholderConverter}}"/>
But I think I need to add it 'globally' to the data collection elements, not to where individual properties are being bound.
You don't need a Binding Converter. Instead, bind the ListBox to a CollectionViewSource that wraps the Custumers collection. The CollectionViewSource skips the NewItemPlaceholder element from the source collection.
<UserControl.Resources>
...
<CollectionViewSource x:Key="CustomersCVS" Source="{Binding Customers}"/>
</UserControl.Resources>
...
<ListBox ItemsSource="{Binding Source={StaticResource CustomersCVS}}"/>
You also don't need a Converter for the SelectedItem Binding. Just set the Binding's TargetNullValue property:
<DataGrid SelectedItem="{Binding SelectedCustomer,
TargetNullValue={x:Static CollectionView.NewItemPlaceholder}}" .../>
Even though the accepted answer is correct for the OP's question I needed a more general approach to prevent the error and still allow users to add rows. As I used this ValueConverter for many different object types I used reflection to determine the target type's constructor and just returned a new object of that type.
public class IgnoreNewItemPlaceHolderConverter : IValueConverter
{
private const string NewItemPlaceholderName = "{NewItemPlaceholder}";
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == DependencyProperty.UnsetValue)
return DependencyProperty.UnsetValue;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value.ToString() == NewItemPlaceholderName)
{
var ctors = targetType.GetConstructors();
// invoke the first public constructor with no parameters.
return ctors[0].Invoke(new object[] { });
}
return value;
}
}
I have xaml file where I put 2 TextBox where I can put login and password. After then Button "Login" should be visible. Here is my code:
TreeView.xaml file:
<UserControl x:Class="LayoutMVVM.Views.TreeView"
xmlns:local="clr-namespace:LayoutMVVM.Views"
xmlns:Treemodels="clr-namespace:LayoutMVVM.ViewModels" .../>
<UserControl.Resources>
<Treemodels:VBConverter x:Key="VBConverter" />
</UserControl.Resources>
<Grid>
....
<TextBox Grid.Row="2" Grid.Column="2" Text="{Binding Login, UpdateSourceTrigger=PropertyChanged}" Background="AliceBlue" />
<TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Background="AliceBlue" />
<Button Grid.Row="3" Grid.Column="3" Visibility="{Binding IsVerifyTrue, Converter={StaticResource VBConverter}}" Content="Login" />
</Grid>
TreeView.xaml.cs
namespace LayoutMVVM.Views
{
public partial class TreeView : UserControl
{
public TreeView()
{
InitializeComponent();
}
public TreeView _isVerifyTrue;
public TreeView IsVerifyTrue
{
get { return this; }
set
{
_isVerifyTrue = value;
OnPropertyChanged(() => IsVerifyTrue);
}
}
private void OnPropertyChanged(Func<object> p)
{
throw new NotImplementedException();
}
private string _login;
public string Login
{
get { return _login; }
set
{
_login = value;
IsVerifyTrue = this;
OnPropertyChanged(() => Login);
}
}
private string _password;
public string Password
{
get { return _password; }
set
{
_password = value;
IsVerifyTrue = this;
OnPropertyChanged(() => Password);
}
}
}
and seperate class for VBConverter.cs:
namespace LayoutMVVM.ViewModels
{
public class VBConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is TreeView)
{
var tv = value as TreeView;
bool result = !string.IsNullOrEmpty(tv.Login)
&& !string.IsNullOrEmpty(tv.Password);
return result? Visibility.Visible : Visibility.Hidden;
}
return Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
When I start app button is always visible and I'm not know what is wrong.
You'll need a MultiValueConverter for this. See below example :
XAML :
<Window x:Class="SOSample1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SOSample1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<local:VisibilityConverter x:Key="VisibilityConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="100" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Name="user" Height="100" Width="200" Text="{Binding Login, UpdateSourceTrigger=PropertyChanged}" Background="AliceBlue" />
<TextBox Grid.Row="1" Name="password" Height="100" Width="200" Text="{Binding Login, UpdateSourceTrigger=PropertyChanged}" Background="AliceBlue" />
<Button Grid.Row="2" Content="Login" Height="100" Width="200" >
<Button.Visibility>
<MultiBinding Converter="{StaticResource VisibilityConverter}" >
<Binding ElementName="user" Path="Text" />
<Binding ElementName="password" Path="Text" />
</MultiBinding>
</Button.Visibility>
</Button>
</Grid>
Converter :
public class VisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool result = false;
if (values != null)
{
foreach (var item in values)
{
result = (item as string).Length > 0;
if (!result) break;
}
}
return (Visibility)new BooleanToVisibilityConverter().Convert(result, targetType, parameter, culture);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
OUTPUT
I have converted Image to base64 string and saved it in SQLite database as public string ProfileImage { get; set; }
I want to bind image into a List view as I did binding Name and Address.
XAML
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,10,0,0" Grid.Column="0" HorizontalAlignment="Left">
<Image x:Name="proImg" Source="{Binding ProfileImage}" Stretch="UniformToFill" Height="79" Width="79"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Margin="5,0,0,0" Grid.Row="0" x:Name="NameTxt" TextWrapping="Wrap" Text="{Binding Name}" FontSize="32" Foreground="White" Style="{ThemeResource ListViewItemTextBlockStyle}"/>
<TextBlock Margin="5,0,0,0" Grid.Row="1" x:Name="PhoneTxt" TextWrapping="Wrap" Foreground="White" FontSize="20" Text="{Binding Address}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
Code I used to convert base64 String to Image in other Places
public static BitmapImage Base64StringToBitmap(string source)
{
var ims = new InMemoryRandomAccessStream();
var bytes = Convert.FromBase64String(source);
var dataWriter = new DataWriter(ims);
dataWriter.WriteBytes(bytes);
dataWriter.StoreAsync();
ims.Seek(0);
var img = new BitmapImage();
img.SetSource(ims);
return img;
}
Is it possible to bind image source similar way to this
Source="{Binding Base64StringToBitmap(ProfileImage)}"
You cannot call method in Xaml Binding like this. You need to convert it by implementing IValueConverter and then bind it. You should use a ValueConverter like this.
public class StringToBitmapConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value != null)
{
string source = value.ToString();
var ims = new InMemoryRandomAccessStream();
var bytes = Convert.FromBase64String(source);
var dataWriter = new DataWriter(ims);
dataWriter.WriteBytes(bytes);
dataWriter.StoreAsync();
ims.Seek(0);
var img = new BitmapImage();
img.SetSource(ims);
return img;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
and use this converter in Xaml like this
xmlns:MyConverter="using:Your converter namespace path"
<Page.Resources>
<MyConverter:StringToBitmapConverter x:Key="ImageShow"/>
</Page.Resources>
<Image x:Name="proImg" Source="{Binding ProfileImage,Converter={StaticResource ImageShow}}" Stretch="Fill" Height="60" Width="60"/>
You should add a XAML IValueConverter to bind the image in your scenario.Converter will do the conversion of Base64String to Bitmap Image.
Add a class with interface IValueConverter as like below.
public class PictureConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
{
return null;
}
string item = value.ToString();
BitmapImage objBitmapImage = new BitmapImage();
objBitmapImage = NewViewModel.Base64StringToBitmap(item);
return objBitmapImage;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Now define a key to this converter either in Resource dictionary or in Page
<Page.Resources>
<local:PictureConverter x:Key="PictureConverter"/>
</Page.Resources>
Then bind your key in XAML
<Image x:Name="proImg" Source="{Binding ProfileImage,Converter={StaticResource PictureConverter}}" Stretch="UniformToFill" Height="79" Width="79"/>
Hope now image is being displayed.
I have a ListView that has a Grid with two columns and many rows. Each row has a TextBlock in each column with each Text property binded to a value in ListView's ItemSource. I need to do some converting of the text in the second TextBlock depending on the value in the first TextBlock. How can I get the value of the first text box to the converter?
Here is what I have so far:
XAML:
<UserControl.Resources>
<local:ValueStringConverter x:Key="valueStringConverter" />
</UserControl.Resources>
<ListView Name="theListView" ItemsSource="{Binding ItemCollection}" SelectedItem="{Binding SelectedItem}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Grid.Row="1" >
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Key}" Grid.Column="0" Margin="0,0,10,0" />
<TextBlock Text="{Binding Path=Value, Converter={StaticResource valueStringConverter}}" TextWrapping="Wrap" Grid.Column="1" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code of ValueStringConverter:
public class ValueStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string name = (string)value;
name = name.Replace("$$", " ");
name = name.Replace("*", ", ");
name = name.Replace("##", ", ");
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can't pass more than one value to the "regular" value converter. You could go with IMultiValueConverter and define the binding as MultiBinding.
Or you can create a IValueConverter that takes the entire object in the DataContext, cast the object to its type, take the Value and Key and return the string you need.
On your second textblock define the binding as
<TextBlock Text="{Binding Converter={StaticResource valueStringConverter}"/>
And your converter as:
public class ValueStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
MyDataContextObjectType obj= (MyDataContextObjectType)value;
var name= obj.Name;
var key = obj.Key;
//here you have both Name and Key, build your string and return it
//if you don't know the type of object in the DataContext, you could get the Key and Name with reflection
name = name.Replace("$$", " ");
name = name.Replace("*", ", ");
name = name.Replace("##", ", ");
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Try multi-binding. You'll need an IMultiValueConverter:
public class MultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var key = (string)values[0];
var value = (string)values[1];
// replace with appropriate logic
var result = key + ": " + value;
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and slightly modified XAML:
<TextBlock Text="{Binding Path=Key}" Grid.Column="0" Margin="0,0,10,0" />
<TextBlock TextWrapping="Wrap" Grid.Column="1">
<TextBlock.Text>
<MultiBinding Converter={StaticResource valueStringConverter}>
<Binding Path="Key" />
<Binding Path="Value" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Bind to the instance, not the property (value in this case). Then you will have access to both Key and Value in the converter.
I want to Bind the VarBinary(Max) using Ivaluconverter But Problem is that I have a error which is
Error 1 The tag 'ImageDataConverter' does not exist in XML namespace
'clr-namespace:UI'. Line 7 Position 10. C:\Documents and
Settings\Muhammad Yaqoob\My Documents\Visual Studio
2008\Projects\BLL\UI\Pics.xaml 7 10 UI
I Retrieve Image like this
DataClasses1DataContext dt = new DataClasses1DataContext();
var query = from prod in dt.Students
where (prod.StudentID == 100)
select new
{
prod.LastName,
prod.StudentID,
prod.MyImage
};
this.listView1.ItemsSource = query;
Then i use the Ivalconverter to Convert the Image From VarBinary to the Image as
public class ImageDataConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#region IValueConverter Members
object IValueConverter.Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
object IValueConverter.ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
And my .Xmal file is like that
xmlns:local="clr-namespace:UI" /// i have problem at here can't find the essembly info or Resours file
Title="Pics" Height="408" Width="406" xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit" Loaded="Window_Loaded">
<Window.Resources>
<local:ImageDataConverter x:Key="imageConverter"/> // ImageDataConverter cant be locat at here
</Window.Resources>
<ListView Name="listView1" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" Height="263">
<ListView.ItemTemplate>
<DataTemplate>
<Border Margin="5" BorderThickness="1" BorderBrush="SlateGray" CornerRadius="4">
<Grid Margin="3">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"></TextBlock>
<TextBlock Grid.Row="1" Text="{Binding Path=ListPrice}"></TextBlock>
<Image Grid.Row="2" Source="{Binding Path=ThumbNailPhoto , Converter={StaticResource imageConverter}}"></Image>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
i cant know how to solve this problem the problem is that my resourse propertie of ImageDataconvert is not converting and also essembly is not found for the IN the UI project yes my project is in tree tier and my resourse sitting is in UI project