How to set ComboBox selected item in ModelView? - c#

I have static combo box items. My XAML look like this:
<ComboBox x:Name="comboBox" SelectedItem="{Binding MySelectedItem}" HorizontalAlignment="Left" Margin="58,7,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem Name="cbi1">Item 1</ComboBoxItem>
<ComboBoxItem Name="cbi2">Item 2</ComboBoxItem>
<ComboBoxItem Name="cbi3">Item 3</ComboBoxItem>
</ComboBox>
Model View:
// How to set initial value here or in constructor?
private ComboBoxItem _mySelectedItem;
public ComboBoxItem MySelectedItem
{
get
{
return _mySelectedItem;
}
set
{
Console.WriteLine("Value = {0}", (value as ComboBoxItem).Name);
}
}
How can I set selected item of combo box having Name? I would like to set selected item in MV constructor, after reading from persistent storage.

What you need to add is the SelectedValuePath="Name" to your combo box. Then in your ViewModel constructor, add your startup Item like this. I made my SelectedDropDown property a string, not sure if you have to have it as a ComboBoxItem in your case.
public MainFormViewModel()
{
SelectedDropDown = "cbi1";
}
private string _SelectedDropDown;
public string SelectedDropDown
{
get { return _SelectedDropDown; }
set { _SelectedDropDown = value; NotifyPropertyChanged("SelectedDropDown"); }
}
Here is the ComboBox Code, tested it and it works fine.
<ComboBox x:Name="comboBox1" HorizontalAlignment="Left" Margin="114,213,0,0" SelectedValuePath="Name" SelectedValue="{Binding SelectedDropDown }" VerticalAlignment="Top" Width="120" Grid.Column="1">
<ComboBoxItem Name="cbi1">Item 1</ComboBoxItem>
<ComboBoxItem Name="cbi2">Item 2</ComboBoxItem>
<ComboBoxItem Name="cbi3">Item 3</ComboBoxItem>
</ComboBox>

You must create your collection from ViewModel in order to use SelectedItem
*.xaml (View)
<ComboBox x:Name="comboBox" SelectedValue="{Binding MySelectedItem, Mode=TwoWay}" ItemsSource="{Binding MyCollection}" Height="25"/>
*.cs (ViewModel)
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
for (int i = 0; i < 10; i++)
{
MyCollection.Add("Item " + i);
}
MySelectedItem = "Item 2";
}
private ObservableCollection<string> myCollection = new ObservableCollection<string>();
public ObservableCollection<string> MyCollection
{
get
{
return myCollection;
}
set
{
myCollection = value;
NotifyPropertyChanged("MyCollection");
}
}
private string _mySelectedItem;
public string MySelectedItem
{
get
{
return _mySelectedItem;
}
set
{
_mySelectedItem = value;
NotifyPropertyChanged("MySelectedItem");
}
}
//NotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}

Related

Reset the combobox iwhen a button is clicked

I have combo box with some contents. I want it to get reset to the first item when a button is clicked.
WPF and C#.net is used.
<ComboBox x:Name="categoriesComboBox" Height="40" Grid.Row="0" ItemsSource="{Binding Categories}" SelectedValue="{Binding SelectedCategory}"
VerticalContentAlignment="Center" Background="{StaticResource InventoryManagementAlternatingRowBackground}" BorderBrush="Transparent">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding CategoryName}" FontSize="20" Margin="3,0" FontFamily="Malgun Gothic" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
private void ClearFilter_Click(object sender, RoutedEventArgs e)
{
SearchFiltersControl s = new SearchFiltersControl();
s.ResetCategoryComboBox();
}
public void ResetCategoryComboBox()
{
categoriesComboBox.SelectedIndex = -1;
}
I am adding the ViewModel. Add I want to how to use this View Model to reset the ComboBox:
using System;
using System.Collections.ObjectModel;
namespace NextGen.Optik.UI.Presentation.ViewModels.Inventory.Contracts
{
public class SearchFilterCategoryViewModel : ViewModelBase
{
private int _categoryId;
public int CategoryId
{
get => _categoryId;
set
{
if (_categoryId != value)
{
_categoryId = value;
RaisePropertyChangedEvent();
}
}
}
private string _categoryName;
public string CategoryName
{
get => _categoryName;
set
{
if (_categoryName != value)
{
_categoryName = value;
RaisePropertyChangedEvent();
}
}
}
private ObservableCollection<SearchFilterViewModel> _filters = new ObservableCollection<SearchFilterViewModel>();
public ObservableCollection<SearchFilterViewModel> Filters
{
get => _filters;
set
{
if (_filters != value)
{
_filters = value;
RaisePropertyChangedEvent();
}
}
}
}
}
Expected Result: When the reset button is clicked, first item has to be selected.
Actual Results: Not getting reset.

