Basically I have two textboxes which binds to two columns of a ListView. When the user select one row in the ListView, the values will be displayed in the textboxes. This has no problem.
The user can edit the text of one TextBox, the other TextBox is not editable. The text of the second TextBox is based on the text of the first TextBox. For example, the first box is product price in Chinese yuan and second box is product price in British pound. The exchange rate is from setting. The user can only edit value of Chinese yuan, but not British pound. The sold price is initially from database.
My purpose is when the user change the first TextBox, then in the text_changed event, I calculate the value for the second TextBox.
When the end user change selection to the ListView, It seems to me the binding to GoodsSoldPriceCN happened first, then this triggered the text_changed event. In the event handler, I calculate the sold price in pound for the second TextBox and this two-way binding will update source. The problem is this wouldn't update the row the user just selected, but update the row the user previously selected.
So, my question is how can I achieve this requirement.
Two textboxes bind to the selection of a row of a ListView.
The second text box also bind to the text of the first box when the user manually change the text of the first TextBox.
My code is as follows:
XAML
<TextBox Grid.Row="2" Grid.Column="1" HorizontalAlignment="Stretch" Name="GoodsSoldPriceCN" Style="{StaticResource textBoxInError}" TextChanged="GoodsSoldPriceCN_TextChanged">
<TextBox.Text>
<Binding Path="soldpricecn" ConverterCulture="zh-cn">
<Binding.ValidationRules>
<ValidationRules:MoneyValueRule Min="1" Max="100000"></ValidationRules:MoneyValueRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBox Grid.Row="3" Grid.Column="1" HorizontalAlignment="Stretch" Name="GoodsSoldPriceGB" IsEnabled="False" Style="{StaticResource textBoxInError}" Text="{Binding Path=soldpricegb, Converter={StaticResource MoneyValueConverter}, UpdateSourceTrigger=PropertyChanged, ConverterCulture=en-gb}" />
Code
private void GoodsSoldPriceCN_TextChanged(object sender, TextChangedEventArgs e)
{
isDirtyOrder = true;
ListViewItem item = e.OriginalSource as ListViewItem;
try
{
if (!String.IsNullOrEmpty(GoodsSoldPriceCN.Text))
GoodsSoldPriceGB.Text =
(decimal.Parse(GoodsSoldPriceCN.Text) / decimal.Parse (Properties.Settings.Default.ExchangeRate)).ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
...
}
I use Binding.SourceUpdated event instead of TextChanged event and that solve the problem.
Related
I am new to WPF and unable to implement the below scenario :
Three drop down boxes side by side. I have tried using Combo Box. I have tried to explain the problems with the help of an image
Example : (refer image)
I want to select any one - name/school/email. Say I select Name1 , then I should not be able to choose any of the other two dropdowns - School/Email.However, in my implementation I am still able to select values from the other dropdowns as well.
If I change my mind and move to the School dropdown and leave the Name dropdown, the Name dropdown should change the value from Name1(which was selected in Step 1) to Name(which is the title of that button), However, in my implementation both the selections - Name1 and School1 are persisting.
I tried implementing this with the help of these two posts and the nearest I could get was as I mentioned in the example above : How to display default text "--Select Team --" in combo box on pageload in WPF? and Name on combobox in WPF
PS : Name/School/ Email are NOT watermarks. They are the title of the button which is there by default as you land on that page/window.
Any help/resources is appreciated.
You can use the selection changed event of the comboboxes to set the text of each if you are going to code in code-behind:
<StackPanel Grid.Row="1" Orientation="Horizontal">
<ComboBox x:Name="cmbName" ItemsSource="{Binding NameList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="Name"
SelectionChanged="cmbName_SelectionChanged" MinWidth="80" Margin="10" IsEditable="True" IsReadOnly="True"/>
<ComboBox x:Name="cmbSchool" ItemsSource="{Binding SchoolList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="School"
SelectionChanged="cmbSchool_SelectionChanged" MinWidth="80" Margin="10" IsEditable="True" IsReadOnly="True"/>
<ComboBox x:Name="cmbEmail" ItemsSource="{Binding EmailList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="Email"
SelectionChanged="cmbEmail_SelectionChanged" MinWidth="80" Margin="10" IsEditable="True" IsReadOnly="True"/>
</StackPanel>
In the selection changed of the Name combobox do the following:
private void cmbName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(cmbName.SelectedItem != null)
{
cmbSchool.SelectedItem = null;
cmbSchool.Text = "School";
cmbEmail.SelectedItem = null;
cmbEmail.Text = "Email";
}
}
Do the same for each of the other comboboxes; just change the combobox names respectively.
If you are using MVVM, then bind the SelectedItem and the Text property of each of the combobox and write a common method which sets the selected items to null and also the text property inside the setter of each of the bound SelectedItems respectively.
In my WPF Application, I have created ValidationRules for my TextBoxes so that it will not allow an empty string which works fine and shows a red border with text telling the user it can not be empty. When the application launches, all the fields are blank waiting for input but I still see the red border around them. Is this normal behavior? Note: I would prefer it firing after either a propertychange event or lostfocus event fires when the user using the form not when the form initially loads.
Example of the validation I am doing:
<TextBox x:Name="itemNum" HorizontalAlignment="Left" Height="23" Margin="82,58,0,0" VerticalAlignment="Top" Width="90"
HorizontalContentAlignment="Left" VerticalContentAlignment="Center" PreviewKeyDown="ItemNum_PreviewKeyDown"
PreviewTextInput="ItemNum_PreviewTextInput" TabIndex="0" Validation.ErrorTemplate="{StaticResource validationErrorTemplate}">
<TextBox.Text>
<Binding Path="rxID" Mode="TwoWay" StringFormat="{}{0:#}" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<MY:TextBoxNotEmptyValidationRule x:Name="rxIDValidation" ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
My TextBoxNotEmptyValidationRule Class:
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
string str = value as string;
if (string.IsNullOrEmpty(str))
{
return new ValidationResult(false, "Value CAN NOT BE empty");
}
return ValidationResult.ValidResult;
}
According to your logic, it seems that it is normal. Lets define a bool flag and set it false or true, does not matter, than when application is run and check the flag, if flag value is initial value do not do anything. Beside this, you "if" check needs to check also focused element. If focused element is our textbox and your flag is not initial value so you can change the textblock border.
You can look at the following link :
Validation on Load
Ideally this is the normal behavior in XAML applications if you use IDataErorInfo or INotifyDataErrorInfo . you can use beginInit and EndInit to achieve your desired output.
There are two TextBox on the WPF page. While user is typing into the first TextBox, the second TextBox must display modified text from the first TextBox. As a result both values must be binded to a view model.
Can it be done with Data Binding?
I was able to get the second TextBox display text from the first one implementing DependencyProperty on my view model. But I don't have the slightest idea how to apply transformation on the fly.
Maybe there is an easy way to achieve this?
Just use databinding with UpdateSourceTrigger set to PropertyChanged:
<TextBox x:Name='txt1' Text="{Binding MyText, UpdateSourceTrigger=PropertyChanged}" />
<TextBox x:Name='txt2' Text="{Binding MyText, UpdateSourceTrigger=PropertyChanged}" />
In this case it will update ViewModel's property on the fly instead of waiting for FocusLost.
I have a Data Grid in Silverlight 4 with 3 columns along with a column which contains "Edit/Apply" button.
The row cells are initially rendered as plain text and I need them to be changed to Comboboxes in the edit mode.
Once the Edit button in any of the row is clicked. I need to change the textblock( This is my Cell Template) in one of the row to the ComboBox(This is my Cell Editing template)
The question is how do i facilitate this on clicking the Edit button of each row and not by double clicking on the row.
Thanks,
Vijay
1st way
Put the textblocks on top of the combo-boxes (comboboxes with collapsed visibility). On Edit Switch visibilities between controls (Combo - visible / TextBlock - Collapsed) and Bind the Text Property from the Textblock to the selected value from the combo.
2nd way
Put only combo-boxes with IsReadOnly Property set to True. On Edit set IsReadOnly to false and on save set it back to true.*
3rd way
Make the datagrid readonly and bind a Data Form to it. The Data Form contains edit / save / cancel buttons.
If you need an example just let me know and I'll write one as soon as possible.
Not sure if this is what you expected. If not, please just ignore it. It is possible that I missunderstood the question.
Another answer
The other answer will be to use a DelegateCommand binded on the Command property of the Edit button wich can contain a parameter (the row number). This is if you are using the MVVM pattern. And in the ViewModel you could edit the selected row.
After a bit of searching / trying i was able to toggle between display and edit mode by a button click (button placed in each row).
Below posted is the sample code , which facilitates this toggle for one of the Cells in the Grid, Which makes use of Two Boolean Properties ShowDefaultTemplate and ShowEditableTemplate , The VisibilityConverter converts the boolean values to corresponding Visibility Options (Visible or Collapsed).
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding XXX}" HorizontalAlignment="Center" VerticalAlignment="Center"
Visibility="{Binding ShowDefaultTemplate, Converter={StaticResource visibilityConverter}}" />
<ComboBox HorizontalAlignment="Left" MinHeight="24" Width="100"
ItemsSource="{Binding Source, Source={StaticResource Provider}}"
Visibility="{Binding ShowEditableTemplate , Converter={StaticResource visibilityConverter}}"
SelectedItem = "{Binding SelctedItem,Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
Thanks,
Vijay
I try to validate the IP-Address a user enters into a text box of a WPF Dialog. The text box is supposed to be initialized with 127.0.0.1. This is the XAML:
<TextBox
Height="23"
Width="98"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Name="ip_address"
Text="127.0.0.1">
<TextBox.Text>
<Binding Path="Left" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:IPValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
This attempt to bind the text box to the validation rule causes an error, because the attribute Text already has the value 127.0.0.1. My question is this: How can I achieve initializing and binding simultaneously?
Regards, RSel
PS: Initializing the text box in Window_Loaded doesn't work either. The box just remains empty. Without the binding to the rule it works.
A couple options:
Set an initial value in the property that the textbox is bound to. The binding should pick this up when the control loads. I'm not sure if this meets your goals though.
Use the TargetNullValue property of the binding object to specify what to show when the source is null.
Here's MSDN on option 2:
http://msdn.microsoft.com/en-us/library/system.windows.data.bindingbase.targetnullvalue.aspx