Bind WPF DataGrid column to another - wpf

I want to enable / disable a DataGridTextColumn based on whether or not the SelectedValue of its neighboring DataGridComboBoxColumn == 'Other'
I can make this work in a ListBox as below, but this won't work in my DataGrid environment as the DataGridComboBox column doesn't have a name property.
<ListBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Source={StaticResource CustomData}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox Name="operatorComboBox" SelectedValue="{Binding OperatorId}" ItemsSource="{Binding Source={StaticResource Operator}}" SelectedValuePath="Id" DisplayMemberPath="Name"></ComboBox>
<TextBox Text="{Binding Name}" Visibility="{Binding Path=SelectedValue, ElementName=operatorComboBox, Converter={StaticResource intToVis}}"></TextBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So can this be done with a DataGrid?
(I know I've changed visibility in the ListBox example, but its not a quantum leap to change that to enabled. (Obviously hiding an entire column would be a bad thing in a proper DataGrid)
this question is fairly similar to what I'm asking, I just can't seam to mangle the solution into what I'm after

The easiest way I can think of solving this problem is actually to create a DataGridTemplateColumn instead of a DataGridTextBoxColumn then create a textbox inside the template. In order to disable / enable the textbox, bind the IsEnabled property to the underlying OperatorId property. You will also have to write a ValueConverter that checks whether the OperatorId value == 'Other' and returns that value.

Related

Recycling of Combobox within a ListView causes null values in SelectedValue

I reproduced the issue by creating a simple UWP application with a ListView and a DataTemplateSelector.
<DataTemplate x:Key="DetailCombo" x:DataType="classes:Question">
<ItemsControl x:Name="questionItemsControl">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding QuestionText}"/>
<ComboBox x:Name="AnswerComboBox" ItemsSource="{Binding AnswerOptions, Mode=OneWay}" SelectedIndex="{Binding AnswerIndex, Mode=TwoWay}"/>
</StackPanel>
</ItemsControl>
</DataTemplate>
For a simple Listview:
<ListView x:Name="dataTemplateSelectorList"
SelectionMode="None"
ItemsSource="{Binding Questions}"
ItemTemplateSelector="{StaticResource QuestionDataTemplateSelector}">
</ListView>
When I put a breakpoint on the setter of "AnswerIndex" I see that the value of -1 is set when I start scrolling through the list. This happens when the list is recycling the listviewitem. When I bind "SelectedValue" the value of null is set while scrolling.
Has anyone experienced this before and has a good solution for it? Now I just check if the value is null or -1 in the setter of binding-property in the viewmodel. But it feels strange that the framework updates the values upon recycling the listviewitem.
I did see the same behavior in the Microsoft.UI.Xaml.Controls.RadioButtons component.

WPF DataGrid ItemsSource - Change from ComboBox

Here is a snippet of XAML:
<ComboBox ItemsSource="{Binding UnileverDataSet.Tables, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Margin="5" x:Name="TableNameComboBox">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TableName}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<DataGrid Margin="5" AutoGenerateColumns="True" ItemsSource="{Binding UnileverDataSet.Tables[TableNameComboBox.SelectedIndex]}"
UnileverDataSet is a DataSet made up of about 12 DataTables
The idea here is that when the ComboBox value changes, the DataGrid should update based on the index value from the ComboBox.
Is this possible or should I look at another way of doing this?
If I do: UnileverDataSet.Tables[0], then all works and data displays correctly.
You can do element binding with combobox..
Your combox will display list of items in the "UnileverDataSet.Tables" collection. When ever your select a item in Combo box the selected item will bounded to the Datagrid Items source (since we are using element binding)
Here is the sample code
<DataGrid Margin="5" AutoGenerateColumns="True" ItemsSource="{Binding SelectedItem,ElementName=TableNameComboBox}">

Two way binding in ListBox ItemTemplate

I have a ListBox which DataTemplate is TextBox that can be edited. Where should I set Binding TwoWay? In ItemSource or In TextBox binding? Maybe in both? And how it works inside? Is it inherited? So if I set Binding in ItemSource - is it inherited in TextBox?
<ListBox HorizontalAlignment="Left" ItemsSource="{Binding Commands, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Two way binding should be setup op your item you need to display, in this case the Textbox. Here you need to have coupling back to your datacontext. You might want to consider setting the UpdateSourceTrigger property to PropertChanged.
This way you will always have entered value of your text, even without loosing focus.
The itemsource should not be Two way. One way will do since you probable will be binding to an observable collection. This will only be set once from your datacontext. This will automatically handle the adding and removing of items to your collection.
I'd add your code like this:
<ListBox Margin="10,0,0,0" Width="200" HorizontalAlignment="Left" ItemsSource="{Binding Commands}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Where should I set Binding TwoWay?
You should set this Mode for TextBox like this:
<TextBox Text="{Binding Path=Name, Mode=TwoWay}" />
If I'm not mistaken, the Text property is listed TwoWay mode by default. Therefore, it's construction is not required.
From MSDN:
When used in data-binding scenarios, this property uses the default update behavior of UpdateSourceTrigger.LostFocus.
This means that updates the properties were visible at once, you need to set the property UpdateSourceTrigger to PropertyChanged:
<TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
So if I set Binding in ItemSource - is it inherited in TextBox?
No, inheritance will not be, because settings of Binding unique for each dependency property. Inheritance happens when using DataContext, but again, settings unique for each property.

