TextBox ConvertBack event doesn't fire for XML element - wpf

ValueFormattingConverter.Convert is called with the XmlElement. ConvertBack is never called. Why? Is there some obligation to pass binding directives down the chain? Is the use of the TextBox overriding its own binding settings? What can be done?
My TextBox
<TextBox Width="200"
Text="{Binding Path=., Converter={StaticResource valueFormattingConverter}}",
Mode=TwoWay,
NotifyOnSourceUpdated=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}" />
Usage is rather convoluted. Starting at the top, we provide an XML element to a tab.
<TabItem.DataContext>
<Binding Source="{StaticResource mcf}",
XPath="mdf/press_information"/>
</TabItem.DataContext>
That tab contains a ItemsControl which builds TextBoxes through this ControlChooser which passes the binding along.
<ItemsControl.ItemTemplate>
<DataTemplate>
<W3V:ControlChooser RelativeSource="{RelativeSource AncestorType=W3V:ObjectList}",
Content="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
My converter class header. Convert method is called. ConvertBack never.
[ValueConversion(typeof(XmlElement), typeof(string))]
public class ValueFormattingConverter : IValueConverter
EDIT: The chosen answer basically says Path=. doesn't support 2-way binding. I believe it is the correct answer to the question. Very helpful to know, but "can't do that" doesn't solve the larger problem. So I have laid out the larger question here: Means of generating an editable form from XML.

The binding direction to source won't work with a {Binding Path=.}. This is because there is no bound property, but just the binding source object.
Hence there will never be a source update, and the ConvertBack method is never called, because that would mean to replace the source object.
In order to make your code work, you would have to bind to some property:
<TextBox Text="{Binding Path=SomeElement, ...}"/>

Related

WPF Binding - Self Binding with its own DataContext

Anyone got a situation to bind the same DataContext to Text property (for example) in TextBlock.
I have to assign the DataContext to reflect some trigger based on the Data values from Datacontext in my style. at the same time, i need to bind with the same DataContext object to get the Text Property After applying some conversion on either IValueConverter/IMultivalueConverter.
As i know {Binding}, just bind with the current datacontext. But in the same scenario how to use converter with it?
Any suggestions will be appreciated.
<TextBlock Style="{StaticResource DataEntryTextBlock1}" Grid.Row="1"
DataContext="{Binding MyField1}"
Text="{Binding MyField1, Converter={StaticResource myConverter}}">
</TextBlock>
This XAML script does not work, as the Text binding is trying to look for the MyField1 variable inside the MyField1.
Thanks,
Vinodh
{Binding} is equivalent to {Binding Path=.} so in you case you can use
Text="{Binding Path=., Converter={StaticResource myConverter}}"
Binding.Path on MSDN
Optionally, a period (.) path can be used to bind to the current source. For example, Text="{Binding}" is equivalent to Text="{Binding Path=.}"

Concatenation of binding's path property in XAML

I have a question that is connected with setting path when binding in XAML, using WPF.
Imagine that my DataContext is of PropertyInfo type. PropertyInfo contains data about Property Name.
And in that object I nest (for example) TextBox which Text property I would like to bind to property with that name of another's element DataContext.
Something like that [it's pseudocode because it's not possible that way]:
<DataTemplate>
<TextBox Text={Binding ElementName=someElement, Path=DataContext. + {Binding Path=Name}}/>
</DataTemplate>
I want to create flexible view that's why I need to solve that problem.
Is there a way to achieve this without code behind?
Considering all the above, I think that I can make my question short and simply ask whether there is a way to concatenate string while setting binding's path.
I'm not sure if I understand correctly but is this something that multibinding would assist with?
<TextBlock Grid.Row="3" Grid.Column="1" Padding="5"><TextBlock.Text>
<MultiBinding StringFormat="[{0}, {1}]">
<Binding Path="LastName"></Binding>
<Binding Path="FirstName"></Binding>
</MultiBinding>
</TextBlock.Text>
</TextBlock>

How do I bind combobox text to legacy data not in the drop down list?

