Combobox with static and dynamic data together in wpf - wpf

As the title suggests I want to add a static Item to a dataBound ComboBox.
I have refered this post.
Databinding a Combobox :
<ComboBox Name="comboBox1" Width="Auto" ItemsSource="{Binding}" />
Adding Static Items to a combobox :
<ComboBox Text="Is not open">
<ComboBoxItem Name="cbi1">Item1</ComboBoxItem>
<ComboBoxItem Name="cbi2">Item2</ComboBoxItem>
<ComboBoxItem Name="cbi3">Item3</ComboBoxItem>
</ComboBox>
Doing the above things together using CompositeCollection :
<ComboBox>
<ComboBox.Items>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={...whatever...}" />
<ComboBoxItem Name="cbi1">Item1</ComboBoxItem>
<ComboBoxItem Name="cbi2">Item2</ComboBoxItem>
<ComboBoxItem Name="cbi3">Item3</ComboBoxItem>
</CompositeCollection>
</ComboBox.Items>
</ComboBox>
But the above examples does not solve my problem.
I want to add a static Item to a dataBound ComboBox in which I use DataTemplate
Here is my Code for dataBound ComboBox (I don't know how to add static Items):
<ComboBox x:Name="cbUnder" ItemsSource="{Binding GroupsAndCorrespondingEffects}"
IsEditable="True" SelectedItem="{Binding SelectedGroup, Mode=TwoWay}"
TextSearch.TextPath="GroupName" Grid.Column="1" Grid.ColumnSpan="4" Grid.Row="3">
<ComboBox.ItemTemplate>
<DataTemplate>
<VirtualizingStackPanel Orientation="Horizontal">
<TextBlock Text="{Binding GroupName}" Width="250"/>
<TextBlock Text="{Binding CorrespondingEffect}" />
</VirtualizingStackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Update as requested by aks81 :
Here is the code for GroupsAndCorrespondingEffects
public GroupsViewModel()
{
using (DBEntities db = new DBEntities())
{
GroupsAndCorrespondingEffects = (from g in db.Groups
select new GroupAndCorrespondingEffect
{
GroupName = g.Name,
CorrespondingEffect = g.Type_Effect.Name
}
).ToList().OrderBy(g => g.GroupName);
Items = (from e in db.Type_Effect
select e.Name).ToList();
}
}
public static GroupsViewModel CurrentInstance { get { return Instance; } }
private IEnumerable<GroupAndCorrespondingEffect> _groupsAndCorrespondingEffects;
public IEnumerable<GroupAndCorrespondingEffect> GroupsAndCorrespondingEffects
{
get
{
return _groupsAndCorrespondingEffects;
}
set
{
_groupsAndCorrespondingEffects = value;
OnPropertyChanged("GroupsAndCorrespondingEffects");
}
}

Check out this link and let me know if it was useful :)
http://social.msdn.microsoft.com/Forums/vstudio/en-US/86229c53-15bd-4780-bee3-c6c2cdae81e7/select-multiple-checkboxes-placed-inside-a-combobox
have a nice day!

Related

wpf combobox default value to textBlock

I need to add a default value 'select' in the combobox.I cant add this value to the database.This location value is dynamic.It appears based upon the userrole. I tried different ways nothing worked.Please help.
<ComboBox Width="140" ItemsSource="{Binding SecurityContexts, Mode=OneWay}"
SelectedItem="{Binding ActiveSecurityContext, Mode=TwoWay}"
ToolTip="Working Location">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Location}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The code behind is
SecurityContexts = new ObservableCollection(_currentUser.ApplicationSecurityContexts);
public interface IApplicationSecurityContext
{
IRole Role { get; }
string Location { get; }
IEnumerable<string> Budgets { get; }
}
public IApplicationSecurityContext ActiveSecurityContext
{
get { return this._currentUser.ActiveSecurityContext; }
set
{
if (this._currentUser.ActiveSecurityContext != value)
{
this._currentUser.ChangeActiveSecurityContext(value);
RaisePropertyChanged("CurrentUser");
LoadData();
}
}
}
You can achieve your goal using CompositeCollection
you can do this. Define resource in your grid/usercontrol/combobox:
<Grid.Resources>
<CollectionViewSource x:Key="cvs" Source="{Binding Binding SecurityContexts, Mode=OneWay}" />
<DataTemplate DataType="{x:Type c:SecurityContexts}">
<TextBlock Text="{Binding Location}"/>
</DataTemplate>
</Grid.Resources>
then your combobox itemsource will be:
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem>
<TextBlock Text="select"/>
</ComboBoxItem>
<CollectionContainer Collection="{Binding Source= {StaticResource cvs}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
It should work. You need to define your datatemplate for your collection in the resource too, to define how your item will be displayed
Note that c in c:SecurityContexts is the path where you defined your custom object

