WPF - Lost ability to input date via keyboard? - wpf

I have a WPF user control that makes use of a ComboBox to contain a DatePicker. Unfortunately, when I put the DatePicker into the ComboBox, I seem to lose the ability to enter the date through the keyboard; only the Calendar and mouse work.
Any ideas?
Also, here's my XAML:
<ComboBox Name="cboCombo" IsReadOnly="True" IsEditable="True" Foreground="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=Foreground}" DropDownOpened="cboCombo_DropDownOpened" DropDownClosed="cboCombo_DropDownClosed">
<ComboBox.Text>
<MultiBinding Converter="{StaticResource DateTimeTextConverter}" Mode="OneWay">
<Binding RelativeSource="{RelativeSource FindAncestor,AncestorType={x:Type UserControl}}" Path="SelectedDateAndTime" Mode="OneWay" />
<Binding RelativeSource="{RelativeSource FindAncestor,AncestorType={x:Type UserControl}}" Path="ShowTime" />
</MultiBinding>
</ComboBox.Text>
<ComboBoxItem IsSelected="True">
<ComboBoxItem.Template>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<DatePicker Grid.Row="0" Grid.Column="0" SelectedDate="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=SelectedDateAndTime}" SelectedDateChanged="BCDatePicker_SelectedDateChanged" />
<controls:TimePicker Grid.Row="0" Grid.Column="1" MouseUp="TimePicker_MouseUp" Loaded="TimePicker_Loaded" Time="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=SelectedDateAndTime,Mode=OneWay}" Visibility="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=ShowTime, Converter={StaticResource VisibilityConverter}}" />
<Button Grid.Row="1" Grid.Column="0" Content="Today" Click="Button_Click" />
<Button Grid.Row="1" Grid.Column="1" Content="Clear" Click="Button_Click_1" />
<Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="View Date Calculator" Click="Button_Click_2" Visibility="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=ShowDateCalculator,Mode=OneWay,Converter={StaticResource VisibilityConverter}}" />
<Label Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=SelectedDateAndTime,Mode=OneWay,Converter={StaticResource HolidayDateConverter}}" Foreground="Red" />
</Grid>
</ControlTemplate>
</ComboBoxItem.Template>
</ComboBoxItem>
</ComboBox>

I would try mode=twoway and make sure there is a get set on the property and take off the event. I understand you want the event but if the event is is breaking it then at least you know the event is breaking it. And you can trace and see if set if fired. I am with the other comments - why do you want to do this?

Related

How to Bind Textbox.ReadOnly to property in the parent (owner) view model

