Binding Combobox SelectedValue to Textbox - wpf

I have a TextBox and a ComboBox. I want to bind ComboBox the selected value to text in the TextBox.
Please help.
Thanks

<ComboBox x:Name="MyComboBox">
<ComboBoxItem>12</ComboBoxItem>
<ComboBoxItem>13</ComboBoxItem>
<ComboBoxItem>14</ComboBoxItem>
<ComboBoxItem>15</ComboBoxItem>
</ComboBox>
<TextBox Text="{Binding Path=SelectedValue.Content, ElementName=MyComboBox}" />
Since the items in the ComboBox are of type ComboBoxItem, I used the Content property to get the real value. You should use whatever property exposed by the objects in your ComboBox (use nothing if it already is a list of strings).

This is for a listbox, not a combobox, but it should be pretty much the same code:
private void *lstProducts*_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
*currentlabel*.Content = *lstProducts*.SelectedValue.ToString();
}
The italicized bits are the names of the control.
Hope it helps...

Related

Wpf clear disabled TextBox.Text when there is validation error

I have three textboxes with text binded to three properties.
I need to disable two textboxes, when i type in the third one. And i have to clear the value of the disabled textboxes.
`
<TextBox Text="{Binding TextProperty1}" IsEnabled="{Binding T1Enabled}"/>
<TextBox Text="{Binding TextProperty2}" IsEnabled="{Binding T2Enabled}"/>
<TextBox Text="{Binding TextProperty3}" IsEnabled="{Binding T3Enabled}"/>
`
T1-3Enabled is a property with only getters, and i raise propertychanged on textboxes' lost focus command. When these properties refreshed i clear the binded propertes of the disabled textboxes (TextProperty1-3).
But, when some of the disabled textboxes have validation errors, the source property is cleared, but the textbox.text is not.
How can i solve this in mvvm? I dont want to set textbox.text.
I hope the problem is clear.
Thanks for any help or other solution.
I solved the problem with a derived textbox class.
public class MyTextBox : TextBox
{
public MyTextBox()
{
IsEnabledChanged += MyTextBox_IsEnabledChanged;
}
private void MyTextBox_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if(e.NewValue is bool)
if (!(bool)e.NewValue)
Text = string.Empty;
}
}

Binding Visibility to Yes/No ComboBox with Converters

I've got a form that gets given a datarow from a dataset to bind all its elements. One of them is a bool, but I want that bool to be represented by by a Yes/No combo box. So I did this and it works nicely.
I also want to bind the visibility of a couple elements to this bool field. When the form loads, the initial setting of the visibility works. When I change the combobox selection, the ConvertBack() method of the ComboBox gets called (i.e. it's setting the bound value). But the other elements that have their visibility bound to that same field don't get updated. I set breakpoints in the Conversion methods and they never get called like they do when the form loads.
Here's the relevant XAML:
<ComboBox SelectedIndex="{Binding Path=[Adequate], Converter={StaticResource b2iConverter}}" Name="cb_Adequate" >
<ComboBoxItem>Yes</ComboBoxItem>
<ComboBoxItem>No</ComboBoxItem>
</ComboBox>
<Label Content="Reason:"
VerticalAlignment="Center"
Visibility="{Binding Path=[Adequate],
Converter={StaticResource b2vConverterInverse}}"/>
<TextBox Text="{Binding Path=[NotAdequateReason]}"
Visibility="{Binding Path=[Adequate],
Converter={StaticResource b2vConverterInverse}}"/>
"Adequate" is the bool field
b2iConverter is just booleanToIndexConverter (from the above link)
b2vConverterInverse is just an inverted boolean to visibility converter (I want the label and textbox shown when Adequate is FALSE or 0).
Thanks for any help. I can post more code if needed, I figure the problem is in the XAML...
EDIT: Apparently it's not possible with XAML (see Greg's post below), so I just do it in code:
private void cb_Adequate_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Visibility vis = (cb_Adequate.SelectedItem as ComboBoxItem).Content.ToString() == "Yes" ? Visibility.Collapsed : Visibility.Visible;
label_Reason.Visibility = tb_AdequateDesc.Visibility = vis;
}
If you want your UI elements to change state when a data property changes, you need to implement INotifyPropertyChanged on your data class.
This means that you can't use the DataRow for your purposes. You'll have to create a new class, then at run time populate it with values from the DataRow and then bind that object to your view.