Loop through the second column of WPF ListView and retrieve value of ComboBox in each row

I have a two-column ListView with CheckBoxes in the first column and ComboBoxes in the second column. I need to loop through the ComoboBoxes in the second column and retrieve the selected values (or indexes) from each ComboBox, along with some index or identifier of the ComboBox, and put the values in an array. For example, the layout looks like this:
COLUMN 1 COLUMN 2
======== ========
ChBx 1 Combo1
ChBx 2 Combo2
I need to grab the SelectedValue or SelectedIndex of each ComboBox in the second column and put it into an array in the right order. But, what I've found on the internet is to use: myListView.Items(0).SubItems(1).Text, to loop through the second column. However, my second column contains a ComboBox and I want its' value (not some Text property). Any ideas? My XAML markup is below.
<ListView IsSynchronizedWithCurrentItem="True" Margin="0,0,10,10" Name="patternList" Height="139" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="112" BorderBrush="{x:Null}" BorderThickness="1" Background="White" >
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Pattern">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Content="{Binding outContent}"
ToolTip="{Binding outToolTip}"
IsThreeState="False"
IsChecked="{Binding Path=outIsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Freq" Width="55">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox HorizontalContentAlignment="Center"
Height="14"
Padding="0"
SelectionChanged="FrequencyChanged_OnSelectionChanged"
FontSize="10">
<ComboBoxItem Content="0%"/>
<ComboBoxItem Content="10%"/>
<ComboBoxItem Content="20%"/>
<ComboBoxItem Content="30%"/>
<ComboBoxItem Content="40%"/>
<ComboBoxItem Content="50%"/>
<ComboBoxItem Content="60%"/>
<ComboBoxItem Content="70%"/>
<ComboBoxItem Content="80%"/>
<ComboBoxItem Content="90%"/>
<ComboBoxItem Content="100%"/>
</ComboBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
Bind SelectedValue to a property in your ViewModel. And in the Setter of that property, also update the collection.
Second approach, in your FrequencyChanged_OnSelectionChanged event handler. You can keep updating your collection there too.
From my perspective it would be better to generate items for the combobox in list item viewmodel, and bind to selected item in that view model. Below is the code that illustrates the approach.
XAML
<Window x:Class="ComboboxesInGrid.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:ComboboxesInGrid"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ListView IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding ListItems}" Margin="0,0,10,10" Name="patternList" BorderBrush="{x:Null}" BorderThickness="1" Background="White" >
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Pattern" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Content="{Binding outContent}"
ToolTip="{Binding outToolTip}"
IsThreeState="False"
IsChecked="{Binding Path=outIsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Freq" Width="155">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox HorizontalContentAlignment="Center"
Height="14"
Padding="0"
SelectedItem="{Binding outComboSelected}"
ItemsSource="{Binding outComboValues}"
FontSize="10">
</ComboBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<TextBlock Grid.Row="1" Text="{Binding SelectedComboItems}" />
</Grid>
</Window>
C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
namespace ComboboxesInGrid
{
public class MainWindowViewModel : ViewModelBase
{
private ObservableCollection<ListItemViewModel> _listItems = new ObservableCollection<ListItemViewModel>();
public string SelectedComboItems
{
get { return String.Join(",", _listItems.Select(li => $"{li.outContent}-{li.outIsChecked}-{li.outComboSelected}")); }
}
public ObservableCollection<ListItemViewModel> ListItems
{
get { return _listItems; }
set { _listItems = value; OnProperyChanged(); }
}
public MainWindowViewModel()
{
AddListItem(new ListItemViewModel() { outContent = "ChBx 1 ", outToolTip="Tooooool", outIsChecked = false, outComboSelected="30%" });
AddListItem(new ListItemViewModel() { outContent = "ChBx 2 ", outComboSelected = "70%" });
}
private void AddListItem(ListItemViewModel item)
{
item.PropertyChanged += (s, e) => OnProperyChanged(nameof(SelectedComboItems));
_listItems.Add(item);
}
}
public class ListItemViewModel : ViewModelBase
{
private string _outContent;
public string outContent
{
get { return _outContent; }
set { _outContent = value; OnProperyChanged(); }
}
private string _outToolTip;
public string outToolTip
{
get { return _outToolTip; }
set { _outToolTip = value; OnProperyChanged(); }
}
private bool? _outIsChecked;
public bool? outIsChecked
{
get { return _outIsChecked; }
set { _outIsChecked = value; OnProperyChanged(); }
}
private string _outComboSelected;
public string outComboSelected
{
get { return _outComboSelected; }
set { _outComboSelected = value; OnProperyChanged(); }
}
public IEnumerable<string> outComboValues
{
get
{
return Enumerable.Range(0, 11).Select(i => $"{i*10}%");
}
}
}
public class ViewModelBase : INotifyPropertyChanged
{
protected void OnProperyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
}

How can i add different images to combobox itemssource array

I would like to add different images next to each item in a combobox itemssource. Here's what i have at the moment.
<ComboBox x:Name="cmb" HorizontalAlignment="Left" Width="135" Height="22"
SelectedItem="{Binding myViewMode}" Margin="5,0,0,0">
<ComboBox.ItemsSource>
<x:Array Type="sys:String" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String>Oranges</sys:String>
<sys:String>Mangoes</sys:String>
</x:Array>
</ComboBox.ItemsSource>
</ComboBox>
How should add the two diffent images using an itemtemplate. Thanks
Edit One
This is what i have tried with itemtemplate
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding OrangesImage}" Height="100"/>
<Image Source="{Binding MangoesImage}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
It's here that am really stuck.
At the moment your item template contains only two images, so you will show two images and no text for each item!
I would suggest you change your ItemsSource to code behind so you can have text and image properties.
First make a simple Fruit class:
public class Fruit
{
public string FruitName { get; set; }
public string FruitImage { get; set; }
}
Then create a list of these fruits and set the ItemsSource of your combo box to this list:
var fruits = new List<Fruit>();
fruits.Add(new Fruit() { FruitName = "Mangos", FruitImage = #"C:\mangoimage.jpg" });
fruits.Add(new Fruit() { FruitName = "Oranges", FruitImage = #"C:\mangoimage.jpg" });
cmb.ItemsSource = fruits;
Then simplify your XAML thus:
<ComboBox x:Name="cmb" HorizontalAlignment="Left" Width="135" Height="22" SelectedItem="{Binding myViewMode}" Margin="5,0,0,0">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FruitName}"/>
<Image Source="{Binding FruitImage}" Height="100"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
In your ItemSource your image should consists as Uri path with BitMapImage Class then only Images are accepted in ItemTemplate in ComboBox
Xaml Code
<ComboBox x:Name="cmb" HorizontalAlignment="Left" Width="135" Height="22"
SelectedItem="{Binding myViewMode}" Margin="5,0,0,0">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="25" Height="25" Source="{Binding FruitName}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Your Model Class
public class Fruit
{
public string FruitName { get; set; }
}
Your ItemSource should Consists as:
fruitCollection.Add(new Fruit() {FruitName= new BitmapImage(new Uri("C:\mangoimage.jpg", UriKind.Relative))});

WPF MVVM Combobox IsEditable="True"

I have this issue, I must use IsEditable="True" in a combobox but when I select an item I get in the text "Travel_order.Model", while if i remove IsEditable="True" I get an item. (see the picture)
How can i resolved ?
this is the code.
<ComboBox x:Name="Cmb_Uti"
ItemsSource="{Binding User_Utilizzatore, Mode=TwoWay}"
SelectedValuePath="Value"
SelectedItem="{Binding SelectUser_Utilizzatore, Mode=TwoWay}"
IsEditable="True"
Grid.Row="2" Grid.Column="3"
HorizontalAlignment="Left" Height="23" Margin="5,17,0,0"
VerticalAlignment="Top" Width="176">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DescUtente, UpdateSourceTrigger=PropertyChanged}" Padding="10,0,0,0"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.Effect>
<DropShadowEffect Color="#FF0A0A0A" Opacity="0.6"/>
</ComboBox.Effect>
</ComboBox>
Public Property User_Utilizzatore As ObservableCollection(Of Model_User_Utilizzatore)
Private _SelectUser_Utilizzatore As Model_User_Utilizzatore
Public Property SelectUser_Utilizzatore As Model_User_Utilizzatore
Get
Return _SelectUser_Utilizzatore
End Get
Set(value As Model_User_Utilizzatore)
_SelectUser_Utilizzatore = value
OnPropertyChanged("SelectUser_Utilizzatore")
End Set
End Property
You don't have to define ItemTemplate as textBlock. When you do that and add IsEditable = true, the item will become a textbox.
To Avoid this, just use DisplayMemberPath:
<ComboBox x:Name="Cmb_Uti"
ItemsSource="{Binding User_Utilizzatore, Mode=TwoWay}"
SelectedValuePath="Value"
SelectedItem="{Binding SelectUser_Utilizzatore, Mode=TwoWay}"
IsEditable="True"
DisplayMemberPath="DescUtente"
Grid.Row="2" Grid.Column="3"
HorizontalAlignment="Left" Height="23" Margin="5,17,0,0"
VerticalAlignment="Top" Width="176">
<ComboBox.Effect>
<DropShadowEffect Color="#FF0A0A0A" Opacity="0.6"/>
</ComboBox.Effect>
</ComboBox>
Found a neat little workaround: You can bind the IsEditable property to a bool and switch it to false when the bound SelectedItem is set. Works just as wanted...
<ComboBox ItemsSource="{Binding YourSource}"
IsReadOnly="True"
SelectedItem="{Binding YourSelectedItem}"
Text="Please select..."
IsEditable="{Binding ComboBoxEditable}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding ToWhatever}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
and the code:
private Object _YourSelectedItem;
public Object YourSelectedItem { get { return _YourSelectedItem; } set { YourSelectedItem = value); ComboBoxEditable = false; } }
private Boolean _ComboBoxEditable;
public Boolean ComboBoxEditable { get { return _ComboBoxEditable; } set { _ComboBoxEditable = value); } }