It seems a resolved question but after trying several answers posted here I could not resolve my problem. Here it is:
I want to set (by binding) the property IsReadonly of a TextBox to a property of the main view model which contains the type to which the TextBox is already bound to. Also de text box is in a DataTemplate bound to a type.
Trying this produces "Property 'IsReadOnly' is not found" which has sense because the data template is bound to a type that doesn't have it:
<TextBox Name="PromoEntryForm" AutomationProperties.Name="Promo Description" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Path=FriendlyName, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5"
IsReadOnly="{Binding Path=IsReadOnly}" />
Trying this produces nothing, which also has sense because it is binding to the same TextBox.IsReadOnly, as I understand:
<TextBox Name="DiscountEntryForm" AutomationProperties.Name="PromoDiscount" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" IsReadOnly="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=IsReadOnly}" />
I know I have to bind to a property in the parent (container view model) so I also tried this, which produces "System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='CataloGo.ViewModel.PromoViewModel', AncestorLevel='1''. BindingExpression:Path=IsReadOnly; DataItem=null; target element is 'TextBox' (Name='PrintableNameEntryForm'); target property is 'IsReadOnly' (type 'Boolean')"
<TextBox Name="PrintableNameEntryForm" AutomationProperties.Name="Printable Name" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Path=PublicName, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5"
IsReadOnly="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type localVm:PromoViewModel}}, Path=IsReadOnly}" />
But the type is the one in the error message and the DataContext of the view is set to an instance of PromoViewModel so I don't know why it cannot find the source.
This is the full view model:
public class PromoViewModel : SupervisedEntity
{
private ObservableCollection<Promo> _promos;
private Promo _current;
private bool _editMode;
private bool _isNew;
public string Title => "Promociones";
public ObservableCollection<Promo> Promos
{
get => this._promos;
set => this.SetPropertyValue(ref this._promos, value);
}
public Promo Current
{
get => this._current;
set => this.SetPropertyValue(ref this._current, value);
}
public bool IsEditMode
{
get => this._editMode;
set
{
this.SetPropertyValue(ref this._editMode, value);
this.NotifyPropertyChanged(nameof(this.IsReadOnly));
this.NotifyPropertyChanged(nameof(this.HideIfEditing));
this.NotifyPropertyChanged(nameof(this.ShowIfEditing));
}
}
public bool IsNew
{
get => this._isNew;
set => this.SetPropertyValue(ref this._isNew, value);
}
public Promo Backup { get; set; }
public bool IsReadOnly => !this.IsEditMode;
public Visibility HideIfEditing => (this.IsReadOnly ? Visibility.Visible : Visibility.Collapsed);
public Visibility ShowIfEditing => (this.IsReadOnly ? Visibility.Collapsed : Visibility.Visible);
}
And this is the corresponding view:
<Window x:Class="CataloGo.View.PromoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:localroot="clr-namespace:CataloGo"
xmlns:local="clr-namespace:CataloGo.View"
xmlns:localVm="clr-namespace:CataloGo.ViewModel"
xmlns:localModel="clr-namespace:CataloGo.Model"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance localVm:PromoViewModel, d:IsDesignTimeCreatable=True}"
Title="{Binding Path=Title}" SizeToContent="WidthAndHeight" MinWidth="640" MinHeight="480">
<Window.Resources>
<CollectionViewSource
Source="{Binding Path=Promos}"
x:Key="PromoListingDataView" />
<DataTemplate x:Key="PromoDetailTemplate" DataType="{x:Type localModel:Promo}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="106" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Style="{StaticResource SmallTitleStyle}"
Margin="5">
DescripciĆ³n:
</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0"
Style="{StaticResource SmallTitleStyle}" Margin="0,5,0,5">
Descuento (%):
</TextBlock>
<TextBox Name="PromoEntryForm" AutomationProperties.Name="Promo Description" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Path=FriendlyName, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5"
IsReadOnly="{Binding Path=IsReadOnly}" />
<TextBox Name="DiscountEntryForm" AutomationProperties.Name="PromoDiscount" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" IsReadOnly="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=IsReadOnly}" >
<TextBox.Text>
<Binding Path="DiscountPct" StringFormat="N2" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</Grid>
</DataTemplate>
</Window.Resources>
<Border Padding="20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" MinHeight="300"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
Style="{StaticResource TitleStyle}"
Margin="5">
Promociones:
</TextBlock>
<Border Grid.Row="2" Grid.ColumnSpan="3" Style="{StaticResource BorderStyle}">
<ListView Name="ListViewPromos" Grid.Row="1" Grid.ColumnSpan="3" ItemsSource="{Binding Source={StaticResource PromoListingDataView}}"
IsSynchronizedWithCurrentItem="True"
SelectionChanged="OnSelectionChanged"
MouseDoubleClick="EnterEditMode"
IsEnabled="{Binding Path=IsReadOnly}">
<ListView.View>
<GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Info de la promociĆ³n">
<GridViewColumn DisplayMemberBinding="{Binding Path=FriendlyName}" Header="Nombre de la promo" Width="300"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=DiscountPct, StringFormat=N2}" Header="Descuento (%)" Width="150"/>
</GridView>
</ListView.View>
</ListView>
</Border>
<Grid Grid.Row="4" Grid.ColumnSpan="3">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ContentControl Name="PromoDetail" Grid.Row="0" Grid.ColumnSpan="2"
Content="{Binding Path=Current}"
ContentTemplate="{StaticResource PromoDetailTemplate}"
Margin="9,0,0,0" />
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="0,0,0,0"/>
</Style>
</StackPanel.Resources>
<Button Name="NewPromoButton" HorizontalAlignment="Right" Content="_Nueva" Style="{StaticResource AcctionButtonStyle}"
Click="NewPromo" Visibility="{Binding Path=HideIfEditing}"/>
<Button Name="EditPromoButton" HorizontalAlignment="Right" Content="_Modificar" Style="{StaticResource AcctionButtonStyle}"
Click="EditPromo" Visibility="{Binding Path=HideIfEditing}"/>
<Button Name="SubmitPromoButton" HorizontalAlignment="Right" Content="_Aceptar" Style="{StaticResource AcctionButtonStyle}"
Click="SubmitPromo" Visibility="{Binding Path=ShowIfEditing}"/>
<Button Name="CancelEditButton" HorizontalAlignment="Right" Content="_Cancelar" Style="{StaticResource AcctionButtonStyle}"
Click="UndoEdit" Visibility="{Binding Path=ShowIfEditing}"/>
</StackPanel>
</Grid>
</Grid>
</Border>
Use Element Binding instead of relative source.
First Provide name for the Window.
<Window x:Class="CataloGo.View.PromoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:localroot="clr-namespace:CataloGo"
xmlns:local="clr-namespace:CataloGo.View"
xmlns:localVm="clr-namespace:CataloGo.ViewModel"
xmlns:localModel="clr-namespace:CataloGo.Model"
mc:Ignorable="d"
x:Name="Window1"
d:DataContext="{d:DesignInstance localVm:PromoViewModel, d:IsDesignTimeCreatable=True}"
Title="{Binding Path=Title}" SizeToContent="WidthAndHeight" MinWidth="640" MinHeight="480">
Element Binding Code in xaml
<TextBox Name="DiscountEntryForm" AutomationProperties.Name="PromoDiscount" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" IsReadOnly="{Binding ElementName=Window1, Path=DataContext.IsReadOnly}" >
<TextBox.Text>
<Binding Path="DiscountPct" StringFormat="N2" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

