Combobox text property twoway binding not working - c#

I have a ComboBox as below
<ComboBox VerticalAlignment="Center"
Width="83.84"
Canvas.Left="626.24"
Canvas.Top="249.088" DataContext="{Binding Items[0]}"
Text="{Binding TextVariable, Mode=TwoWay, NotifyOnValidationError=True, TargetNullValue='', ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"
Height="68.293"
Style="{StaticResource ComboBoxDialogControlQ69_74}" />
The problem is: when I set the value for TextVariable in my view model it gets displayed on UI. But when I change it on UI it is not updated in the property.
I think I am missing something very obvious, any help is appreciated.

It works really good when i tried doing like below for Text binding on ComboBox,
Text="{Binding TextVariable, Mode=TwoWay, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, TargetNullValue='', ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"
I have added one more property to make it editable.
IsEditable="True"
if you need the change on PropertyChange change UpdateSourceTrigger to PropertyChanged
UpdateSourceTrigger=PropertyChanged
VM
public string TextVariable {
get
{ return _TextVariable; }
set
{
_TextVariable = value;
NotifyPropertyChanged();
}
}

Related

Cannot set combobox selected item opening a view

I created a new project using template10 and I'm working to a simple form: I load a list of items from a remote server in a comboxbox and select one of the items after the list is loaded.
I tried setting SelectedValue, SelectedItem ot SelectedIndex, but when the Form is shown the listbox appears unselected.
Am I missing something?
this is the xaml
<ComboBox x:Name="voceSpesaCb" Margin="16,16,0,0"
RelativePanel.AlignLeftWith="parameterResizer"
RelativePanel.Below="voceSpesaTextBlock"
DisplayMemberPath="Descrizione"
SelectedValue="{x:Bind ViewModel.VoceCorrente, Converter={StaticResource XConverter}, Mode=TwoWay}"
ItemsSource="{x:Bind ViewModel.Voci, Converter={StaticResource XConverter}}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
this is the code
Voci = await vociSpesaTable.OrderBy(vs => vs.Descrizione).ToListAsync();
VoceCorrente = Voci.FirstOrDefault(vs => vs.VoceSpesaNo == Item.VoceSpesaNo);
in the setter of the properties there is the call to the RaisePropertyChanged
Looks loike I found the problem. For reasons I don't understand at full I have to set Mode=TwoWay for the ItemsSource property too.
<ComboBox x:Name="voceSpesaCb" Margin="16,16,0,0"
RelativePanel.AlignLeftWith="parameterResizer"
RelativePanel.Below="voceSpesaTextBlock"
DisplayMemberPath="Descrizione"
SelectedValue="{x:Bind ViewModel.VoceCorrente, Converter={StaticResource XConverter}, Mode=TwoWay}"
ItemsSource="{x:Bind ViewModel.Voci, Converter={StaticResource XConverter}, Mode=TwoWay}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
/>
This way it works

Why is my Visibility binding not working?