The drop-down list (itemssource) of my combobox contains new product request items. I want to bind to legacy data that is not in the drop-down list. To complicate things I'm using multibinding with an IMultiValueConverter to combine fields for display. Also, the names of bound fields do not match the names of the properties I'm bound to.
The combobox itemssource is a list of NewProductRequests. From this NPR object NewProdNumber and NewProdName are combined for display in the drop-down list by my type converter. The ConvertBack method returns the values NewProdNumber and NewProdNumberCombinedWithName. These two values will be saved to database fields with slightly different names. For this example I'll call them DBProdRequestNumber and DBProdRequestTitle.
I've succeeded in displaying and saving new items. The problem is I haven't figured out how to display legacy data that is not in the list. It's not in the list because it no longer qualifies as a new product request.
Here is the problem XAML (the itemssource is set in code-behind):
<ComboBox x:Name="NPRComboBox" IsSynchronizedWithCurrentItem="False" IsEditable="False">
<ComboBox.SelectedItem>
<MultiBinding Converter="{StaticResource combineNPRStuffMultiConverter}">
<Binding Path="DBProdRequestNumber" UpdateSourceTrigger="PropertyChanged"/>
<Binding Path="DBProdRequestTitle" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</ComboBox.SelectedItem>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding}">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource combineNPRStuffMultiConverter}">
<Binding Path="NewProdNumber" UpdateSourceTrigger="PropertyChanged"/>
<Binding Path="NewProdNumberCombinedWithName" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
A similar problem with a datagrid and combobox I solved using a DataGridTemplateColumn.CellEditingTemplate based on this MSDN Magazine example from Julie Lerman. Of course, in this case I'm not using a datagrid.
Thanks in advance for any help.
This answer (to my own question) was pulled from a comment in the NathanAW answer:
Unfortunately I can't include legacy items in the ItemsSource. The list is from a web service that is out of my control. I devised a kludgy solution which I don't really like (but it works)...Since I know the combobox is needed only for new records it is visible only when the user clicks "Add". In the same location I placed a textbox bound to the legacy data that is visible when NOT in add mode. So, I toggle the visiblity of each control as the app switches in and out of add mode. I'm sure there is a better way!
It seems that you might be able to simplify this by not using a Multi-Binding converter. If you have a collection of NPR objects, then you can set that as the ItemsSource for the listbox. Then use the DataTemplate to format how you want that item displayed.
With this setup, you can construct a template that shows multiple fields from the NPR object in a single TextBlock using something like:
<ComboBox
x:Name="NPRComboBox"
IsSynchronizedWithCurrentItem="False"
IsEditable="False"
SelectedItem={Binding SelectedNPR, Mode=TwoWay}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Path=NewProdNumber, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
<Run> - </Run>
<Run Text="{Binding Path=NewProdNumberCombinedWithName, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
If you have additional properties on the NPR object that you'd like to access, you can add an additional section to the template.
Notice that the "selected" item is bound two-way back to a property on your ViewModel (or code-behind, or whatever). This would be something like:
public NPR SelectedNPR
{
get { ... }
set
{
...
// don't forget INotifyPropertyChanged
...
}
}
EDIT
Here is a sample that seems to do what you've indicted about showing legacy data in the "SelectionBox", but not in the drop down list. To test this, try running it in KaXaml or something. Then start typing "Hello 3" and see that it suggests "Hello 30". This indicates that the Combo knows about the item. Now drop the list down and see that it isn't in the list. If you arrow down with the arrow keys, it skips from "Hello 20" to "Hello 40".
The next step would be to setup your templates so that the ListBoxItem template's Visibility is bound to "IsLegacy" on your NPR object. Then add both legacy and new items to the ItemsSource collection and bind to the list.
<ComboBox IsEditable="True">
<ComboBoxItem >Hello 10</ComboBoxItem>
<ComboBoxItem >Hello 20</ComboBoxItem>
<ComboBoxItem Visibility="Collapsed">Hello 30</ComboBoxItem>
<ComboBoxItem >Hello 40</ComboBoxItem>
</ComboBox>

WPF: How to bind to the name property

Can i bind to the name property?
This does not seem to work:
<TextBlock Name="FordPerfect" Text="{Binding Path=Name, Mode=OneWay}"/>
Am i doing something wrong?
Edit:
Adding ElementName=FordPerfect" solved the issue. What i don't understand is why only binding to Name required this while other properties don't.
Note: Moved the second (design) issue to another question (where i should have placed in the first time...)
Thanks
I would try this :
<TextBlock Name="FordPerfect"
Text="{Binding ElementName=FordPerfect, Path=Name, Converter={StaticResource conv}, Mode=OneWay}"/>
This way, your TextBlock will be the context of the binding.
If it does not work, watch the Output window, you should find a binding error !
you could have more easily done this:
<TextBlock Name="FordPerfect"
Text="{Binding Name, Converter={StaticResource conv}, Mode=OneWay, RelativeSource={RelativeSource Self}}"/>
As to why: that textbox' DataContext is not automatically the TextBox itself. So binding to Name tries to bind to whateverObjectInDataContext.Name. So either you set the DataContext beforehand like:
<TextBlock Name="FordPerfect" DataContext={Binding RelativeSource={RelativeSource Self}}
Text="{Binding Name, Converter={StaticResource conv}, Mode=OneWay}"/>
... or directly set a Source for the Binding
The issue you're having is a Binding, by default, uses the DataContext of the element it's used on as its source. However you want the binding source to be the TextBlock element itself.
WPF has a class called RelativeSource which, as its name implies, sets the source relative to the binding. One of the relations you can choose is Self which does exactly what you want: sets the source of the binding to the element it's used on.
Here's the code:
<TextBlock Name="FordPerfect" Text="{Binding Name, RelativeSource={RelativeSource Self}}" />
Since you're already setting the source with RelativeSource, you don't need to specify ElementName. You also don't need Mode=OneWay as a TextBlock.TextProperty already defaults to one-way since it's output-only.
Hope this helps!

ValueConverter not invoked in DataTemplate binding

I have a ComboBox that uses a DataTemplate. The DataTemplate contains a binding which uses an IValueConverter to convert an enumerated value into a string. The problem is that the value converter is never invoked. If I put a breakpoint in StatusToTextConverter.Convert(), it never is hit.
This is my XAML:
<ComboBox ItemsSource="{Binding Path=StatusChoices, Mode=OneWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource StatusToTextConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I thought this is how one implicitly binds to the value a DataTemplate is presenting. Am I wrong?
Edit: For context: I intend to display an Image in the DataTemplate alongside that TextBox. If I can't get the TextBox binding to work, then I don't think the Image will work, either.
In some circumstances you must explicitly supply a Path for a Binding. Try this instead:
<TextBlock Text="{Binding Path=.,Converter={StaticResource StatusToTextConverter}}"/>

Resources