WPF Move text "outside" the boundaries of its own element

I am making a LinearGauge control with an ItemsControl. I would like to show the boundaries labels exactly at the center of two bars. I'll try to depict my problem in the screenshot below:
Thus, the labels should all move a few pixels to the right. But the problem of course is, is that the element boundaries are where the next colored bar starts. So I want to move the label "while ignoring the element boundaries".
Is there an easy trick to do something like that?
The xaml I have so far:
<ItemsControl
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding Elements}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:HorizontalGaugeElement}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Rectangle
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
Height="30"
Fill="{Binding Color}">
<Rectangle.Width>
<MultiBinding Converter="{StaticResource BoundsToWidthConverter}">
<Binding Path="Lower"/>
<Binding Path="Upper"/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ItemsControl}}" Path="DataContext.ValueToPercentage"/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ItemsControl}}" Path="DataContext.GaugeSize"/>
</MultiBinding>
</Rectangle.Width>
</Rectangle>
<TextBlock
Visibility="{Binding ShowLowerBoundary, Converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Row="1" Grid.Column="0"
Text="{Binding Lower}"
Margin="5, 0, 0, 0">
</TextBlock>
<TextBlock
Grid.Row="1" Grid.Column="2"
Text="{Binding Upper}" TextAlignment="Right"
Margin="0, 0, 0, 0">
</TextBlock>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:VerticalGaugeElement}">
<!-- similar story but then vertical -->
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="{Binding IsHorizontal, Converter={StaticResource BoolToOrientationConverter}}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

WPF MVVM Binding ComboBox to Datagrid Selected Item