I have a problem with one of my Visibility Bindings.
In my application I have a Textbox and a combobox at nearly the same place.
They are overlapping so I have two Variables in the background for their Visibility. They are in a Datagrid, so the Visibility Source will be provided from the list.
The Binding of my Combobox works absolutely fine, but the one of my Textbox doesn't
Here is my Code:
<TextBox x:Name="Textvalue"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Width="150"
BorderBrush="#FF383F55"
BorderThickness="0"
Foreground="White"
Background="#FF232734"
Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding Path=IsPath}"/>
<ComboBox x:Name="Combobox"
VerticalAlignment="Center"
Foreground="White"
Margin="3,3,3,3"
Height="23"
ItemsSource="{Binding Path=ValueArray}"
SelectedValue="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}"
Style="{DynamicResource ComboBoxStyle1}"
Visibility="{Binding Path=IsCombobox}"/>
These are my Get Property for both (Both only have the Get Proberty):
public System.Windows.Visibility isPath
{
get
{
return _IsPath;
}
}
public System.Windows.Visibility IsCombobox
{
get
{
return _IsCombobox;
}
}
I hope you can help me because I don't know what's wrong here :/
Thanks in advance
What I have tried:
Tried to change the binding to a different Variable.
The property name in your code has a lower case 'i' public System.Windows.Visibility isPath and the XAML has an upper case I in binding IsPath. Change this and it should be working!
{Credit C S, I'd already started writing this}

How to bind a form in a grid that is bound to a tree which is bound to a different collection in wpf

Ok so this is kinda hard to explain. I have a view which has a tree and has a form. The tree is bound to 2 different observable collections.
<TreeView FontFamily="Calibri" FontSize="16" Name="tree" Margin="3" Grid.Row="1" Grid.Column="0" Height="950" VerticalAlignment="Top" Grid.ColumnSpan="2"
ItemsSource="{Binding Path=Org, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItemChanged="tree_SelectedItemChanged" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Org_Sredstva}">
<TextBlock Text="{Binding Path=Organizacije_Naziv}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Ossr_Naziv}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Now then next to the tree there is a form. And the form is supposed to be bound to a third observable collection that changes depending on selecteditem of tree.
<Grid Grid.Row="2" Grid.Column="2" Margin="5" DataContext="{Binding ElementName=tree, Path=SelectedItem}">
As you can see the binding is to the tree which is bound to a different observable collection.
<extToolkit:WatermarkTextBox x:Name="RadnoVrijeme" Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Width="100"
Height="25"
Padding="3"
Margin="3"
AcceptsReturn="True"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
Validation.Error="Validation_Error">
<extToolkit:WatermarkTextBox.Watermark>
<StackPanel Orientation="Horizontal">
<TextBox Text="Radno Vrijeme" Margin="4,2,2,0" FontWeight="Regular" Foreground="Silver" BorderThickness="0"/>
</StackPanel>
</extToolkit:WatermarkTextBox.Watermark>
<extToolkit:WatermarkTextBox.Text>
<Binding Path="Opr_RadnoVrijeme" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True">
<Binding.ValidationRules>
<validation:InputLenghtRule MinLength="10" MaxLength="250" ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</extToolkit:WatermarkTextBox.Text>
</extToolkit:WatermarkTextBox>
This is a textbox and it is bound to a property on the third collection but it doesn't work obviously because that collection is never set as itemssource anywhere.
The workaround I found is to in codebehind set every textbox individually so
this.View.RadnoVrijeme.Text = opr.Opr_RadnoVrijeme;
Where the left side of the equation is the text property of the textbox and the right side is the collection.property. This works but I don't like it and was hoping there was a way to actually bind this?
You should definetely have a look at MVVM. It utilize modular design, where your View is consisting of multiple Views controlled by ViewModels. Then it's easy to solve any kind of dependency (relation? selection?) problem.
In your case you are trying to bind to SelectedItem directly, while in MVVM you will handle selection and then you have possibility to rise notification of related property change, which will cause update of corresponding View element automatically.
Here is a generic example:
ItemVM _selectedItem;
public ItemVM SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
OnPropertyChanged();
// trigger update in the view
OnPropertyChanged(nameof(SomeRelatedProperty));
}
}
// bind TextBlock.Text to that property
public string SomeRelatedProperty
{
get
{
// some logic based on selected item
if(SelectedItem.SomeProperty == SomeValue)
return "a";
...
return "b";
}
}
The cooler thing if SelectedItem already provides value as one of property (because it's a ViewModel), then assuming all ViewModels implement INotifyPropertyChanged you can simply bind to that property directly and whenever selected item is changed the view will be updated to display that property too:
<TextBlock Text="{Binding SelectedItem.SomeProperty} ... / >
As for error you are getting:
System.Windows.Data Error: 40 : BindingExpression path error: 'Opr_RadnoVrijeme' property not found on 'object' ''Organizacije' (HashCode=23451234)'. BindingExpression:Path=Opr_RadnoVrijeme; DataItem='Organizacije' (HashCode=23451234); target element is 'WatermarkTextBox' (Name='RadnoVrijeme'); target property is 'Text' (type 'String')
Try binding (pretty unsure, you didn't provide ViewModels to figure that out):
<WatermarkTextBox Text="{Binding SelectedItem.Opr_RadnoVrijeme, RelativeSource={RelativeSource FindAncestor, AncestorType=TreeView}}" ... />

Textbox not updating

Ive tried searching, but maybe im not using the right terms to search for.
I have several textboxes that im using, and when i enter data, i see the values being updated when debugging, but they never get updated to the form.
Basically, I have a form that is used for the visuals, and then i have a class that handles all the activity. I have created the class as a resource, and I am referencing to the resource within the textboxes.
The only way that i really knew how to handle the updating of the forms was by implementing the calculations on values changing. So if I updated a property, I called the method from OnPropertyChanged(). This created issues because the values were always getting changed due to the calculations rewriting values. I then tried evaluating the changes of the new value
I.E.
public double In1
{
get{_return _in1;}
set{
if (_in1 != value)
_in1 = value;
OnPropertyChanged("In1");
}
}
regardless of anything, my problem is that i dont see the values getting written to the textbox. This is my first real endevour of using data binding so im assuming that im doing something incorrectly (clearly)
<ad:DockableContent
xmlns="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="DMC_Robot_Editor.GUI.frmAngleConvertor"
Title="frmAngleConvertor" Height="259" Width="282">
<ad:DockableContent.Resources>
<local:AngleConvertor x:Key="Converter"/>
</ad:DockableContent.Resources>
<Grid >
<GroupBox HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Grid>
<ComboBox x:Name="cbInput" HorizontalAlignment="Stretch" VerticalAlignment="Top" Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="1" DisplayMemberPath="ValueCartesianString" SelectedValuePath="ValueCartesianEnum" IsSynchronizedWithCurrentItem="True" SelectedIndex="{Binding InputItem,Source={StaticResource Converter}}" ItemsSource="{Binding InputConvention, Source={StaticResource Converter}}" IsReadOnly="True"/>
<TextBox x:Name="tbIn1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text="{Binding In1, Converter={StaticResource DoubleToStringConverter}, Source={StaticResource Converter}}" Grid.Column="0" d:LayoutOverrides="GridBox" Grid.Row="2" Width="50" TextAlignment="Center">
<TextBox.DataContext>
<local:AngleConvertor/>
</TextBox.DataContext> </Grid>
</ad:DockableContent>
public class AngleConverter()
{
private double _in1 = 0.0;
public double In1
{
get{_return _in1;}
set{
if (_in1 != value)
_in1 = value;
OnPropertyChanged("In1");
}
}
}
Try to apply UpdateSourceTrigger=PropertyChanged on your text box:
Text="{Binding Path-In1, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource DoubleToStringConverter}, Source={StaticResource Converter}}"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can add to your binding UpdateSourceTrigger=PropertyChanged with your Mode TwoWay
<TextBox Name="tbIn1"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Text="{Binding In1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource DoubleToStringConverter},
Source={StaticResource Converter}}"
Grid.Column="0"
d:LayoutOverrides="GridBox"
Grid.Row="2"
Width="50"
TextAlignment="Center"
/>
your real code should have something like this:
public class AngleConverter : INotifyPropertyChanged
so i assume its just a typo in your code. you did not post your converter code, the binding in your textbox is ok. Textbox default UpdateSourceTrigger is lostfocus. so maybe UpdateSourceTrigger=PropertyChanged did what you want.
Review the binding
Does DoubleToStringConverter get called?
Is get called?
Text="{Binding In1, Converter={StaticResource DoubleToStringConverter}, Source={StaticResource Converter}}"
Move Source out of binding in into DataContext on the DockableContent.
DataContext="{Binding RelativeSource={RelativeSource self}}"
Try with no converter
Text="{Binding In1}"

Same binding works for 1 XAML item, but null for another

The binding for productColumn2 works perfect both ways. When I added a converter for each, productColumn1 called the converter; but always has it's value set to null when loading from observable collection, or value set to product when assigning (but doesn't actually assign observable collection).
Issue has to do with DataContext and LogicalTree. The DataContext for ProductSelectorTextBoxUserControl is itself, and is used for it's own code. I want to be able to bind its 'text' property to my observable collection, as in productColumn2. I so far can't seem to set ProductSelectorTextBoxUserControl DataContext to the DataContext used here.
<DataGrid ItemsSource="{Binding Path=ObservableCollectionItems, Mode=OneWay}" AutoGenerateColumns="False" EnableRowVirtualization="True" >
<DataGrid.Columns>
<DataGridTemplateColumn x:Name="productColumn1" SortMemberPath="Product" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<productSelector:ProductSelectorTextBoxUserControl Text="{Binding Path=Product, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=LostFocus, ValidatesOnExceptions=True}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn x:Name="productColumn2" Binding="{Binding Path=Product, Mode=TwoWay, NotifyOnSourceUpdated=True}" />
</DataGrid.Columns>
If ProductSelectorTextBoxUserControl has a DataContext set to itself, the Binding won't be able to find the Product property as it doesn't exist. You need to modify your binding so that it knows where to find the Product property; something like this may work:
<productSelector:ProductSelectorTextBoxUserControl Text="{Binding Path=Product, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=LostFocus, ValidatesOnExceptions=True}" />
By adding a RelativeSource, you're telling the binding to look for the Product property in the DataGridRow.DataContext.
UPDATE
Have you tried {RelativeSource AncestorType={x:Type DataGridRow}}? You should be targeting the row and not the grid.
When the ItemContainerGenerator creates each DataGridRow it sets the row's DataContext to the corresponding item in the ObservableCollectionItems. So, the logical tree something like this:
DataGrid (DataContext = object that defines ObservableCollectionItems)
DataGridRow (DataContext = ObservableCollectionItems[0])
ProductSelectorTextBoxUserControl (DataContext = self)
DataGridRow (DataContext = ObservableCollectionItems[0])
ProductSelectorTextBoxUserControl (DataContext = self)
The grid's DataContext doesn't expose the Product property, it's defined on each element in the collection (unless I've missed something). The Product property should be in the context of each row.
Thanks #SellMeADog for helping me out on this, however this still took me way way to long to figure out. Final line is:
<productSelector:ProductSelectorTextBoxUserControl x:Name="productSelector" Product="{Binding Path=Item.Product, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridRow, AncestorLevel=1}, Converter={StaticResource productNameToProductConverter}, Mode=TwoWay, NotifyOnSourceUpdated=True, ValidatesOnExceptions=True}" />
Key points are RelativeSource DataGridRow, Path is Item(ObservableCollection).Property
If you notice question referred to text and this refers to product, I had to switch to product and add converter. UserControl would then set its own text

Categories

Resources