ComboBox - bind selected value - wpf

I want to bind the combobox's selected value to the bounded object property, and also set the selected index of every combobox to 0.
The problem is that only first combo shows the selected item.
public enum SubEnum1
{
Apple=1,
Banana=2,
Pear=3
}
public enum FullEnum
{
Apple=1,
Banana=2,
Pear=3,
Cucumber=4,
Tomato=5,
Onion=6
}
Im XAML window i have some data control (list) where is a datatemplate that has a combobox.
comboboxes are bounded to SubEnum1.
The data-control is bounded to an object-collection:
List<MyObject> collection = new List<MyObject>()
//collection.Add...
mylist.ItemsSource = collection;
public class MyObject
{
public FullEnum TheSelectedEnum {get;set;}
....
//other properties
}
public class EnumConverter2 : 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)
{
if (value != null)
return (FullEnum)value;
else return "";
}
}
<ObjectDataProvider x:Key="Enum1"
MethodName="GetValues"
ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:SubEnum1" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ListBox Height="261" HorizontalAlignment="Left" Name="mylist" VerticalAlignment="Top" Width="278">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ComboBox Height="23" Width="90"
ItemsSource="{Binding Source={StaticResource Enum1}}"
SelectedValue="{Binding Path=TheSelectedEnum, Converter={StaticResource enumConverter}}"
SelectedIndex="0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
(If I expand other comboboxes I see the values)
Update to post:
Maybe I can somehow else pass the selected value to the binded object?

You can do this and solve your problem:
public enum SubEnum1
{
None=0,
Apple=1,
Banana=2,
Pear=3
}
Then use FallbackValue:
<ComboBox Height="23" Width="90"
ItemsSource="{Binding Source={StaticResource Enum1}}"
SelectedValue="{Binding Path=TheSelectedEnum, FallbackValue=0}" />

Related

Bind to a System.Windows Enum from xaml

I am trying to bind a ComboBox ItemsSource to the TextWrapping enum within the System.Windows namespace. The end result would be a drop down where the user can select which type of text wrapping to apply for a given object within my application. Everything works fine when I bind to a custom enum, but I can't figure out what path/source I need to use to bind to an enum within the System.Windows namespace. How can I access this namespace through data binding?
<DataTemplate
DataType="{x:Type MyObjectWrapper}"
>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Text Wrapping" VerticalAlignment="Center" Margin="5,5,0,5"/>
<ComboBox
ItemsSource="{Binding Source={???}, Converter={local:MyEnumConverter}}"
SelectedValuePath="Value"
DisplayMemberPath="Description"
SelectedValue="{Binding Path = TextWrapping}"
VerticalAlignment="Center"
Margin="5"
/>
</StackPanel>
</DataTemplate>
Update: My enum converter just needs the enum class passed in the xaml, which looks like this for custom enums:
<ComboBox
ItemsSource="{Binding Path=MyCreatedEnum, Converter={local:MyEnumConverter}}"
SelectedValuePath="Value"
DisplayMemberPath="Description"
SelectedValue="{Binding Path = TextWrapping}"
VerticalAlignment="Center"
Margin="5"
/>
Found this over the web under this link.
http://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/
Here is the modified code to suite your requirement.
<Grid x:Name="LayoutRoot">
<Grid.Resources>
<local:EnumToListConverter x:Key="enumToListConv" />
</Grid.Resources>
<ComboBox
Margin="5"
VerticalAlignment="Center"
ItemsSource="{Binding Source={local:EnumBindingSource {x:Type sysWin1:TextWrapping}}, Converter={StaticResource enumToListConv}}"
SelectedValuePath="Value" />
</Grid>
public class EnumBindingSourceExtension : MarkupExtension
{
private Type _enumType;
public Type EnumType
{
get { return this._enumType; }
set
{
if (value != this._enumType)
{
if (null != value)
{
Type enumType = Nullable.GetUnderlyingType(value) ?? value;
if (!enumType.IsEnum)
throw new ArgumentException("Type must be for an Enum.");
}
this._enumType = value;
}
}
}
public EnumBindingSourceExtension() { }
public EnumBindingSourceExtension(Type enumType)
{
this.EnumType = enumType;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (null == this._enumType)
throw new InvalidOperationException("The EnumType must be specified.");
Type actualEnumType = Nullable.GetUnderlyingType(this._enumType) ?? this._enumType;
return actualEnumType;
}
}
public class EnumToListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var items = Enum.GetValues((Type)value);
return items;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Partially binding to a list