How to Aceess cell level ComboBox in WPF DataGrid?

My data grid column template which has combo box in it is as below .
<my:DataGridTemplateColumn x:Name="dgColReferece" Header="References" >
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cmbReferece_SRV" Loaded="cmbReferece_SRV_Loaded" Width="160" SelectionChanged="cmbReferece_SRV_SelectionChanged"
IsTextSearchEnabled="True" SelectedValue="{Binding Reference, Mode=TwoWay}" >
</ComboBox>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
All combo boxes have Add new as one item in them which has value -2. When the user clicks on add new a new item added to the database and should be rebound to all comboboxes in the grid.
Below is my code behind for SelectionChanged
private void cmbReferece_SRV_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ ComboBox objComboBox = (ComboBox)sender;
if (objComboBox.SelectedValue.ToString() == "<-- Add New -->")
{
//code for saving new item entered by user to database
if (IsSaved)
{
DataSet dsReference = (DataSet)GetFStdReference();
CommonCalls.BindDropDownList(cmbReferece_SRV, dsReference.Tables[0], "Reference", "Reference");
}
objComboBox.SelectedValue = -1;
}
}
This will bind the new item only to the combobox in the selected row. But I need it to bind to all comboboxes? How Can I do this. I am new to wpf and binding stuffs > How can i Proceed ?
You code above is a little confusing. Can you explain more what are you trying to do. I can see several deviations from the proper WPF programming practises esp. regarding using comboboxes in datagrid.
E.g.
Why are you using events like cmbReferece_SRV_SelectionChanged and not using SelectedValue and SelectedValuePath via Converter?
Also what is your ComboBox.ItemsSource? DataTable? List of objects?
Why are you setting ItemsSource of a ComboBox in its own SelectionChanged event, which is counterproductive.
I understand that you are new to WPF, so may be if you explain your problem to me, I can suggest some useful WPF practises of coding for your issue.

WPF Listbox - change itemsource of control in datatemplate

I have a listbox with a datatemplate that holds a number of controls bound to my collection.
What i want is to change the itemsource for one of these comboboxes dependant upon the value selected in one of the other comboboxes in the same row. I don't want to change the itemsource for all corresponding comboboxes within the rest of the rows in the listbox.
How do I get a handle on the control in the selected row only.
Is this something that is easier to try doing witht the WPF datagrid?
Thanks.
This is actually easier with the ListBox, as the DataTemplate defines all the controls for a row.
I think the easiest way is to use a converter on a binding. You will bind your second ComboBox's ItemsSource to the SelectedItem of the first ComboBox:
<myNamespace:MyConverter x:Key="sourceConverter" />
<StackPanel Orientation="Horizontal>
<ComboBox x:Name="cbo1" ... />
...
<ComboBox ItemsSource="{Binding SelectedItem, ElementName=cbo1, Converter={StaticResource sourceConverter}}" ... />
...
</StackPanel>
Note that if you need additional information from the DataContext of the Row, you can make it a MultiBinding and an IMultiValueConverter, and pass in the DataContext easily by doing:
<MultiBinding Converter="{StaticResource sourceConverter}">
<Binding />
<Binding Path="SelectedItem", ElementName="cbo1" />
</MultiBinding>
Then, in your converter class, do whatever it is you have to do in order to get the correct items source.
Get the SelectionChanged event of that paticular combobox and set the Itemsource of the other combobox inside the event.
private void cmb1SelectionChanged(object sender, SelectionChangedEventArgs e)
{
cmboBox2.ItemSource = yourItemSource;
}
Also it is better to get the SelectionChaged event of listview and handle it.
private void OnlistviewSelectionChanged( object sender, SelectionChangedEventArgs e )
{
// Handles the selection changed event so that it will not reflect to other user controls.
e.Handled = true;
}