Does anyone have an example of binding a ComboBox to a Selected Item of a DataGrid? I have tried a bunch of ways, but I can't seem to get it to work. I am fairly new to MVVM so I am doing something wrong. Any help would be appreciated. I have the datacontext of the grid that the combobox is in set to the datagrid, but when I select a row from the datagrid the combobox does not change. All of the text boxes are populated with the data from the datagrid, but the combobox does not change. The combobox in question is cmbRoles.
Thank you,
RG
Here is the XAML:
<UserControl x:Class="Compliance.Views.UserAdministrationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Compliance"
xmlns:views="clr-namespace:Compliance.Views"
xmlns:helpers="clr-namespace:Compliance.Helpers"
xmlns:vm="clr-namespace:Compliance.ViewModels"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
d:DesignHeight="1000" d:DesignWidth="800">
<UserControl.Resources>
<helpers:ActiveStatusConverter x:Key="ActiveStatusConverter"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0" Margin="15">
<Label Content="User" Height="25" FontSize="14" HorizontalContentAlignment="Center" />
<Grid HorizontalAlignment="Center" VerticalAlignment="Top" DataContext="{Binding ElementName=usersDG, Path=SelectedItem}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="35" />
</Grid.RowDefinitions>
<telerik:Label Content="User Name: " Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180" >
<TextBox.Text>
<Binding Path="UserName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="First Name: " Grid.Column="2" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="3" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="FirstName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Last Name: " Grid.Column="4" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="5" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="LastName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Email: " Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="1" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="Email" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Active Status: " Grid.Column="2" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<telerik:RadComboBox x:Name="comBoxActiveStatus" Grid.Column="3" Grid.Row="1" MinHeight="23" MinWidth="180" HorizontalAlignment="Left" VerticalAlignment="Center"
SelectedItem="{Binding Path=ActiveStatus,
Converter={StaticResource ResourceKey=ActiveStatusConverter},
Mode=TwoWay,
ValidatesOnExceptions=True,
NotifyOnValidationError=True}">
</telerik:RadComboBox>
<telerik:Label Content="Role: " Grid.Column="4" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<telerik:RadComboBox x:Name="cmbRoles" DisplayMemberPath="RoleName"
Grid.Column="5"
Grid.ColumnSpan="3"
Grid.Row="1"
MinHeight="23"
HorizontalAlignment="Left"
ItemsSource="{Binding}"
Margin="5"
VerticalAlignment="Center"
MinWidth="180"
SelectedItem="{Binding RoleName}"
IsSynchronizedWithCurrentItem="True">
</telerik:RadComboBox>
<Button Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="3" Content="Save User" Width="100" />
<Button Grid.Column="4" Grid.Row="2" Grid.ColumnSpan="3" Content="Add User" Width="100" />
</Grid>
</StackPanel>
<Border CornerRadius="10" BorderThickness="5" Grid.Row="1" VerticalAlignment="Top" HorizontalAlignment="Center">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Content="Users" Grid.Row="0" Height="25" FontSize="14" HorizontalContentAlignment="Center" />
<telerik:RadGridView x:Name="usersDG" ItemsSource="{Binding Users}" AutoGenerateColumns="False" ShowGroupPanel="False" IsReadOnly="True">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding UserName}" Header="User Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding FirstName}" Header="First Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding LastName}" Header="Last Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding Email}" Header="Email" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding Role.RoleName}" Header="Role Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding ActiveStatus, Converter={StaticResource ActiveStatusConverter}}" Header="Active Status" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
</Grid>
</Border>
</Grid>
Expanding and taking a different take on Hannish's Answer above, I too assume you are using a Master Details type arrangement, where you want the Details DataContext to be set to the DataGrid Selected Row.
I also had alot of trouble with ComboBox Binding in this setup too.
I don't use Telerik Controls for my applications, however I tend to create a Property for the DataGrid Selected Row, and bind my details to this.
The DataGrid XAML would be something like;
<DataGrid x:Name="grdResults"
DataContext="{Binding DataGridDataContextCollection}"
ItemsSource="{Binding}"
SelectedItem="{Binding DataContext.SelectedRow, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
I do it this way, as I have Behaviours I've set for the Rows which run off items in the DataGrid DataContext.
I then have a Property for the Selected ComboBox Item also, and Bind the ComboBox to this.
For the ComboBox ItemSource, the issue is, that you have an ObservableCollection of Items which you need to Bind your ComboBox to, but these of course won't be a member of your DataGrid Selected Row, and in turn your details DataContext.
So for Binding the ComboBox ItemSource and SelectedItem, you must refer to the DataContext of your View, rather than that of the Details.
If you have it available in your DataGrid DataContext, also bind the ComboBox Text Property to the DataGrid SelectedRow Name value, assuming the two are the same! This helps update the DataGrid updated also.
The XAML I use for the ComboBox is something like;
<ComboBox x:Name="cmbRoles"
SelectedItem="{Binding DataContext.SelectedRole, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}"
SelectedValuePath="Role_ID"
SelectedValue="{Binding Role_ID, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}"
ItemsSource="{Binding DataContext.RoleItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
Text="{Binding RoleName, Mode=TwoWay}"
DisplayMemberPath="RoleName"
IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Left"/>
To be 100% sure, I then sync the ComboBox SelectedItem to the DataGrid SelectedRow by setting the DataGrid SelectedRow ID value from within your ComboBox SelectedItem Setter. This of course isn't strictly necessary.
I hope this helps!
If I understood correctly, you have a RadGridView with all users, and some sort of Details form in which you edit the values for the selected row.
So, you have to modify a couple of things:
1: The ItemsSource in the combobox is set to {Binding}, so it will just bind to the datacontext of its parent element to get the items list. In this case the parent is the Grid with the DataContext set (correctly) to the RadGrid's selected item (here: DataContext="{Binding ElementName=usersDG, Path=SelectedItem}", it's ok).
The problem is that you have to populate the ItemsSource of the ComboBox with the list of possible Roles. I usually use a static ObservableCollection for such lists (so I make sure they are the same all around the application). Something like this:
ItemsSource="{x:Static local:Lists.RolesList}"
You may have an enum or something else, but the important thing there is that you populate the ItemsSource property with all the options that may be selected.
2: Since you will populate the list in the combobox with Role objects, the SelectedItem must be bound to such an object, which has to exist as a public property (with INPC or a DependecyProperty) inside the User object. You need to set it up like this:
SelectedItem="{Binding Role, Mode=TwoWay}"
Remember that the datacontext of your combo is an User object, as selected in the RadGrid. The user class must have a property Role.
I think that'll do it, let me know if you have any more problems. Best regards!