I have a collection of a few thousand elements and I want to display only a subset of them. Is there a way to bind the collection to a view such that only certain elements, e.g. those with property "Show == true", are displayed? If so, would it still create thousands of UI elements? Or do I have to create a new list of the to-be-shown elements?
Check CollectionViewSource Class and CollectionViewSource.Filter Event
View(partial example):
<Grid>
<Grid.DataContext>
<wpfCalc:StudentList/>
</Grid.DataContext>
<Grid.Resources>
<CollectionViewSource
Source="{Binding Students,Mode=OneWay}" x:Key="StudentsCollViewSource"
Filter="StudentsCollViewSource_OnFilter"/>
</Grid.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource StudentsCollViewSource}}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name,Mode=OneTime}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
And code behind filter implementation:
private void StudentsCollViewSource_OnFilter(object sender, FilterEventArgs e)
{
var s = e.Item as Student;
e.Accepted = s != null && !string.IsNullOrWhiteSpace(s.Name);
}
There are two methods. First one is to use a converter.
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="converter"/>
</Window.Resources>
<StackPanel>
<ListView x:Name="listView" ItemsSource="{Binding List}">
<ListView.ItemTemplate>
<DataTemplate >
<TextBlock Text="{Binding Name}" Visibility="{Binding IsActive, Converter={StaticResource converter}}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
//Code Behind
public class BoolToVisibilityConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (bool)value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return false; // not needed
}
#endregion
}
Second method is to use linq
List<MyData> list
{
get
{
if(list!=null)
return list.where( p => p.IsActive == true );
return null;
}
set
{
if(list!=value)
list = value;
}
}

Bind ListBox to SelectionChanged ComboBox in XAML

I want to bind the selection change of the combo box to update my list box, but my xaml code is probably wrong.
This is my Collection that takes the data from the Service.
public class WorkersCollection
{
private WorkerClient client = new WorkerClient();
public ObservableCollection<Worker> Workers { get; set; }
public WorkersCollection()
{
Workers = new ObservableCollection<Worker>();
}
public ICollection<Worker> GetAllWorkers()
{
foreach (var worker in client.GetAllWorkers())
{
Workers.Add(worker);
}
return Workers;
}
}
My DataContext is workers:
public partial class MainWindow : Window
{
WorkersCollection workers;
public MainWindow()
{
InitializeComponent();
workers = new WorkersCollection();
this.DataContext = workers;
workers.GetAllWorkers();
}
}
and in XAML:
<ComboBox Name="cbxWorkers" HorizontalContentAlignment="Right" SelectedItem="{Binding Workers}" ItemsSource="{Binding Workers}">
<ComboBox.ItemTemplate>
<DataTemplate>
<ComboBoxItem Content="{Binding LastName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ListBox Grid.Row="3" ItemTemplate="{StaticResource WorkersTemplate}" ItemsSource="{Binding ElementName=cbxWorkers, Path=SelectedItem}" />
How can I fix it?
ItemsSource property of class ListBox has type IEnumerable (msdn).
So you can't assign to it object of type Worker.
You can create converter to do that.
Converter class:
public class WorkerToListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return new List<Worker> { value as Worker };
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML code:
...
<Window.Resources>
<local:WorkerToListConverter x:Key="myCon" />
</Window.Resources>
...
<ComboBox Name="cbxWorkers" HorizontalContentAlignment="Right" ItemsSource="{Binding Workers}">
<ComboBox.ItemTemplate>
<DataTemplate>
<ComboBoxItem Content="{Binding LastName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ListBox Grid.Row="3" ItemTemplate="{StaticResource WorkersTemplate}"
ItemsSource="{Binding ElementName=cbxWorkers, Path=SelectedItem, Converter={StaticResource myCon}}" />
...
You should also delete SelectedItem binding from ComboBox.
... SelectedItem="{Binding Workers}" ItemsSource="{Binding Workers}" ...
It's no sense to binding SelectedItem to the same thing as ItemsSource.

