Wpf clear disabled TextBox.Text when there is validation error - wpf

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;
}
}

Related

Mark as read only all controls WPF

OK this is an interesting one.
I have a wpf application with tabs. What I want to do is have a DB setting that turns off the ability to edit all textboxs. What I was thinking was to bring in the value, if the value is true then I would turn all the text boxes to read only.
I have seen this example:
private void DisableControls(Control con)
{
foreach (Control c in controls)
{
DisableControls(c);
}
con.Enabled = false;
}
However I get red squiggly line under controls and again under Enabled. I will preface this by saying I am new to WPF.
Does anyone have a solution to this (or even a better way) any pointing in the right way would help.
Create a view model that wraps your database models
public class MyViewModel : INotifyPropertyChanged
{
public bool MakeReadOnly {get;set;}
}
Reference your view model in the View
<Window x:Class="Example.MainWindow"
...
xmlns:local="clr-namespace:Example"
...>
<Window.Resources>
<local:MyViewModel x:Key="ViewModel"/>
</Window.Resources>
...
</Window>
Bind the boolean value to your textboxes IsReadOnly property
<TextBox x:Name="FirstName" IsReadOnly="{Binding MakeReadOnly">
The user may not modify the contents of this TextBox if marked as readonly
</TextBox>
<TextBox x:Name="LastName" IsReadOnly="{Binding MakeReadOnly">
The user may not modify the contents of this TextBox if marked as readonly
</TextBox>
More on View Models here
Hope this helps!

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 make TextChanged happen for copy/paste for TextBox in Silverlight?

For silverlight control TextBox, when copy/paste content for TextBox Text property, TextChanged Event not happening.
How to make paste same as typing for Text in TextBox?
Sorry, I can't reproduce this.
I used the following XAML
<StackPanel>
<TextBox TextChanged="TextBox_TextChanged" />
<TextBlock x:Name="tbk" />
</StackPanel>
and the following event handler
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
tbk.Text += "X";
}
Every time I typed in the TextBox or pasted text into it, the TextBlock gained another X.

XAML ReadOnly ComboBox

To set up a ReadOnly ComboBox in XAML (WPF), you have to set up a ComboBox and a TextBox showing only one of them according to a pair of properties IsReadOnly/IsEditable that must exist on your ViewModel. Note that on this sample "UserNVL" must exist in the resources and it should be a NameValueList collection that allows us to convert ID to names. In this case the RecipientID is the key for a user name. Note also the VisibilityConverter must also exist in the resources and it's a standard BooleanToVisibilityConverter.
Gosh! This was so hard to find I had to made it myself. This allows the user the select the content of the text box. No way a disabled ComboBox would ever allow you to do it.
There are two properties named IsHitTestVisible & IsTabVisible. the former makes the control deaf to mouse events and the latter to keyboard events.
This could help you as it would not give the disabled look to your combo box but you will succeed in making a read only combo box..
Source :-
http://www.telerik.com/community/forums/wpf/combobox/isreadonly-does-seem-to-work.aspx
Why not just set IsEnabled=false?
<DockPanel>
<TextBlock Text="Recipient" Margin="6,9,3,6" HorizontalAlignment="Right"/>
<ComboBox
x:Name="RecipientID"
ItemsSource="{Binding Source={StaticResource UserNVL}}"
DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding Path=RecipientID}"
Height="20"
Margin="6,6,0,6"
MinWidth="200"
HorizontalAlignment="Left"
IsEditable ="True"
Visibility="{Binding Path=IsEditable, Converter={StaticResource VisibilityConverter}}"/>
<TextBox
x:Name="RecipientName"
Text="{Binding ElementName=RecipientID, Path=Text}"
Margin="6,6,0,6"
MinWidth="200"
HorizontalAlignment="Left"
Style="{StaticResource textBoxInError}"
Visibility="{Binding Path=IsReadOnly, Converter={StaticResource VisibilityConverter}}"/>
</DockPanel>
I think that you will find it much easier and practical to create a class to extend the ComboBox class in this very simple manner:
override the OnSelectionChanged method of the Combobox to check the property IsReadOnly before to allow base.OnSelectionChanged(e) to run.
That way you just have to set ComboBox.IsReadOnly property to True. No big XAML to write everywhere...
Here is a custom ComboBox subclass that gives the read only behaviour I needed for my scenario:
public class ReadOnlyComboBox : ComboBox
{
static ReadOnlyComboBox()
{
IsDropDownOpenProperty.OverrideMetadata(typeof(ReadOnlyComboBox), new FrameworkPropertyMetadata(
propertyChangedCallback: delegate { },
coerceValueCallback: (d, value) =>
{
if (((ReadOnlyComboBox)d).IsReadOnly)
{
// Prohibit opening the drop down when read only.
return false;
}
return value;
}));
IsReadOnlyProperty.OverrideMetadata(typeof(ReadOnlyComboBox), new FrameworkPropertyMetadata(
propertyChangedCallback: (d, e) =>
{
// When setting "read only" to false, close the drop down.
if (e.NewValue is true)
{
((ReadOnlyComboBox)d).IsDropDownOpen = false;
}
}));
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
if (IsReadOnly)
{
// Disallow changing the selection when read only.
e.Handled = true;
return;
}
base.OnSelectionChanged(e);
}
}
Points about this approach:
Doesn't break any existing styles applied to the element, unlike an approach that introduces additional UI elements.
Doesn't break input focus while read only. You can still tab into and click to focus this element. This is more accessible, which is a concern in my scenario.
The UI element doesn't, but default, look any different when read only. If you need that, you would have to apply relevant styles to make it so.
If IsEnabled is set to false, Combobox value is nearly not readable. What I found as suitable solution is:
combobox and textbox (formated as readonly) are in the same grid position
combobox spans to next column to gain additional 15 width so dropdown button is visible
textbox.IsVisible is bound to combobox.IsEnabled with bool to visibility converter.
textbox.Text is bound to combobox.SelectedItem (in my case it is strongly typed so I actually bound into .DisplayText of it)

Binding Combobox SelectedValue to Textbox

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...

Resources