Databinding controls to properties of ComboBoxItem

I am trying to have a WPF window with a ComboBox, with which you select an item, and then use TextBoxes below to edit the properties of the currently selected item, eg Name and Age.
How do I do this with Data Binding, ie. to bind the name TextBox to the Name property of the currently selected item in the ComboBox?
My XAML is
<Window x:Class="BindingTest001.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
>
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,75,0,0" TextWrapping="Wrap" Text="{Binding Path=CURR.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="497"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,103,0,0" TextWrapping="Wrap" Text="{Binding Path=CURR.Age, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
<ComboBox ItemsSource="{Binding Path=MO}" SelectedValue="{Binding Path=CURR, Mode=TwoWay}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="497" Name="MyComboBox"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="322,181,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
Where my code behind is
public partial class MainWindow : Window
{
ObservableCollection<myObj> mo;
public MainWindow()
{
InitializeComponent();
mo = new ObservableCollection<myObj>();
mo.Add(new myObj("Test1", 2));
var ct = new MainWindowDatacontext(this);
this.DataContext = ct;
this.MyComboBox.SelectedIndex = 0;
}
private class MainWindowDatacontext : INotifyPropertyChanged
{
MainWindow parent;
myObj curr;
public MainWindowDatacontext(MainWindow mainWindow)
{
this.parent = mainWindow;
}
public ObservableCollection<myObj> MO
{
get
{
return parent.mo;
}
}
public myObj CURR
{
get
{
return curr;
}
set
{
this.curr = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void executePropertyChanged(string s)
{
if(PropertyChanged!=null)
{
PropertyChanged(this.parent, new PropertyChangedEventArgs(s));
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
mo.Add(new myObj("Test2", 10));
}
}
But the Data Binding only works for the ComboBox- the TextBoxes never bind to anything.
myObj is very simple:
public class myObj : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void propertyChanged(string s)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(s));
}
}
string name;
public string Name
{
get { return name; }
set {
name = value;
propertyChanged("Name");
}
}
int age;
public myObj(string p1, int p2)
{
this.name = p1;
this.age = p2;
}
public int Age
{
get { return age; }
set { age = value;
propertyChanged("Age");
}
}
public override string ToString()
{
return String.Format("{0}, {1}", name, age);
}
}
Because you want to bind to the property of another element in your application you should use Binding.ElementName Property. So Change your TextBox's Binding like this:
Text="{Binding SelectedItem.Name, ElementName=MyComboBox,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Text="{Binding SelectedItem.Age, ElementName=MyComboBox,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
You are using SelectedValue in your ComboBox rather than SelectedItem.
The former is for when you want to select one property out of the object in the ComboBox's ItemsSource rather than the object itself. It's used in conjunction with the SelectedValuePath.
As you want to edit more than one property of the selected item you need to use SelectedItem.

Data binding WPF XAML

Hello I am new to WPF and I am not sure how to do the data binding and the code behind to get my textbox and button to be enabled and disabled.
If you could show me how to get it to work in the example below it would help me out in my project.
XAML
<ComboBox Name="ComboBoxA"
Margin="5"
SelectedIndex="0" SelectionChanged="ComboBoxA_SelectionChanged" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" Height="Auto" Margin="5" />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
<ComboBoxItem Content="Option1" Width="72" />
<ComboBoxItem Content="Option2" Width="72" />
<ComboBoxItem Content="Option3" Width="72" />
</ComboBox>
<TextBox Name="TextBoxA"
Margin="5"
Width="200"
IsEnabled="{Binding TextBoxEnabled}" />
<Button Name="ButtonA"
Content="Next"
HorizontalAlignment="left"
Margin="5"
IsEnabled="{Binding ButtonEnabled} />
C#
private void ComboBoxA_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
TextBoxA = new TextBox();
ButtonA = new Button();
if (ComboBoxAfterProcessing.SelectedIndex == 0)
{
TextBoxA.IsEnabled = false;
ButtonA.IsEnabled = false;
}
else if (ComboBoxAfterProcessing.SelectedIndex == 1)
{
TextBoxA.IsEnabled = true;
ButtonA.IsEnabled = true;
}
else if (ComboBoxAfterProcessing.SelectedIndex == 2)
{
TextBoxA.IsEnabled = true;
ButtonA.IsEnabled = true;
}
}
Write a class as follows which shall look like below
public class ViewMole:INotifyPropertyChanged
{
public ViewMole()
{
ListValues = new List<string>() { "Option1", "Option2", "Option3", "Option4",
"Option5" };
}
public ICommand Click
{
get
{
return new RelayCommand();
}
}
public List<string> ListValues
{
get;
set;
}
string a;
public string A
{
get
{
return a;
}
set
{
a = value;
RaisePropertyChanged("A");
}
}
int index=0;
public int SelectedIndex
{
get
{
return index;
}
set
{
index = value;
RaisePropertyChanged("SelectedIndex");
A = ListValues[index];
if (index == 0)
{
IsEnabled = false;
}
else
{
IsEnabled = true;
}
}
}
bool isEnabled;
public bool IsEnabled
{
get
{
return isEnabled;
}
set
{
isEnabled = value;
RaisePropertyChanged("IsEnabled");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Write another class which implements ICommand as below. This is to handel button click events
public class RelayCommand : ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
MessageBox.Show("Button cliked");
}
}
Change your Xaml below
<ComboBox Name="ComboBoxA" SelectedIndex="{Binding SelectedIndex, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding ListValues}"/>
<TextBox Name="TextBoxA" Margin="5" Width="200" Text="{Binding A}" IsEnabled="{Binding IsEnabled}"/>
<Button Name="ButtonA" Content="Next" HorizontalAlignment="left" Margin="5" Command="{Binding Click}" IsEnabled="{Binding IsEnabled}"/>
In Xmal.cs set the data Context as beolw
public MainWindow()
{
InitializeComponent();
DataContext = new ViewMole();
}
Refer the below links to understand why INotifyPropertyChanged and ICommand has to be used
http://wpftutorial.net/INotifyPropertyChanged.html
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
http://msdn.microsoft.com/en-us/library/system.windows.input.icommand.aspx
you can binding your textbox and button's IsEnabe Property to the Combox's SelectedIndex
Property and you neednot response to ComboBoxA_SelectionChanged Event. in order to let the
SelectedIndex change your button and textBox's IsEnabe you need a convetor in your binding
for example:

How to set combox item visibility?

i have 2 WPF comboboxes(comboboxA, comboboxB)with identical combobox item(Apple & Orange). Let say i select "Apple" in the comboboxA, then the "Apple" need to be hidden in the comboxB. If i go back to comboxA and select "Orange", "Apple" will be visible and "Orange" need to be hidden. How can i achieve that using C#?
code snippet for xaml:
<ComboBox Name="comboboxA" >
<ComboBoxItem Content="Apple" Name="AppleA"></ComboBoxItem>
<ComboBoxItem Content="Orange" Name="OrangeA"></ComboBoxItem>
</ComboBox>
<ComboBox Name="comboboxB" >
<ComboBoxItem Content="Apple" Name="AppleB"></ComboBoxItem>
<ComboBoxItem Content="Orange" Name="OrangeB"></ComboBoxItem>
</ComboBox>
You can use the Method that sa_ddam213 mentioned, or you can just brute force it in the SelectionChanged Event like so.
private void comboboxA_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
for (int i = 0; i <= comboboxB.Items.Count -1; i++)
{
if (((ComboBoxItem)(comboboxB.Items[i])).Content.ToString() == ((ComboBoxItem)comboboxA.SelectedItem).Content.ToString())
{
((ComboBoxItem)(comboboxB.Items[i])).Visibility = System.Windows.Visibility.Collapsed;
}
else
((ComboBoxItem)(comboboxB.Items[i])).Visibility = System.Windows.Visibility.Visible;
}
}
Maybe just filtering the selected item from list
<Window x:Class="WpfApplication6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Name="UI">
<Grid>
<ComboBox ItemsSource="{Binding ElementName=UI,Path=YourCollection}" SelectedItem="{Binding ElementName=UI,Path=SelectedItem}" Height="23" HorizontalAlignment="Left" Margin="65,61,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" />
<ComboBox ItemsSource="{Binding ElementName=UI, Path=FilteredCollection}" Height="23" HorizontalAlignment="Left" Margin="223,61,0,0" Name="comboBox2" VerticalAlignment="Top" Width="120" />
</Grid>
</Window>
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string _selectedItem;
private ObservableCollection<string> _yourCollection = new ObservableCollection<string>();
public MainWindow()
{
InitializeComponent();
YourCollection.Add("Apple");
YourCollection.Add("Banana");
YourCollection.Add("Pear");
YourCollection.Add("Orange");
NotifyPropertyChanged("FilteredCollection");
}
// Collection Fro ComboBox A
public ObservableCollection<string> YourCollection
{
get { return _yourCollection; }
set { _yourCollection = value; }
}
// ComboBox A selected Item
public string SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
// Notify the the filter collection has changed
NotifyPropertyChanged("FilteredCollection");
}
}
// Collection to show in ComboBox B
public List<string> FilteredCollection
{
// Remove the selected Item
get { return _yourCollection.Where(s => !s.Equals(_selectedItem)).ToList(); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Or do you need this to work both ways

Binding to a WPF combo box in a list view (2-way)

I have this problem of having to bind the selected value of a combo box embedded inside a list view. I have no trouble in displaying items in the combo box. However, I wish I had a way to dictate what the combo box should display (from among the items that it holds) on the click of a button. I think there are several posts on this issue, however, I am not able to get exactly what I want. Here is my code.
XAML:
<Grid>
<StackPanel Orientation="Vertical">
<ListView
x:Name="OptionsListView"
ItemsSource="{Binding MyObjectCollection}">
<ListView.Resources>
<DataTemplate x:Key="comboBoxTemplate">
<ComboBox
Margin="0,3"
x:Name="MyTypeComboBox"
SelectedValue="{Binding Path=SelectedType, Mode=TwoWay}">
<ComboBoxItem Content="ABC"/>
<ComboBoxItem Content="DEF"/>
<ComboBoxItem Content="XYZ"/>
</ComboBox>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="Text-Sample"
Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Combo-Sample"
Width="100"
CellTemplate="{StaticResource comboBoxTemplate}" />
</GridView>
</ListView.View>
</ListView>
<Button Click="Button_Click">Click Me!</Button>
</StackPanel>
</Grid>
C# Code Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
OptionsListView.DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//Something here that dictates what should be displayed in the combo box
}
List<MyObject> myObjectCollection = new List<MyObject>();
public List<MyObject> MyObjectCollection
{
get
{
myObjectCollection.Add(new MyObject("One"));
myObjectCollection.Add(new MyObject("Two"));
return myObjectCollection;
}
}
}
public class MyObject : INotifyPropertyChanged
{
private string _name;
public MyObject(string name)
{
// TODO: Complete member initialization
this._name = name;
}
public string Name
{
get
{
return _name;
}
}
string selectedType = string.Empty;
public string SelectedType
{
get
{
return selectedType;
}
set
{
selectedType = value;
this.NotifyChange("SelectedType");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyChange(params object[] properties)
{
if (PropertyChanged != null)
{
foreach (string p in properties)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}
#endregion
}
I would be glad if someone could help me crack this..
Thanks
Ram
I'm not sure if I misunderstanding your question. I think your issue is about the reference issue. I changed your code a little and it works when click on the button.
See the code below.
XAML:
<ComboBox Margin="0,3"
x:Name="MyTypeComboBox"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=ListBox},Path=DataContext.Sources}"
SelectedValue="{Binding Path=SelectedType, Mode=TwoWay}">
</ComboBox>
C# code:
private Collection<string> sources = new Collection<string>() { "ABC", "DEF", "XYZ" };
public Collection<string> Sources { get { return sources; } }
private void Button_Click(object sender, RoutedEventArgs e)
{
myObjectCollection[0].SelectedType = Sources[0];
myObjectCollection[1].SelectedType = Sources[2];
}
How about
foreach (ComboBox c in OptionsListView.Items)
{
c.SelectedValue = "Put your value here";
}
This should do the work, if you have other objects than comboboxes inside you can add a
if (c is ComboBox)
to ensure that you are working on the right object

Categories