Silverlight binding visibility to parent class property

I have problem with binding visibility in listbox-item template with property in parent object. Here is a little snippet from custom xaml style template:
<!-- DATA BINDING ITEM TEMPLATE -->
<StackPanel Orientation="Vertical">
<TextBlock Height="19"
....
Text="{Binding InfoTop}"/>
<Rectangle Height="1"
....
Visibility="{Binding _linesVisibility[0], RelativeSource={RelativeSource AncestorType=my:PatientsList}}"/>
<TextBlock Height="19"
....
Text="{Binding InfoMiddle}"
Visibility="{Binding _linesVisibility[0], ElementName=patientsControl}"/>
<Rectangle Height="1"
....
Visibility="{Binding _linesVisibility[1]}"/>
<TextBlock Height="19"
....
Text="{Binding InfoBottom}"
Visibility="{Binding _linesVisibility[1]}"/>
</StackPanel>
I managed to bind Text value by assigning ItemsSource in code file but i can't bind Visibility. As you can see i tried some different ideas but none of them work.
I have public variable public Visibility[] _linesVisibility = new Visibility[2]; in my custom control. This control contains listbox with custom style as above. How to bind properly my _linesVisibility to listbox-item style ?
You can't bind directly to an array:
Visibility="{Binding _linesVisibility[1]}"
This will not work.
You need to bind to a property and your class needs to implement INotifyPropertyChanged:
private Visibility backingVariable;
public Visbilility PublicProperty
{
get { return backingVariable; }
set
{
backingVariable = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("PublicVariable"));
}
}
}
It doesn't have to be a property of type Visibility. It can be any type as long as you bind through a converter that returns Visibility:
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool visibility = (bool)value;
return visibility ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility visibility = (Visibility)value;
return (visibility == Visibility.Visible);
}
}
Usage:
Visibility="{Binding SomeBoolean, Converter={StaticResource boolToVisibilityConverter}}"
where the converter is declared in XAML like this:
<UserControl.Resources>
<globalConverters:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
</UserControl.Resources>

Bind a DataGridComboBoxColumn to an Enum

I have a simple DataGrid which I want the user to add some rows to.
However I want one of the columns to be a ComboBox with it's values taken from an enum.
What's the simplest way of doing this in my XAML?
I've tried following but I get the error "Two-way binding requires Path or XPath"
<Window.Resources>
<ObjectDataProvider x:Key="myEnumData"
MethodName="GetValues"
ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:MyEnum" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
...
<DataGrid.Columns>
<DataGridComboBoxColumn Header="MyHeader" DisplayMemberPath="EnumValue"
SelectedItemBinding="{Binding Source={StaticResource myEnumData}}">
</DataGridComboBoxColumn>
</DataGrid.Columns>
You are trying to bind the selected item when you (presumably) want to bind the list of available items. Change your binding to this:
<DataGridComboBoxColumn Header="MyHeader"
ItemsSource="{Binding Source={StaticResource myEnumData}, Mode=OneWay}">
</DataGridComboBoxColumn>
XAML
xmlns:ext="clr-namespace:Project.Core.Tools;assembly=Project.Core"
<DataGridComboBoxColumn ItemsSource="{x:Static ext:Extensions.GetEnumTypes}" SelectedItemBinding="{Binding EnumType}" />
Static Class
public static IEnumerable<EnumType> GetEnumTypes => Enum.GetValues(typeof(EnumType)).Cast<EnumType>();
XAML:
<DataGridComboBoxColumn ItemsSource="{Binding Orientantion, Mode=OneTime, Converter={Converts:EnumToItemSourceConverter}}" SelectedItem="{Binding Orientantion}"/>
C#:
public enum OrientantionTypes : int { Custom, Automatic}
public OrientantionType Orientantion { get; set;}
Converter:
public class EnumToItemSourceConverter: MarkupExtension, IValueConverter
{
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is Enum ))
return null;
{
Type enumType = value.GetType();
var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(enumType);
var instance = Activator.CreateInstance(constructedListType);
foreach (var m in Enum.GetValues(enumType))
{
((IList)instance).Add(m);
}
return (IList)instance;
}
return null;
}
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}

Resources