MVVM issue with binding a combobox to a datagrid

I have sort of a Master/Details view. I have some text boxes and a combo box bound to the selected item of the data grid. What I want is the text boxes and the combo box to populate with the data from the data grid when a row is selected. This part works fine. The issue I am having is when I change the value of the combo box the data grid field is not updating. I have implemented INotifyPropertyChanged, but it appears that I have something wrong. The data grid holds records of type user and the combo box in question has records of type role. The User entity has a navigation property to a RoleID. How can I ensure that the data grid will update when changing the role combo box in the details?
Thank you,
RG
Here is the XAML...
<UserControl x:Class="Compliance.Views.UserAdministrationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Compliance"
xmlns:views="clr-namespace:Compliance.Views"
xmlns:helpers="clr-namespace:Compliance.Helpers"
xmlns:vm="clr-namespace:Compliance.ViewModels"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
d:DesignHeight="1000" d:DesignWidth="800">
<UserControl.Resources>
<helpers:ActiveStatusConverter x:Key="ActiveStatusConverter"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0" Margin="15">
<Label Content="User" Height="25" FontSize="14" HorizontalContentAlignment="Center" />
<Grid HorizontalAlignment="Center" VerticalAlignment="Top" DataContext="{Binding ElementName=usersDG, Path=SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="35" />
</Grid.RowDefinitions>
<telerik:Label Content="User Name: " Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180" >
<TextBox.Text>
<Binding Path="UserName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="First Name: " Grid.Column="2" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="3" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="FirstName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Last Name: " Grid.Column="4" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="5" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="LastName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Email: " Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="1" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="Email" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Active Status: " Grid.Column="2" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<telerik:RadComboBox x:Name="comBoxActiveStatus" Grid.Column="3" Grid.Row="1" MinHeight="23" MinWidth="180" HorizontalAlignment="Left" VerticalAlignment="Center"
SelectedItem="{Binding Path=ActiveStatus,
Converter={StaticResource ResourceKey=ActiveStatusConverter},
Mode=TwoWay,
ValidatesOnExceptions=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
EmptyText="Please Set Active Status">
</telerik:RadComboBox>
<telerik:Label Content="Role: " Grid.Column="4" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<telerik:RadComboBox x:Name="cmbRoles"
Grid.Column="5"
Grid.ColumnSpan="3"
Grid.Row="1"
MinHeight="23"
HorizontalAlignment="Left"
Margin="5"
VerticalAlignment="Center"
MinWidth="180"
ItemsSource="{Binding}"
DisplayMemberPath="RoleName"
SelectedValue="{Binding RoleID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="RoleID"
EmptyText="Please Choose A Role">
<telerik:RadComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</telerik:RadComboBox.ItemsPanel>
</telerik:RadComboBox>
<Button Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="3" Content="Save User" Width="100" />
<Button Grid.Column="4" Grid.Row="2" Grid.ColumnSpan="3" Content="Add User" Width="100" />
</Grid>
</StackPanel>
<Border CornerRadius="10" BorderThickness="5" Grid.Row="1" VerticalAlignment="Top" HorizontalAlignment="Center">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Content="Users" Grid.Row="0" Height="25" FontSize="14" HorizontalContentAlignment="Center" />
<telerik:RadGridView x:Name="usersDG" ItemsSource="{Binding Users}" AutoGenerateColumns="False" ShowGroupPanel="False" IsReadOnly="True">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding UserName}" Header="User Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding FirstName}" Header="First Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding LastName}" Header="Last Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding Email}" Header="Email" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding Role.RoleName, Mode=TwoWay}" Header="Role Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding ActiveStatus, Converter={StaticResource ActiveStatusConverter}}" Header="Active Status" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
</Grid>
</Border>
</Grid>
Your ComboBox bindings looks strange
You have ItemsSource="{Binding }" which suggests that the DataContext for the ComboBox is a collection of Role objects, however you also have SelectedValue="{Binding RoleID}, which suggests the DataContext contains a property called RoleId
In addition, your GridView binds to Role.RoleName, so I would expect you'd want to bind your ComboBox.SelectedValue to Role.RoleId or perhaps ComboBox.SelectedItem to the property Role if they reference the same Role object in memory.
So I would expect your ComboBox bindings to look something like
<ComboBox ItemsSource="{Binding Source={x:Static local:StaticLists.RoleList}}"
SelectedValue="{Binding Role.RoleID}" ... />
or something like this:
<ComboBox ItemsSource="{Binding
RelativeSource={RelativeSource AncestorType={x:Type views:UserAdministrationView}},
Path=DataContext.AvailableRoles}"
SelectedItem="{Binding Role}" ... />
I'd suggest looking into what your ComboBox.DataContext is (I use Snoop for debugging things like this), and double-check that your bindings are correct

