How can I binding data to ComboBox and rewrite items template? - wpf

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

Related

wpf Combobox and IValueConverter

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"

How can I binding an enum with IValueConverter?

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).

How can I add a resource to a silverlight custom control?

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".

Change DataTemplate to use depending on condition

I have 3 user controls
Control 1
Control 2
Control 3
I have a stack panel that contains an ItemsControl
<UserControl.Resources>
<DataTemplate x:Key="Template1">
<my:UserControl1 Height="117"/>
</DataTemplate>
<DataTemplate x:Key="Template2">
<my:UserControl3 Height="117"/>
</DataTemplate>
<DataTemplate x:Key="Template3">
<my:UserControl3 Height="117"/>
</DataTemplate>
</UserControl.Resources>
<StackPanel Name="stackPanel3" Orientation="Vertical" VerticalAlignment="Bottom" Width="Auto">
<ItemsControl ItemsSource="{Binding BlocksForMonth.Blocks}" ItemTemplate="{StaticResource Template1}">
</ItemsControl>
</StackPanel>
BlocksForMonths.Blocks is a list of view models. The Blocks class has a property called ClipType. If the clipType is 1, I want to use Template1. If its 2 I want to use Template 2. If its 3 I want to use Template 3
These templates contain different user controls
How can I do this through binding?
I have considered 1 template with the 3 controls, but I dont know how to bind the visibility?
In this XAML I am binding to a list not a single item
Paul
I would put the 3 controls in the same template and use Visibility to display the correct one. What I would do is build an IValueConverter to convert the deciding value (your case it's ClipType) and compare that to the ConverterParameter. If they are equal, return Visibility.Visible, otherwise return Visibility.Collapsed.
<UserControl.Resources>
<my:ClipTypeToVisibilityConverter x:Key="converter"/>
<DataTemplate x:Key="Template">
<StackPanel>
<my:UserControl1 Height="117" Visibility={Binding ClipType, Converter={StaticResource converter}, ConverterParameter=1} />
<my:UserControl2 Height="117" Visibility={Binding ClipType, Converter={StaticResource converter}, ConverterParameter=2} />
<my:UserControl3 Height="117" Visibility={Binding ClipType, Converter={StaticResource converter}, ConverterParameter=3} />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<StackPanel Name="stackPanel3" Orientation="Vertical" VerticalAlignment="Bottom" Width="Auto">
<ItemsControl ItemsSource="{Binding BlocksForMonth.Blocks}" ItemTemplate="{StaticResource Template}">
</ItemsControl>
</StackPanel>
This example assumes the ClipType property is on each item view model in the list being displayed.
Here is a C# example converter.
public class ClipTypeToVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var clipType = value.ToString();
if (clipType == (string)parameter))
return Visibility.Visible;
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Sorry, everything was air-code. But I think you get the idea.

Binding to ComboBox with converter in Silverlight

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.

Resources