Binding ListBox Items using Templates

I am going crazy trying to figure this out without success.
I have a DependencyObject, ("UserObject"). It has a "DataItems" DependecyProperty that is an ObservableCollection. "UserDefiniton" is a DependencyObject with a DependencyProperty of "Data". Data has two properties: DataType (an enumeration) and Value (a string).
I am trying to define a ListBox in XAML that uses the "DataItems" property as its ItemsSource. In the ItemTemplate, I have several different controls. For simplicity of this issue, I am using a CheckBox and a TextBox. I want CheckBox to be available and visible when DataType is 0, while I want the TextBox to be available and visible when the DataType is 1. Only one control can be available and visible at a time.
This works:
<ListBox
ItemsSource={Binding DataItems, Mode=OneWay}>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox
Visibility="{Binding Path=Data.DataType, Mode=OneWay, Converter={StaticResource VisibilityConverter}, ConverterParameter=0}"
IsChecked="{Binding Path=Data.Value, Mode=TwoWay, Converter={StaticResource StringToBoolean}}" />
<TextBox
Visibility="{Binding Path=Data.DataType, Mode=OneWay, Converter={StaticResource VisibilityConverter}, ConverterParameter=1}"
Text="{Binding Path=Data.Value, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
<Listbox.ItemTemplate>
</ListBox>
The problem is that even though only one is visible, both are fighting over the Data.Value property (the boolean of the checkbox will show in the textbox, even though the checkbox is hidden).
Basically, though, the binding in this case is working--but the implementation is incorrect.
So, I switched to using Templates. The problem I am having is that I can't get the binding to work.
This is the code that I have for the Template. The Template selector is working correctly, but the Text property of the TextBox and the IsChecked property of the checkbox are not binding to Data.Value:
<DataTemplate x:Key="TextBoxItem">
<TextBox
Text="{Binding Path=Data.Value, Mode=TwoWay}" />
</DataTemplate>
<DataTemplate x:Key="CheckBoxItem">
<CheckBox
IsChecked="{Binding Path=Data.Value, Mode=TwoWay, Converter={StaticResource StringToBoolean}}" />
</DataTemplate>
...
<ListBox
ItemsSource={Binding DataItems, Mode=OneWay}>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl
Content="{Binding Path=Data.DataType, Mode=OneWay}"
ContentTemplateSelector="{DynamicResource UserDefinitionTemplateSelector}"/>
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>
So how do I fix the binding?
Content should be set to {Binding}, since the Content will be the DataContext of the data-templates, hence you should just pass on the current DataContext. If you need to pass specific data to the template selector you can just drill down in the whole object.
There also is a template selector on the level of the ListBox, so you do not really need the internal ContentControl.
(You might also be interested in generic methods of debugging data bindings.)

WPF: ComboBox with selecteditem set make not use of SelectedIndex=0?

Why is the first element in my combobox popup menu not shown in the selected item area of
my combobox , when I use the SelectedItem binding? Without that it is showing up ?? Using
the same code selecteditem + selectedindex that is no problem!
<ComboBox
ItemsSource="{Binding SchoolclassSubjectViewModels}"
SelectedItem="{Binding SelectedSchoolclassSubjectViewModel}"
SelectedIndex="0"
Height="23"
HorizontalAlignment="Left"
Margin="375,13,0,0"
VerticalAlignment="Top"
Width="151">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SchoolclassName}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding SubjectName}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Well as workaround I used:
SchoolclassSubjectViewModels.Add(schoolclassSubjectVM);
SelectedSchoolclassSubjectViewModel = schoolclassSubjectVM;
and this:
SelectedItem="{Binding SelectedSchoolclassSubjectViewModel,Mode=TwoWay}"
but I would prefer the xaml only way as it should really work.
It is because the reference inside your ItemsSource collection is not the same as the one in your SelectedItem property. I would venture to guess that you are using one object context to query your database for the list of SchoolclassSubject objects which the ItemsSource is bound to, but another context to query the actual data item to which you bind the SelectedItem. Even though the list contains a reference which represents the value held by your object, it is not really the same reference, but a separate instance of the same data.
There are ways to solve this issue, most of them involve using the SelectedValuePath and SelectedValue instead of the SelectedItem properties, but the concrete solution would be different depending on your particular ORM.

Resources