I am working with the the WPF Toolkit DataGrid and currently have a problem with committing data back to the source.
My grid is bound to a CLR object list and I have a converter with both the convert and convert back methods implemented.
The two way binding works fine if the user hits Enter in the cells but if they deselect or tab out of the cells the data that was typed is lost.
I have put a break on the CellEditEnding event and both events for Tab and Enter seem identical, but when it gets to the ConvertBack method on my converter the value is empty.
Any help would be much appreciated.
Try changing the UpdateSourceTrigger parameter of your control's Binding to PropertyChanged instead of the default LostFocus.
Eg
<TextBox
Width="75"
VerticalAlignment="Top"
Margin="10"
Text="{Binding
Source={StaticResource data},
Path=Age,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True,
ValidatesOnExceptions=True}"
Style="{StaticResource textBoxInError}" />
Related
So here's the situation:
I have a label (custom control derviative of it, if it matters), and I need to get its width and height with MVVM. However, if I set either of the parameters to {Binding XXX}, they are no long Auto and thus when I change the font in runtime their size doesn't update.
I read about using ActualWidth/Height, which sounds like just what I need besides the fact that it's not a dependence parameter, thus it seemss like I'd need to break MVVM for it.
Are there any better solutions?
EDIT
Well, the element in XAML looks nothing special. Just a million of bindings.
<local:DraggableLabel
Content="123"
Margin="{Binding Label2Position, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="{Binding Label2Font.Family}"
FontSize="{Binding Label2Font.Size}"
FontWeight="{Binding Label2Font.Weight}"
FontStyle="{Binding Label2Font.Style}"
Foreground="{Binding Path=Label2Color,
UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource ColorToBrushConverter}
}"/>
The default is,
Width="Auto"
which doesn't have to be written explicits, but can (changes nothing). It makes it resize when the font changes. If I set it to
Width="Binding {Label1Width}"
The binding works fine, but I no longer get the auto-adjustment.
Okay, so I found a workaround.
Since I had create a custom control, I was able to create a new DependencyProperty called RealWidth, then I added a OnSizeChanged event that updates it with the value of ActualWidth that you CAN get from inside the element every time the size of the element changes.
I have a thread that updates the current Mode property every second. I also want an option to be able to set a mode within the same cell in datagrid. So, in not editing mode I just show the mode. In editing mode, I show a populated ComboBox.
Now,
to be able to show the selected item in ComboBox, when I enter the editing mode, I bind the SelectedItem to Mode.
to be able to get the changes back to the ViewModel I bind SelectedValue to a different property. ( I need to bind to a different property since 'Mode' is updated every second and will overwrite the selected value).
The problem is that though SelectedItem is bound with Mode=OneTime it still triggers SelectedValue property. I want the SelectedValue to be triggered only when user select a value.
I hope it's clear what I'm trying to do. So, how I can achieve this? Other approaches are welcome (even if I need to use a different control).
<DataGridTemplateColumn Header="Mode">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Mode}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource Modes}}"
SelectedItem="{Binding Mode, Mode=OneTime}"
SelectedValue="{Binding ModeToSet, Mode=OneWayToSource}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The premise of what needs to be done is not attainable due to the way the combobox works and how Mode is constantly changing in the background.
Why?
The problem is that though SelectedItem is bound with Mode=OneTime it
still triggers SelectedValue property.
As it should. OneTime as per the docs (BindingMode Enumeration) states:
"Updates the binding target when the application starts or when the data context changes."
The data context as per your design is always changing once a second. If one reads farther into the description it states
"This type of binding is appropriate if you are using data where either a snapshot of the current state is appropriate to use or the data is truly static. ... This is essentially a simpler form of OneWay binding..."
And if one reads up on OneWay bindings
"Updates the binding target (target) property when the binding source (source) changes. This type of binding is appropriate if the control being bound is implicitly read-only."
A combo box is ultimately designed to change both SelectedItem and to get the value off of SelectedItem into SelectedValue
I want the SelectedValue to be triggered only when user select a value.
The problem is not going out of the control, it is what is coming in....
Create a test project and the combobox behaves the way you specify, selected value is only triggered when a user selects a value. Comboboxes only sets the SelectedX properties when a choice is made or an outside value has changed one so it changes the other.
Since Mode is constantly changing it is pushing the change into the selection, not visa versa.
Suggestion To Fix
I suggest you take a snapshot of mode and place that into a ModeOnEdit variable and bind that. When the user makes the selection, capture the event and change the actual Mode.
Test Project
Bind to your own data source, mine was Ships. Ships is a list with and Name as a property on that object. ToString on the ship object returns Name.
Here is the result, there are two textboxes which show the state of the selected item/value. A button to set the selected value and the combobox itself.
<Label Grid.Row="1" Grid.Column="1">SelectedItem</Label>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding SelectedItem, ElementName=cbMain}"/>
<Label Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2">SelectedValue</Label>
<TextBlock Grid.Row="3" Grid.Column="2" Text="{Binding SelectedValue, ElementName=cbMain}"/>
<Button Grid.Row="5" Grid.Column="1" Click="ChangeSelectedValue">Set Selected Value</Button>
<ComboBox Name="cbMain"
Grid.Row="5"
Grid.Column="2"
ItemsSource="{Binding Ships}"
SelectedValuePath="Name"/>
-- Code behind
private void ChangeSelectedValue(object sender, RoutedEventArgs e)
{
cbMain.SelectedValue = "Pacific Silver";
}
I have specified a TextBox with Delay set to 100 as follows:
<TextBox x:Name="SearchTextBox"
Grid.Column="1"
PreviewKeyDown="SearchTextBox_PreviewKeyDown"
KeyUp="SearchTextBox_KeyUp"
Margin="0,2,0,0" FontSize="14"
Padding="3"
Text="{Binding Path=SearchText, Delay=100, UpdateSourceTrigger=PropertyChanged}">
I have an event wired up for KeyUp, my idea is when the user hits the Enter Key i want to perform something.
Sometimes I have noticed that when I hit Enter, the whole text is NOT being updated in the property SearchText in my ViewModel, is it because the binding has not yet updated by the time I hit ENTER? because of the delay? Is there a way around it?
Thanks!
In the key handler you could make sure that the binding is updated by getting the binding expression for the Text binding and calling UpdateSource first.
I have this element in my xaml (DevExpress item):
<dxe:ComboBoxEdit IsTextEditable="False" EditValue="{Binding IDTIPOCONN}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window},Path=DataContext.ttc}" />
All the binding are correct, and when I change the value, I trigger some event from my ViewModel.
My problem is the update of the value is executed only when I leave the focus of my comboBox. I need, instead, to execute my action when the value is changed, before leaving its foucs.
How can I do it? I need this because selecting one or another from the list, I show to the user some hidden elements.
Try for Binding set UpdateSourceTrigger=PropertyChanged:
<dxe:ComboBoxEdit IsTextEditable="False"
EditValue="{Binding Path=IDTIPOCONN, UpdateSourceTrigger=PropertyChanged}" ... />
In this case, most likely the default value of UpdateSourceTrigger is LostFocus.
I have a window control in which I am loading a wpf user control. The wpf user control contains a combo box which is bound to a property in the view model. When I am debugging the code selected value property always has a value. When the control is loaded for the first time I am getting the selected value, but when I reload the control the combo box gets cleared. I tried everything; updating the source and other stuff, but it's still not working. I even set the datacontext in code behind, but am still not getting the expected output.
This is the XAML code:
<ComboBox x:Name="cmbType" Style="{StaticResource ComboBoxStyle}"
PreviewTextInput="cmbErrorType_PreviewTextInput" IsEditable="True"
MaxDropDownHeight="100" ItemsSource="{Binding Path=TypeList,Mode=OneWay}"
SelectedValue="{Binding Path=SelectedValue}" DisplayMemberPath="Id"
SelectedValuePath="Id" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"/>