Grid with DataContext of DataView won't display data after DataTable.Clear and DataAdapter.Fill

I'll apologize in advance for a long post. I have two DataTables (Cases and Jobs), each with a DataView that I bind my GUI to (the Cases dataview is the DataContext for a Grid, while the Jobs dataview is the ItemsSource of a ListView and the DataContext of a TabControl). The first time I fill the tables with DataAdapter.Fill, the data shows properly for cases and jobs. The second time I load data, I call DataTable.Clear and then DataAdapter.Fill, but only the jobs data shows in the GUI. The case data is nowhere to be seen, even though stepping through I can tell there's a row in the DataTable with the correct data. That is, the DataTable.Clear and DataAdapter.Fill work properly; the Grid control in my GUI just doesn't show the data. I've copied the XAML for the Grid control below. Can anyone help me?! Thanks.
UPDATE: If I have more than one row in the table the second time around, data shows up in the text boxes properly! What the hell is going on?
<Grid Height="165" Width="390" DataContext="{Binding caseTableView}" >
<Grid.Resources>
<local:CaseStatusItemsSource x:Key="StatusesSource" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<!--Case Details-->
<Label Style="{StaticResource LabelStyle}" Grid.Row="1" Grid.Column="1" >Case Number:</Label>
<TextBox Grid.Row="1" Grid.Column="2" Style="{StaticResource TextBoxStyle}" IsReadOnly="{Binding isROCaseNumber}" LostFocus="caseNumber_LostFocus" >
<TextBox.Text>
<Binding Path="/CASENUMBER" UpdateSourceTrigger="LostFocus">
<Binding.ValidationRules>
<local:CaseNumberValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Label Style="{StaticResource LabelStyle}" Grid.Row="2" Grid.Column="1" >Date Received:</Label>
<TextBox Grid.Row="2" Grid.Column="2" Style="{StaticResource TextBoxStyle}" Text="{Binding Path=/DATERECEIVED, StringFormat=d}" IsReadOnly="{Binding isRODateReceived}" />
<Label Style="{StaticResource LabelStyle}" Grid.Row="3" Grid.Column="1" >Status:</Label>
<ComboBox Grid.Row="3" Grid.Column="2" Width="140" Height="20" HorizontalAlignment="Left" FontFamily="Verdana" FontSize="9"
ItemsSource="{Binding statuses, Source={StaticResource StatusesSource}}" SelectedItem="{Binding Path=/STATUS, Mode=TwoWay}" IsReadOnly="{Binding isROCaseStatus}" >
</ComboBox>
<Label Style="{StaticResource LabelStyle}" Grid.Row="4" Grid.Column="1" >Date Ord. Received:</Label>
<TextBox Grid.Row="4" Grid.Column="2" Style="{StaticResource TextBoxStyle}" Text="{Binding Path=/DATEORDRECEIVED, StringFormat=d}" IsReadOnly="{Binding isRODateOrdReceived}" />
<Label Style="{StaticResource LabelStyle}" Grid.Row="5" Grid.Column="1" >Date Posted:</Label>
<TextBox Grid.Row="5" Grid.Column="2" Style="{StaticResource TextBoxStyle}" Text="{Binding Path=/DATEPOSTED, StringFormat=d}" IsReadOnly="{Binding isRODatePosted}" />
</Grid>
There has to be a bug in Microsoft's code somewhere, because I fixed it with the code shown below.
ICollectionView _cv = CollectionViewSource.GetDefaultView(_appModel.casesTable);
_cv.MoveCurrentToNext();
I only needed to do this for the case table, not the jobs table, which is why I expect there's a bug somewhere. The jobs table always worked whether there was one or more than one row in the table.

Resources