WPF Listview SelectionChanged event

I have a ListView binding to an ItemsSource and the SelectionChanged event is firing on the load/databound events? I assume that it is because a 'default' items ie index 0 is selected.
How can I disable this?
The listView should not fire the SelectionChange if you only set the ItemsSource property. However if you bind the SelectedIndex property to a property of your dataContext object the selection will move to the index that is specified by the binded property.
this doesn't fires the Selector_OnSelectionChanged event when the page loads:
<ListView SelectionChanged="Selector_OnSelectionChanged"
ItemsSource="{Binding Path=Items}"
></ListView>
but this does:
<ListView SelectionChanged="Selector_OnSelectionChanged"
SelectedIndex="{Binding Path=SelectedIndexValue}"
ItemsSource="{Binding Path=Items}"
></ListView>
because the SelectedIndex is set to the SelecteIndexValue through binding.
To avoid this and still keep the bindings in your markup set the SelectedIndexValue of your dataContext object to -1 before binding (Before InitializeComponent() is called in your form constructor).
Hope this helps.
thanks for the responses.
When I put a breakpoint on the SelectionChanged event, it breaks proceedings there before the screen is fully loaded. You will also see that the first row is 'selected' afterwards on the list. I am not binding to a SelectedIndexValue as you can see in the code. The DataContext for the list is a ReadonlyCollection
In my SelectionChanged event as you can see I notify other objects to be loaded with data relating to the selected item. I only want this to happen when one is selected but not a default one to be set. I have to of these ListViews representing similar data but on loaded none must have an item selected.
I have noticed that the default Selected index is set to -1 on the properties window for the Listview. I can even set this is code on the List_Loaded event, but by then the first SelectionChanged has happened already.
<ListView PreviewMouseDown="ActiveCasesView_MouseDown" x:Name="ActiveCasesView"
DataContext="{StaticResource ActiveCasesViewSource}"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource CasesItemTemplate}"
SelectionMode="Single"
SelectionChanged="ActiveCasesView_SelectionChanged"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto" >
</ListView>
private void ActiveCasesView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (mouseClicked)
if (e.AddedItems.Count > 0)
App.Messenger.NotifyColleagues(App.MSG_SELECT_ACTIVE_CASE, ((CaseViewModel)ActiveCasesView.SelectedItem).CaseNumber);
}
I added the PreviewMouseDown to set an indicator that I have clicked on the listview in the SelectionChanged event. This does help but I'm not convinced that its the best solution.
Thanks
Petrus
I don't know if you still need help with this, but I solved this problem by making a variable that tracks the selectedindex, in my case -- when initially bound it's always 0 so it's a little easier for me to do, however if you inform the viewmodel of the appropriate index, I simply added a
ComboBox box = e.OriginalSource as ComboBox;
if (_previousIndex == cb.SelectedIndex) return;
//do stuff you need to do with a new SelectedIndex
You can try to set the SelectedIndex property to -1 in your binding but this also is not an elegant solution.
<ListView PreviewMouseDown="ActiveCasesView_MouseDown" x:Name="ActiveCasesView"
DataContext="{StaticResource ActiveCasesViewSource}"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource CasesItemTemplate}"
SelectionMode="Single"
SelectionChanged="ActiveCasesView_SelectionChanged"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
**SelectedIndex="-1"**>
</ListView>
I tried to reproduce your behavior but without success.
What is the Type of the ItemsSource collection that you are binding to?
you can use window loaded event to block the action
bool loaded = false;
window.Loaded += new RoutedEventHandler(MainWindow_Loaded);
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
windowLoaded = true;
}
private void ActiveCasesView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if(!loaded)
return ;
//do actions here ....
}

Resources