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"
Related
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;
}
}
}
This question already has an answer here:
WPF ComboBox bind itemssource to different datacontext in MVVM
(1 answer)
Closed 4 years ago.
I Need a collection of ComboBoxes with a common collection of possible selections.
Codebehind excerpt:
namespace ComboBoxesInCollection
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
D = new DataContainer();
this.DataContext = D;
}
private DataContainer D;
}
public class DataContainer
{
public ObservableCollection<Item> ComboboxItems
{
get { return comboboxItems; }
}
public ObservableCollection<Selection> ComboboxSelections
{
get { return comboboxSelections; }
}
public DataContainer()
{
comboboxItems = new ObservableCollection<Item>
{
new Item(100, "Entry #1"),
new Item(101, "Entry #2"),
new Item(102, "Entry #3")
};
comboboxSelections = new ObservableCollection<Selection>()
{
new Selection(1),
new Selection(2),
new Selection(3)
};
}
private ObservableCollection<Item> comboboxItems;
private ObservableCollection<Selection> comboboxSelections;
}
}
XAML excerpt:
<Window.Resources>
<DataTemplate x:Key="CSTemplate">
<Border BorderBrush="Black" BorderThickness="1,1,0,0" Margin="0,0,0,4" Padding="4">
<StackPanel>
<Label Content="{Binding Id}"/>
<ComboBox
ItemsSource="{Binding ComboboxItems}" //<= does not work
DisplayMemberPath="Name"
SelectedValue="{Binding SelectedId}"
SelectedValuePath="Id"
/>
</StackPanel>
</Border>
</DataTemplate>
...
<ItemsControl ItemsSource="{Binding ComboboxSelections}" ItemTemplate="{StaticResource CSTemplate}"/>
The ItemsControl shows the items, but the Combobox is empty.
I know that i try to access a property/collection inside of a Selection that is not existing right now.
How would i correctly specify the DataBinding so i can see the items?
Used Element Binding to access the DataContext Property of the window.
First Name the Window x:Name="Window1" and the while binding, use element binding.
ItemsSource="{Binding ElementName=Window1, Path=DataContext.ComboboxItems}"
XAML of whole window
<Window x:Class="WpfApp6.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:WpfApp6"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" x:Name="Window1">
<Window.Resources>
<DataTemplate x:Key="CSTemplate">
<Border BorderBrush="Black" BorderThickness="1,1,0,0" Margin="0,0,0,4" Padding="4">
<StackPanel>
<Label Content="{Binding Id}"/>
<ComboBox
ItemsSource="{Binding ElementName=Window1, Path=DataContext.ComboboxItems}"
DisplayMemberPath="Name"
SelectedValue="{Binding SelectedId}"
SelectedValuePath="Id"
/>
</StackPanel>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding ComboboxSelections}" ItemTemplate="{StaticResource CSTemplate}" />
</Grid>
I have a class Employee in a WPF Project:
class Employee
{
public int ID { get; set; }
public string Name { get; set; }
}
And I am creating an instance of it emp2 in my XAML file:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:Employee x:Key="emp2" ID="20" Name="Second Employee "></local:Employee>
</Window.Resources>
<StackPanel>
<Label x:Name="lblEmpInfo2" FontSize="18" Margin="20" Content="{StaticResource emp2}"></Label>
</StackPanel>
</Window>
However this only displays the datatype of emp2 i.e. WpfApplication1.Employee. How do I display the ID and Name of emp2
WPF uses the concept of DataTemplates to give you the possibility to decide how data objects should be presented. Therefore you could define a DataTemplate for the class Employee and then use a ContentControl which uses the instance of the Employee class as its Content. The DataTemplate could contain controls to show the values.
<Window.Resources>
<local:Employee x:Key="emp2" ID="20" Name="Second Employee "></local:Employee>
<DataTemplate DataType={x:Type local:Employee}">
<StackPanel>
<TextBlock Text={Binding ID} />
<TextBlock Text={Binding Name} />
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ContentControl Content="{StaticResource emp2}" />
</StackPanel>
Like this:
<Label x:Name="lblEmpInfo2" FontSize="18" Margin="20" Content="{Binding Path=Name, Source={StaticResource emp2}}"></Label>
Or implement the ToString method override of the Employee class
public override string ToString()
{
return string.Format("{0} {1}", Id, Name);
}
Your binding's just a wee bit off:
<Label x:Name="lblEmpInfo2" FontSize="18" Margin="20" Content="{Binding Source={StaticResource emp2}, Path=ID}"></Label>
You have multiple options:
Use DataTemplates (MatthiasG's answer)
Quick and dirty: Implement ToString() in class Employee, simple but not very flexible.
Use StaticResource as Binding Source:
<StackPanel>
<Label Content="{Binding ID, Source={StaticResource emp2}}"></Label>
<Label Content="{Binding Name, Source={StaticResource emp2}}"></Label>
</StackPanel>
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".
TLDR:
A Nullreference exception is thrown when XAML parsing any button element when another unrelated element has databinding and value converter. When the buttons are commented out, or the databinding is removed the form works.
I have a WPF UserControl with a list box in it which has a DataTemplate with multiple controls in it. I also have a bool to visibility value converter which I use in different locations in the control. I added a new static reference of the converter to the control (different bool to visibility values) and bind it to a label and suddenly the app crashes upon loading the control.
I remove the binding and all is well again. The converter is not at fault though; I put break points in its constructor as well as the convert methods, and it never reaches it. The exception is in the parsing of the XAML, not at the label, but at the first button declared, which is 100% unrelated to the label. If I remove the value converter binding from the label, the XAML parses correctly and the button has no issues.
However, to complicate things, if I comment out that button and every other button in the XAML, it also parses correctly and the value converter works without a problem.
What am I missing?
XAML:
<UserControl x:Class="Customer_Management.OpportunityControl"
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"
mc:Ignorable="d"
xmlns:l="clr-namespace:Customer_Management"
d:DesignHeight="300" d:DesignWidth="300" MaxHeight="200" BorderBrush="DarkGray" BorderThickness="1" x:Name="ucOpp">
<UserControl.Resources>
<l:NullToVisibilityConverter NullValue="Hidden" NonNullValue="Visible" x:Key="NullToHidden"></l:NullToVisibilityConverter>
<l:BoolToVisibilityConverter TrueValue="Visible" FalseValue="Hidden" x:Key="TrueToVisible"></l:BoolToVisibilityConverter>
<l:BoolToVisibilityConverter TrueValue="Hidden" FalseValue="Visible" x:Key="FalseToVisible"></l:BoolToVisibilityConverter>
</UserControl.Resources>
<ScrollViewer>
<ListBox Name="lbxOpps" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="DarkGray" BorderThickness="1">
<Grid>
<StackPanel>
<TextBlock Text="{Binding Path=Opportunity.Name}" Margin="0,1,3,1"></TextBlock>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Opportunity.Amount, StringFormat=\{0:C\}}" Margin="0,1,3,1"></TextBlock>
<Button Name="btnFinishOrder" Click="btnFinishOrder_Click">Finish Order</Button>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,1,3,1">Invoice #</TextBlock>
<TextBox Name="tbxInvoiceNumber" Text="{Binding Path=InvoiceNumber}"></TextBox>
</StackPanel>
<ListBox ItemsSource="{Binding Path=Batches}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label FontWeight="Bold" Visibility="{Binding Path=IsOcc, Converter={StaticResource TrueToVisible}}">OCC #:</Label>
<ComboBox Margin="0,0,0,0" Name="cboLicense" SelectedValue="{Binding Path=SLicense}" DisplayMemberPath="LicenseID"
SelectedValuePath="LicenseID" ItemsSource="{Binding ElementName=ucOpp, Path=Licenses}">
</ComboBox>
<!--<Button Margin="0,0,3,0" DataContext="{Binding ElementName=cboLicense}" Click="Button_ClearContorl">X</Button>-->
<Label Margin="0,0,3,0" >R #:</Label>
<!--<Button ToolTip="Click to change" Name="btnLicFile" Click="Button_Click" >LIC File</Button>-->
<!--<Button Margin="0,0,3,0" DataContext="{Binding ElementName=btnLicFile}" Click="Button_ClearContorl" ToolTip="Clear">X</Button>-->
<Label Margin="0,0,3,0" >P #:</Label>
<ComboBox Margin="0,0,0,0" Name="cbxPNum" SelectedValue="{Binding Path=PNum}" DisplayMemberPath="Name"
SelectedValuePath="Id" ItemsSource="{Binding ElementName=ucOpp, Path=Nums}">
</ComboBox>
<!--<Button Margin="0,0,3,0" DataContext="{Binding ElementName=cbxPNum}" Click="Button_ClearContorl" ToolTip="Clear">X</Button>-->
<Label Margin="0,0,3,0" >U #:</Label>
<ComboBox Margin="0,0,0,0" Name="cbxUNum" SelectedValue="{Binding Path=UNum}" DisplayMemberPath="Name"
SelectedValuePath="Id" ItemsSource="{Binding ElementName=ucOpp, Path=Nums}">
</ComboBox>
<!--<Button Margin="0,0,3,0" DataContext="{Binding ElementName=cbxUNum}" Click="Button_ClearContorl" ToolTip="Clear">X</Button>-->
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
<Label HorizontalAlignment="Stretch" Background="LawnGreen" FontSize="24" Opacity="0.8" VerticalAlignment="Stretch" Visibility="{Binding Path=IsProcessing, Converter={StaticResource TrueToVisible}}"></Label>
<Label HorizontalAlignment="Center" FontSize="24" VerticalAlignment="Center" Visibility="{Binding Path=IsProcessing, Converter={StaticResource TrueToVisible}}">Processing...</Label>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
ValueConverter:
public sealed class BoolToVisibilityConverter : IValueConverter
{
public Visibility TrueValue { get; set; }
public Visibility FalseValue { get; set; }
public BoolToVisibilityConverter()
{
// set defaults
TrueValue = Visibility.Visible;
FalseValue = Visibility.Collapsed;
}
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (!(value is bool))
return null;
return (bool)value ? TrueValue : FalseValue;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (Equals(value, TrueValue))
return true;
if (Equals(value, FalseValue))
return false;
return null;
}
}