WPF add Margin Binding using 'Validation.HasError' as Path at runtime - c#

I have the following XAML code that represents a TextBox with validation, when an error occurs then the margin is increased so that the message is not overlapping other UI elements under this TextBox.
In XAML every part of this works like I intended for it to work.
Validation is implemented using the IDataErrorInfo interface
<TextBox
Grid.Column="1"
Validation.ErrorTemplate="{StaticResource validationErrorTemplate}"
Style="{StaticResource baseMargins}"
Margin="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.HasError), Converter={StaticResource MarginConv}}"
Padding="{StaticResource basePadding}">
<TextBox.Text>
<Binding
Path="Email"
Mode="TwoWay"
UpdateSourceTrigger="PropertyChanged"
ValidatesOnDataErrors="True"/>
</TextBox.Text>
</TextBox>
Now I want the create the same but at runtime. The page has an ItemsControl that I fill with the generated TextBoxes.
The following code shows how I create this TextBox
private static void CreateForStackOverflow()
{
TextBox textBox = new TextBox();
Binding textBinding = new Binding();
textBinding.Path = new PropertyPath("Email");
textBinding.Mode = BindingMode.TwoWay;
textBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
textBinding.ValidatesOnDataErrors = true;
textBinding.NotifyOnValidationError = true;
textBox.SetBinding(TextBox.TextProperty, textBinding);
var valTemplate = (ControlTemplate)Application.Current.FindResource("validationErrorTemplate");
Validation.SetErrorTemplate(textBox, valTemplate);
Binding valBinding = new Binding();
valBinding.RelativeSource = new RelativeSource(RelativeSourceMode.Self);
valBinding.Path = new PropertyPath("Validation.HasError");
valBinding.Converter = new Converters.BoolMarginConverter();
textBox.SetBinding(FrameworkElement.MarginProperty, valBinding);
}
Now the validation works, errors are created but the only thing that does not work is the Binding for the MarginProperty. This is never triggered.
The following error is displayed in the Output window:
BindingExpression path error: 'Validation' property not found on 'object' ''TextBox' (Name='')'. BindingExpression:Path=Validation.HasError;
DataItem='TextBox' (Name='');
target element is 'TextBox' (Name='');
target property is 'Margin' (type 'Thickness')
I have found it could maybe have something to do with my `DataContext] but it is set in the XAML, and setting that Context was the solution for all those people but not for me.
Using Snoop (2.10.0.0) I can see that the TextBox has a Validation property.
Here is what Snoop shows on the Marginproperty.
This a what the overlapping errors look like.
And the code for the BoolMarginConverter is the following:
public class BoolMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool hasError = (bool)value;
return hasError ? new Thickness(2, 2, 2, 20) : new Thickness(2, 2, 2, 2);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
But this is never executed because the Validation.HasError could not be found.
What am I missing here?
EDIT: The error template
<ControlTemplate x:Key="validationErrorTemplate">
<DockPanel>
<StackPanel
Orientation="Horizontal" DockPanel.
Dock="Bottom"
ClipToBounds="True">
<Grid
Width="12"
Height="12">
<Ellipse
Width="12"
Height="12"
Fill="Red"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock
Foreground="White"
FontWeight="Heavy"
FontSize="8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
Text="X"
ToolTip="{Binding ElementName=ErrorAdorner, UpdateSourceTrigger=PropertyChanged,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Grid>
<TextBlock
Foreground="Red"
FontWeight="Bold"
TextWrapping="NoWrap"
TextTrimming="WordEllipsis"
Margin="2,0,0,0"
Text="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors), Converter=converters:ValidationErrorsToStringConverter}}"
/>
</StackPanel>
<AdornedElementPlaceholder x:Name="ErrorAdorner"/>
</DockPanel>
</ControlTemplate>

I was missing the brackets on (Validation.HasError) ...
Validation.HasError ==> (Validation.HasError)
valBinding.Path = new PropertyPath("(Validation.HasError)");
Maybe someday this will help someone.
Thanks all

I wouldn't use code to do all that and even then what you have seems over complicated.
The below markup works for me.
I have a public Int property in code behind just to test by typing a character.
Obviously, if you want to apply this by code then put an x:Key on your style and then you can go grab it out resources and apply it. Mine applies to all textboxes. I don't really follow why you wouldn't want that anyhow.
I would also suggest that moving ui around like this is limiting. I'd prefer a border and outline colour change and see all the errors in a tooltip. You can only fit one this way.
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel>
<StackPanel
Orientation="Horizontal" DockPanel.Dock="Bottom"
ClipToBounds="True">
<Grid
Width="12"
Height="12">
<Ellipse
Width="12"
Height="12"
Fill="Red"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock
Foreground="White"
FontWeight="Heavy"
FontSize="8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
Text="X"
ToolTip="{Binding ElementName=ErrorAdorner, UpdateSourceTrigger=PropertyChanged,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Grid>
<TextBlock
Foreground="Red"
FontWeight="Bold"
TextWrapping="NoWrap"
TextTrimming="WordEllipsis"
Margin="2,0,0,0"
Text="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)/ErrorContent}"
/>
</StackPanel>
<AdornedElementPlaceholder x:Name="ErrorAdorner"/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)/ErrorContent}"/>
<Setter Property="Margin" Value="0,0,0,20"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox Text="{Binding MyNum, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="Banana"/>
<Button Content="Some Button"/>
</StackPanel>
</Grid>

Related

How can I bind this Textblock inside ControlTemplate in button style?

I have a Button style and this style contains an icon and a text. I would like to bind the text.
How can I achieve that?
<Style TargetType="{x:Type Button}" x:Key="ConnectedButton">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="FlowDirection" Value="LeftToRight"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Padding="5 0"
Width="80"
Height="30"
Margin="5">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="{Binding Connect}"
Margin="3 0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="{StaticResource ConnectIcon}"
Style="{StaticResource Icon_Text}" Margin="3 0"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Use the style in MainWindow.xaml:
<Button Style="{StaticResource ConnectedButton}" Margin="10,15,0,10" x:Name="cnct_btn" Content="{StaticResource Connect}" Height="40" Width="80 " HorizontalAlignment="Left" VerticalAlignment="Center" Click="Cnct_Click"/>
MainWindow.xaml.cs
bool test = false;
//...
if (test)
{
cnct_btn.Content = "Connect";
}
else
{
cnct_btn.Content = "Not Connected";
}
I have tried Text={Binding Connect} but it doesn't work.
In a control template, you have to use a TemplateBinding to access a property on a templated control. In case of a Button, it is the Content property that you want to bind.
Implements a markup extension that supports the binding between the value of a property in a template and the value of some other exposed property on the templated control.
<TextBlock Text="{TemplateBinding Content}"
Margin="3 0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
A simple Binding will resolve a property on the current data context. You can also make this work, but you need to specify a RelativeSource using TemplatedParent.
TemplatedParent - Refers to the element to which the template (in which the data-bound element exists) is applied. This is similar to setting a TemplateBindingExtension and is only applicable if the Binding is within a template.
<TextBlock Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
Margin="3 0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
Please note that in this scenario a TemplateBinding is sufficient, as it is only one way. In a two-way binding you would have to use the variant using RelativeSource and TemplatedParent.
A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}. A TemplateBinding is always a one-way binding, even if properties involved default to two-way binding. Both properties involved must be dependency properties. In order to achieve two-way binding to a templated parent use the following binding statement instead {Binding RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, Path=MyDependencyProperty}.

WPF : get value from user control to parent window

i've a user control which contains cefsharpwpf:ChromiumWebBrowser control. this UC is loaded dynamically to the main window (in tab control).
UC gets and sets the value of var Title of class DisplayHandler which implements IDisplayHandler, INotifyPropertyChanged and it works fine for the UC.
Now I want the value of Title either from class DisplayHandler or from UC in the main class to set the Header of the Tab Item.
this code is from UC and works for Lable title
<Label x:Name="title" Content="{Binding ElementName=Browser_DisplayHandler, Path=Title, TargetNullValue=TitleHere}" />
<cefsharpwpf:ChromiumWebBrowser Name="browser" Address="google.com">
<cefsharpwpf:ChromiumWebBrowser.DisplayHandler>
<local:DisplayHandler x:Name="Browser_DisplayHandler"/>
</cefsharpwpf:ChromiumWebBrowser.DisplayHandler>
</cefsharpwpf:ChromiumWebBrowser>
but i want this title value in main class which has a Data template designed for tab control and textblock in header is named as txtTitle and is bind to Header
<TabControl Name="tabDynamic" ItemsSource="{Binding}" SelectionChanged="tabDynamic_SelectionChanged">
<TabControl.Resources>
<DataTemplate x:Key="TabHeader" DataType="TabItem">
<DockPanel Width="200" MaxWidth="200" Height="28">
<Button Name="btnDelete" DockPanel.Dock="Right" Margin="5,0,0,0" Padding="0" Click="btnDelete_Click" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Name}" Width="15" Height="15">
<Image Source="C:\Users\Faisal\source\repos\SampleWPF\SampleWPF\delete.png" Height="13" Width="13"></Image>
</Button>
<TextBlock Name="txtTitle" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Header}" />
</DockPanel>
</DataTemplate>
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border" Margin="1,0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="7,2"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
</TabControl>
if i set tab.Header = "Tab Title";from its main class that works but i want Title from class DisplayHandler
string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
OnPropertyChanged("Title");
}
}
Please help me to achieve this by using code behind technique or Binding in WPF
thanks

Get the TabItem Name or header if it has validation Error

I have the following TabConrol
<telerik:RadTabControl
Grid.Row="2" VerticalAlignment="Top" SelectedIndex="{Binding SelectedIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Content" DropDownDisplayMode="Visible" ScrollMode="Item" BorderThickness="0">
<telerik:RadTabItem DropDownContent="Job Config" Header="Job Config" >
<telerik:RadTabItem.Content>
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<local:JobGroupsCars DataContext="{Binding}" Margin="10" IsEnabled="{Binding Job.IsNotInEditMode ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</ScrollViewer>
</telerik:RadTabItem.Content>
</telerik:RadTabItem>
<telerik:RadTabItem
DropDownContent="Job Info" Header="Job Info" >
<telerik:RadTabItem.Content>
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<local:JobDetailView DataContext="{Binding}" Margin="10" IsEnabled="{Binding Job.IsNotInEditMode ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</ScrollViewer>
</telerik:RadTabItem.Content>
</telerik:RadTabItem>
<-- more tabs go here -->
</telerik:RadTabControl>
As you can see, the TabItem is a user control
What Im trying to achieve is when I click the save button I want to show the name that has validation errors
Im able to get all the validation errors but Im not able to show which tab has this error (as you can see in the below image)
I tried to use the following snippet but its not working
<UserControl.Resources>
<ControlTemplate x:Key="ValidationTabTemplate">
<DockPanel LastChildFill="True">
<Image Width="32" Height="32"
Source="../Assets/Delete_Icon.png" Opacity="0.75"
ToolTip="{Binding Path=AdornedElement.ToolTip, RelativeSource={RelativeSource AncestorType={x:Type Adorner}, Mode=FindAncestor}}"
/>
<AdornedElementPlaceholder/>
</DockPanel>
</ControlTemplate>
<Style x:Key="CustomTabError" TargetType="{x:Type telerik:RadTabItem}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="HeaderTemplate"
Value="{StaticResource ValidationTabTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
I am using WPF with MVVM
Any help would be appreciated
thanks alot
Okay a little more detailed than my comment:
You want to highight the Tabcontrol that containes your error if i understand you correctly:
Imagine this beeing your tabcontrol and the Checkboxes beeing your input fields we bound our tab item to each of our checkboxes.IsChecked via Multibinding
this would be your custom control and the .Validation.HasError property
if any of the CheckBoxes is not checked ( or in your case if an error occoured) the forground of the tabcontrol will become red by using a multiconverter
<TabControl>
<TabItem Header="Test">
<TabItem.Foreground>
<MultiBinding Converter="{StaticResource MultiEval}">
<Binding ElementName="CB1" Path="IsChecked"/>
<Binding ElementName="CB2" Path="IsChecked"/>
<Binding ElementName="CB3" Path="IsChecked"/>
</MultiBinding>
</TabItem.Foreground>
<StackPanel>
<CheckBox Name="CB1"></CheckBox>
<CheckBox Name="CB2"></CheckBox>
<CheckBox Name="CB3"></CheckBox>
</StackPanel>
</TabItem>
<Window.Resources>
<loc:MultiEvaluator x:Key="MultiEval"/>
</Window.Resources>
Converter:
public class MultiEvaluator : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
foreach (var value in values)
{
if (!System.Convert.ToBoolean(value))
{
return Brushes.Red;
}
}
return Brushes.Black;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Binding Converter doesn't apply on root TreeViewItem element (WPF)

I'm creating a file explorer app using the TreeView control provided by WPF. I've customized it such that it displays a file icon next to the path. I'm using a IValueConverter to convert the path to the required image, which I based off this page: http://www.codeproject.com/Articles/21248/A-Simple-WPF-Explorer-Tree
It mostly works! Except that the root TreeViewItems don't display icons for some reason. I placed a breakpoint on the IValueConverter::Convert() function and confirmed that it doesn't get executed for the root nodes, but do for all children nodes after that.
The VS output window shows no binding errors, so I'm at a loss at how this could happening. Any ideas?
Converter Code:
[ValueConversion(typeof(string), typeof(bool))]
public class HeaderToImageConverter : IValueConverter
{
public static HeaderToImageConverter Instance = new HeaderToImageConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((value as string).Contains(#"\"))
{
Uri uri = new Uri("pack://application:,,,/Images/diskdrive.png");
BitmapImage source = new BitmapImage(uri);
return source;
}
else
{
Uri uri = new Uri("pack://application:,,,/Images/folder.png");
BitmapImage source = new BitmapImage(uri);
return source;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException("Cannot convert back");
}
}
TreeView XAML:
<TreeView Grid.Column="0" Name="fileExplorer" Margin="8,8,8,8">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="20" Height="20" Stretch="Fill" Source="{Binding Converter={x:Static local:HeaderToImageConverter.Instance}}" />
<TextBlock Text="{Binding}" Margin="5,0" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
I ran into a similar problem. But besides the TreeView.Resources I had the TreeView.ItemContainerStyle element as well. Moving the Style element to there actually styled only the root, but not the children. Therefore, a solution would be to put the element in both places.
TreeView XAML:
<TreeView Grid.Column="0" Name="fileExplorer" Margin="8,8,8,8">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="20" Height="20" Stretch="Fill" Source="{Binding Converter={x:Static local:HeaderToImageConverter.Instance}}" />
<TextBlock Text="{Binding}" Margin="5,0" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="20" Height="20" Stretch="Fill" Source="{Binding Converter={x:Static local:HeaderToImageConverter.Instance}}" />
<TextBlock Text="{Binding}" Margin="5,0" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
Now, it would be nicer not to have to reuse this HeaderTemplate Setter. But I have not found a way to do this.

Combobox "Select Item" binding

I'm working on a few ComboBoxes that need a "select" property as the top option in WPF (c#)
At the moment I have the combobox's named and then populated in the code behind from a array string.
<ComboBox Width="150" x:Name="cmbTitle" Margin="3" SelectedIndex="0" />
.
cmbTitle.Items.Add("Select");
foreach (var title in Constants.Title)
cmbTitle.Items.Add(title);
My Issue is that the selectd Index will always be off by 1 of the index in the string.
After doing my research I see that this is a very prehistoric way of populating a combo box (WinFrom background). Constants seem to be stored in Enums in every example I have looked at so would like to move away from multiple string[]s.
What is my best way of binding an enum to a combobox while accommodating for a "select" option in WPF?
I've looked at half a dozen options today and I'm not too sure what other code examples to list.
It's quite a open question, but I'm quite lost.
Thanks in advance,
Oli
Values of an enumeration can be retrieved from Enum.GetValues(), and binding to a method is typically done using ObjectDataProvider. Here's an example of getting all BindingMode values:
<ObjectDataProvider x:Key="BindingModes" ObjectType="{x:Type sys:Enum}" MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="BindingMode" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
Now, we can bind ItemsSource of our ComboBox:
<ComboBox ItemsSource="{Binding Source={StaticResource BindingModes}}" />
Our control needs a new property for the prompt:
public class ExtendedComboBox : ComboBox
{
public static readonly DependencyProperty PromptProperty =
DependencyProperty.Register("Prompt", typeof(string), typeof(ExtendedComboBox), new PropertyMetadata(string.Empty));
public string Prompt
{
get { return (string)GetValue(PromptTextProperty); }
set { SetValue(PromptTextProperty, value); }
}
}
We can cheat a bit and place a TextBlock with the prompt inside our control, and hide it when there's an item selected. For this we rewrite ControlTemplate of the control with a new one containing the TextBlock. I modified template from there:
<Style x:Key="PromptTextBlock" TargetType="{x:Type TextBlock}" >
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem, RelativeSource={RelativeSource TemplatedParent}}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="PromptedComboBox" TargetType="{x:Type local:ExtendedComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ExtendedComboBox}">
<Grid>
<ToggleButton x:Name="DropDownToggle"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Margin="-1" HorizontalContentAlignment="Right"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
<Path x:Name="BtnArrow" Height="4" Width="8"
Stretch="Uniform" Margin="0,0,4,0" Fill="Black"
Data="F1 M 300,-190L 310,-190L 305,-183L 301,-190 Z " />
</ToggleButton>
<ContentPresenter x:Name="ContentPresenter" Margin="6,2,25,2"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}">
</ContentPresenter>
<TextBox x:Name="PART_EditableTextBox"
Style="{x:Null}"
Focusable="False"
Background="{TemplateBinding Background}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="3,3,23,3"
Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}"/>
<Popup x:Name="PART_Popup" IsOpen="{TemplateBinding IsDropDownOpen}">
<Border x:Name="PopupBorder"
HorizontalAlignment="Stretch" Height="Auto"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="Black" Background="White" CornerRadius="3">
<ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
<ItemsPresenter/>
</ScrollViewer>
</Border>
</Popup>
<TextBlock Margin="4,3,20,3" Text="{Binding PromptText, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource PromptTextBlock}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Combining, we have:
<local:ExtendedComboBox Style="{StaticResource PromptedComboBox}" Prompt="Select an item" ItemsSource="{Binding Source={StaticResource BindingModes}}" />
I think the best way to populate your ComboBox will be using IDictionary.
As an example, your code-behind:
public YourEnum SelectedOption { get; set; }
public IDictionary<string, YourEnum> Options = new Dictionary<string, YourEnum?>();
Options.Add("Select", null);
Options.Add("Option 1", YourEnum.Option1);
...
Options.Add("Option N", YourEnum.OptionN);
Your xaml file:
<ComboBox ItemsSource="{Binding Options, ...}" SelectedValue="{Binding SelectedOption, ...}" DisplayMemberPath="Key" SelectedValuePath="Value" />

Categories

Resources