I am trying to trim the selected value of a silverlight custom control combobox. I have found that using the IValueConverter class should be the way to go. So I create this in my library
public class StringTrimmer : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.ToString().Trim();
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
this is the xaml for the combobox
<UserControl x:Class="SilverlightControlLibrary.SilverlightComboBoxControl"
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"
mc:Ignorable="d" Height="25" Width="122">
<ComboBox Height="23" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120"
Margin="0,0,0,0" Name="ModuleIDFilterCB"
ItemsSource="{Binding Path=Screen.LicenseModuleIDs, Mode=TwoWay}"
DisplayMemberPath="LicenseModuleName"
SelectedItem="{Binding Screen.bufferProp, Converter={StaticResource StringTrimmer},Mode=TwoWay}"
/>
</UserControl>
Except that the resource "StringTrimmer" for the SelectedItem can't be resolved. I tried adding this reference to the xaml and it still didnt work.
xmlns:c="clr-namespace:SilverlightControlLibrary"
EDIT: I also tried this
xmlns:custom="clr-namespace:SilverlightControlLibrary"
along with
SelectedItem="{Binding Screen.bufferProp, Converter= {StaticResource custom:StringTrimmer}, Mode=TwoWay}"
to no avail..
This http://msdn.microsoft.com/en-us/library/cc189061%28v=vs.95%29.aspx is what microsof has to say about XAML namespaces
and this http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convert.aspx is for the IValueConverter
Where am I going wrong?
You have to add static resource (UserControl.Resources section) to reference your converter e.g.:
<UserControl
x:Class="SilverlightControlLibrary.SilverlightComboBoxControl"
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"
mc:Ignorable="d"
Height="25"
Width="122"
xmlns:custom="clr-namespace:SilverlightControlLibrary">
<UserControl.Resources>
<custom:StringTrimmer x:Key="StringTrimmer" />
</UserControl.Resources>
<ComboBox Height="23"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="120"
Margin="0,0,0,0"
Name="ModuleIDFilterCB"
ItemsSource="{Binding Path=Screen.LicenseModuleIDs, Mode=TwoWay}"
DisplayMemberPath="LicenseModuleName"
SelectedItem="{Binding Screen.bufferProp, Converter={StaticResource StringTrimmer}, Mode=TwoWay}" />
</UserControl>
For XAML reference you can use any name in x:Key attribute, not only "StringTrimmer".
Related
I am relatively new to WPF and keep trying out little tests to improve my Knowledge. I am currently trying to utilise a Combobox to select an item and based upon the selection, change the color of the MainForm background utilising an IValueConverter as below:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value != null)
{
if (value.ToString() == "Male")
{
return new SolidColorBrush(Color.FromArgb(255, 27, 161, 226));
}
else
{
return new SolidColorBrush(Color.FromArgb(255, 216, 0, 115));
}
}
return null;
}
My problem is that the value is returning “System.Windows.Controls.ComboBoxItem: Female”
Or System.Windows.Controls.ComboBoxItem: Male.
What is the correct way to implement this comparison?
My full MainWindow Xaml is:
<Window x:Class="MVVM.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:MVVM"
xmlns:m="clr-namespace:MVVM.Models"
xmlns:vm="clr-namespace:MVVM.ViewModels"
xmlns:converters="clr-namespace:MVVM.ViewModels.Converters"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<m:Person x:Key="person"/>
<converters:BackgroundConverter x:Key="converter"/>
<vm:ViewModelBase x:Key="viewModel"/>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource person}}"
Background="{Binding Gender, Converter={StaticResource converter}}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox Text="{Binding Name, Mode=TwoWay}"/>
<TextBox Text="{Binding LastName, Mode=TwoWay}"/>
<TextBlock Text="{Binding FullName}" FontSize="20"/>
<ComboBox SelectedValue="{Binding Gender, Mode=TwoWay}">
<ComboBoxItem>Male</ComboBoxItem>
<ComboBoxItem>Female</ComboBoxItem>
</ComboBox>
<Button Content="Simple Command" Command="{Binding SimpleCommand, Source={StaticResource viewModel}}"/>
</StackPanel>
</Grid>
Thank you for your assistance.
you can add Strings into ComboBox. ComboBoxItems will be created behind the scenes:
<ComboBox SelectedValue="{Binding Gender, Mode=TwoWay}">
<sys:String>Male</sys:String>
<sys:String>Female</sys:String>
</ComboBox>
where sys in a namespace declaration:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Here is the enum:
public enum BarcodeType
{ AZTEC, CODABAR, CODE128, CODE93, CODE39, DATA_MATRIX, EAN13, EAN8, ITF, MAXICODE, PDF417, QRCODE, RSS14, RSSEXPANDED, UPCA, UPCE, UPC_EAN_EXTENSION }
And I bind the enum to the ComboBox like this:
<Page x:Class="KongGamLung.ToolProperty.BarCodeProperty"
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:KongGamLung.ToolProperty"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Model="clr-namespace:KongGamLung.Models"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="BarCodeProperty">
<Page.Resources>
<ObjectDataProvider x:Key="dataFromEnum" MethodName="GetValues"
ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="Model:BarcodeModel+BarcodeType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<local:BarcodeTypeConverter x:Key="BarcodeTypeConverter"/>
</Page.Resources>
<ComboBox x:Name="BarcodeTypeCB" ItemsSource="{Binding Source={StaticResource dataFromEnum},Converter={StaticResource BarcodeTypeConverter}}">
</ComboBox>
</Page>
And here is code-behind:
public class BarcodeTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Enum.GetName(value.GetType(), value).ToString().Replace("_", " ");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The code works well while without the code of the IValueConverter.
I use the IValueConverter for I want to replace the character of '_' in enum to ' ' to make it looks better.
I code the IValueConverter as what https://social.msdn.microsoft.com/Forums/vstudio/en-US/43db6b07-f886-4214-8076-5a5ec2360616/valueconverter-that-converts-an-enum-value-to-its-corresponding-string-value?forum=wpf said. But finally, it throws a System.ArgumentException error.
How can I solve it? Would you please help me? Thank you.
Don't use a converter on ItemsSource, it's changes the type of data that you're binding to. If you need to change the appearance of the enum then specify an ItemTemplate instead and use your converter there:
<ComboBox ItemsSource="{Binding Source={StaticResource dataFromEnum}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=., Converter={StaticResource BarcodeTypeConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Personally I'd bind to an intermediate view model class instead that contains both the enum and the text, that makes it much easier down the track to support things like localization (i.e. multiple languages at runtime).
I wanna make a combo box which likes the photoshop to show all the fonts in computer and display it.
I should display the font name, the sample of the font, so I have to rewrite the style of the items.
I wrote the code as this:
<ItemsControl Grid.Column="1" Margin="10,10,0,10">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<ComboBox></ComboBox>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
But visual studio reports an error:
How can I solve it and custom a combo box by my self? Thank you.
A simple sample. Edited according to owner's comment.
XAML
<Window x:Class="WpfApp1.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:WpfApp1"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ComboBox Width="200" VerticalAlignment="Center"
HorizontalContentAlignment="Stretch"
ItemsSource="{x:Static Fonts.SystemFontFamilies}">
<ComboBox.Resources>
<local:GetFamilyName x:Key="getName"/>
</ComboBox.Resources>
<ComboBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock Text="{Binding Converter={StaticResource getName}}"/>
<TextBlock Text="Sample" TextAlignment="Right"
FontFamily="{Binding}"/>
</DockPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>
Convertor Code
namespace WpfApp1
{
public class GetName : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value as FontFamily)?.FamilyNames.Values.First();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
Each item of my Employee's list has Post property. This property is Int64 type. Also, I have some ObservableDictionary<Int64,String> as static property. Each Employe must display the String value by its key.
DataTemplate for Employe item (I deleted the superfluous):
<DataTemplate x:Key="tmpEmploye">
<Border BorderThickness="3" BorderBrush="Gray" CornerRadius="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=Post}"/>
</StackPanel>
</Border>
</DataTemplate>
But this code displayed the Int64 value, not the String. String for getting static dictionary:
"{Binding Source={x:Static app:Program.Data}, Path=Posts}"
I know how solve it problem for ComboBox, but I don't know for TextBlock. For ComboBox I wrote it (it is works fine):
<ComboBox x:Name="cboPost" x:FieldModifier="public" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Margin="2" Grid.ColumnSpan="2"
ItemsSource="{Binding Source={x:Static app:Program.Data}, Path=Posts}" DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding Path=Post, Mode=TwoWay}">
</ComboBox>
But how can I solve it for TextBlock?
mmmmm, I'm sure I have developed something for this scenario before but I can't remember or find anything related!
IMO you can use a converter, so you pass your Post (Int64) to the converter and it returns the string value from the dictionary, although it must be a better solution.
[ValueConversion(typeof(Int64), typeof(string))]
public class PostToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// validation code, etc
return (from p in YourStaticDictionary where p.Key == Convert.ToInt64(value) select p.Value).FirstOrDefault();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
}
}
XAML:
<Window ...
xmlns:l="clr-namespace:YourConverterNamespace"
...>
<Window.Resources>
<l:PostToStringConverter x:Key="converter" />
</Window.Resources>
<Grid>
<TextBlock Text="{Binding Post, Converter={StaticResource converter}}" />
</Grid>
</Window>
I have a numeric value that I wish to be converted to a more user-friendly string format when it's displayed. I already have an IValueConverter called FlightLevelConverter that I'm using to do this for a normal TextBlock UI item where it works fine.
I now wish to apply the converter to a ComboBox of altitude choices, but I can't get it to work.
This is the relevant part of the XAML I'm using for the ComboBox:
<UserControl.Resources>
<status:FlightLevelConverter x:Key="FlightLevelConverter"/>
</UserControl.Resources>
...
<ComboBox x:Name="AltitudeCombo" Grid.Row="0" Grid.Column="3" Width="100">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource FlightLevelConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
It displays the un-converted numeric values, not the nice string values. I get no errors and if I set a breakpoint in the converter it doesn't get hit, showing that the converter is never called.
I've spent all morning trawling the Internet in general and StackOverflow in particular to try to discover what I'm doing wrong, but haven't found out anything useful.
Why is my converter not being called? What am I doing wrong?
How do you add the items to the ComboBox?
You should set the ItemsSource property to a collection of numeric values, e.g.
List<double> values = new List<double>();
values.Add(2.1);
values.Add(3.2);
values.Add(4.3);
values.Add(5.4);
AltitudeCombo.ItemsSource = values;
If you add ComboBoxItems like this
AltitudeCombo.Items.Add(new ComboBoxItem() { Content = 1.4 });
the ItemTemplate and hence the binding with its converter won't be applied.
Here is a short working sample. You can compare code...
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:bys="clr-namespace:WpfApplication1"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<bys:MyList x:Key="lst"/>
<bys:MyConverter x:Key="myConverter"/>
</Grid.Resources>
<ComboBox ItemsSource="{StaticResource lst}" SelectedIndex="0">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource myConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox >
</Grid>
</Window>
C#:
public class MyList : List<int> {
public MyList() {
AddRange(new[] { 1, 2, 3, 4, 5, 6 });
}
}
public class MyConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return String.Format("<<{0}>>", value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
ComboBox.ItemTemplate is not applicable to the main part of the ComboBox if ComboBox.IsEditable == true. It works for dropdown list entries only. Try to set ComboBox.IsEditable == false. It might help.