Passing values to IValueConverter - c#

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.

Related

ValueConverter method is hit but not showing on UI

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();
}
}

Using a IConverter to deal with {NewItemPlaceholder} in WPF / XAML / MVVM

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;
}
}

How to disable particular cell in Wpf datagrid on Radiobutton checked event

I want to disable particular cell from Datagrid in wpf on the Radio button checked event. I got the row index and column index of the cell which I need to disable.
CS :
public class InverseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool _val = (bool)value;
return !_val;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool _val = (bool)value;
return !_val;
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
public List<object> Stuff
{
get { return new List<object> { 1, 2, 3 }; }
}
XAML :
<Window>
<Grid>
<Grid.Resources>
<local:InverseConverter x:Key="converter" />
</Grid.Resources>
<DataGrid ItemsSource="{Binding Stuff}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<RadioButton IsChecked="{Binding Path=IsEnabled, RelativeSource={RelativeSource AncestorType=ContentPresenter}, Converter={StaticResource converter}, Mode=OneWayToSource}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>

How to Convert Image Using Ivalueconverter and Bind it in Listview

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

How to get datacontext from stackpanel

I have:
<StackPanel DataContext="{Binding Path =MyContext}">
<TextBox Text="{Binding Path =Content}" x:Name="tbName" IsReadOnly="False">
</TextBox>
<CheckBox x:Name="cboxName" Content="Is null ?" Click="cboxName_Click" IsChecked="{Binding Path=THIS, Converter={StaticResource MyContextToBoolConverter}}">
</CheckBox>
</StackPanel>
public class MyContextToBoolConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value!=null);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return parameter;
}
}
I just only want to get DataContext to checkbox from StackPanel.
You should replace THIS with . or completely remove the Path from the Binding. This will create a binding directly to the DataContext.
IsChecked="{Binding Converter={StaticResource MyContextToBoolConverter}}"
Or try this -
<StackPanel x:Name="StackPanel" DataContext="{Binding Path =MyContext}">
<TextBox Text="{Binding Path =Content}" x:Name="tbName" IsReadOnly="False" />
<CheckBox x:Name="cboxName" Content="Is null ?"
Click="cboxName_Click"
IsChecked="{Binding ElementName=StackPanel, Path=DataContext, Converter={StaticResource MyContextToBoolConverter}}">
</CheckBox>
</StackPanel>

Categories