Selectionchanged event firing for every row

I am using a cascading comboboxes inside datagrid.I am able to get the datas based on selectionchanged but that event is firing for every row.
Here is my code:
<sdk:datagridtemplatecolumn header="Category" width="110">
<sdk:datagridtemplatecolumn.celltemplate>
<datatemplate>
<combobox foreground="Black" height="30" isenabled="{Binding Source={StaticResource EffortViewModel}, Path=ComboBoxStatus}" itemssource="{Binding Source={StaticResource EffortViewModel},Path=ProjTypeTaskCtry}" displaymemberpath="TaskCtgyName" selectedvaluepath="TaskCtgy_FK" selectedvalue="{Binding Source={StaticResource EffortViewModel}, Path=TaskCtgy_FKField,Mode=TwoWay}" />
</datatemplate>
</sdk:datagridtemplatecolumn.celltemplate>
</sdk:datagridtemplatecolumn>
<sdk:datagridtemplatecolumn header="SubCategory" width="110">
<sdk:datagridtemplatecolumn.celltemplate>
<datatemplate>
<combobox foreground="Black" height="30" isenabled="{Binding Source={StaticResource EffortViewModel}, Path=ComboBoxStatus}" itemssource="{Binding Source={StaticResource EffortViewModel},Path=SubCtry,Mode=OneWay}" displaymemberpath="TaskSubCtgyName" selectedvaluepath="{Binding TaskSubCtgy_PK, Mode=TwoWay}" selectedvalue="{Binding TaskSubCtgy_FKField,Mode=OneTime}" selectedindex="{Binding TaskSubCtgy_FKField}" />
</datatemplate>
</sdk:datagridtemplatecolumn.celltemplate>
</sdk:datagridtemplatecolumn>
I had the same problem in Silverlight MVVM. I found a solution for this from somewhere. Hope this will help you.
namespace Test
{
public class ComboBoxSelectionChange : TriggerAction<DependencyObject>
{
public ComboBoxSelectionChange()
{
}
public ComboBox DayComboBox
{
get { return (ComboBox)GetValue(DayComboBoxProperty); }
set { SetValue(DayComboBoxProperty, value); }
}
public static readonly DependencyProperty DayComboBoxProperty =
DependencyProperty.Register("DayComboBox",
typeof(ComboBox),
typeof(ComboBoxSelectionChange),
new PropertyMetadata(null, OnDayComboBoxPropertyChanged));
private static void OnDayComboBoxPropertyChanged(DependencyObjectd, DependencyPropertyChangedEventArgs e)
{
var source = d as ComboBoxSelectionChange;
if (source != null)
{
var value = (ComboBox)e.NewValue;
}
}
protected override void Invoke(object o)
{
if (this.DayComboBox != null)
{
//this method will execute when the selection is changed
}
}
}
}
Use the Test namespace in Usercontrol assembly
xmlns:Common="clr-namespace:Test"
<UserControl.Resources>
<Common:ComboBoxSelectionChange x:Name="ComboBoxItem"/>
</UserControl.Resources>
<DataTemplate x:Key="EditMondayDataTemplate">
<ComboBox x:Name="cmbMonday" Height="26" Margin="3" ItemsSource="{Binding Monday,Mode=OneTime}" DisplayMemberPath="displayText" SelectedItem="{Binding Path=MonSelected,Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="80">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<Common:ComboBoxSelectionChange DayComboBox="{Binding ElementName=cmbMonday}" TextParam="Monday"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</DataTemplate>

Resources