Basic problem: How do I bind a textbox to the selected item of a combobox who's itemsource is the result of a LINQ query on a WCF RIA Services Domain context.
Additional requirement: When the selected item is changed the binding should update.
Additional requirement: The binding should be two way.
My solution so far:
After the user clicks to create a new item, new items are created and added to the object set but not persisted yet (one for each language). After that this code runs. The combobox is supposed to allow the user to select one of the created items, which is displayed as it's corresponding language. The bound textboxes should allow the user to edit the item.
Code behind:
//Setup the combobox
LanguageComboBox.ItemsSource = dc.GeneralStatistics.Where(g => g.RelatedResourceId.Equals(guid));
LanguageComboBox.DisplayMemberPath = "Language.LanguageName";
LanguageComboBox.SelectedItem = dc.GeneralStatistics.First(g => g.Language.LanguageName.Equals("English"));
//Setup the textboxes
this.StatisticsText.DataContext = (LanguageComboBox.SelectedItem as GeneralStatistics).Text;
this.ShortDescriptionText.DataContext = (LanguageComboBox.SelectedItem as GeneralStatistics).ShortDescription;
XAML CODE:
<ComboBox x:Name="LanguageComboBox" />
<TextBox x:Name="ShortDescriptionText" Text="{Binding}" />
<TextBox x:Name="StatisticsText" Text="{Binding}" />
The problem with my solution:
It does not work, because when I change the selection in the combobox the textboxes do not update. I could implement the selection changed event handler and manually update the textboxes, but that would defeat the purpose of binding the textboxes. What is the best practice here?
You can simplify the code by doing the following.
Code behind:
LanguageComboBox.DataContext = dc.GeneralStatistics.Where(g => g.RelatedResourceId.Equals(guid));
XAML:
<ComboBox x:Name="LanguageComboBox" />
<TextBox x:Name="ShortDescriptionText" Text="{Binding ElementName=LanguageComboBox, Path=SelectedItem.ShortDescription}" />
<TextBox x:Name="StatisticsText" Text="{Binding ElementName=LanguageComboBox, Path=SelectedItem.LongDescription}" />
Related
I got a page in which I load multiple control template considering some business logic binded to a property in my viewModel.
<ContentView x:Name="ContentView" ControlTemplate="{Binding ItemControlTemplate}">
</ContentView>
Inside this control template I got a CarouselViewControl which uses a DataTemplate.
<carousel:CarouselViewControl x:Name="CarouselViewMapTemplate" Position="
{TemplateBinding BindingContext.CarouselPosition}"
PositionSelectedCommand="{TemplateBinding BindingContext.PositionChanged}"
Orientation="Horizontal" AnimateTransition="True" IsSwipeEnabled="False"
ItemsSource="{TemplateBinding BindingContext.Items}" InterPageSpacing="10"
ItemTemplate="{StaticResource ItemsDataTemplate }">
</carousel:CarouselViewControl>
And inside this DataTemplate I would like to bind to a property in the ViewModel, which is also a DataTemplate.
<maps:SfMaps x:Name="sfmap" EnablePanning="False" EnableZooming="False" BackgroundColor="Transparent">
<maps:SfMaps.Layers>
<maps:ShapeFileLayer x:Name="ShapeLayer" Uri="FRA_adm0.shp" MarkerTemplate="{Binding Parent.BindingContext.MarkerDataTemplate}">
</maps:ShapeFileLayer>
</maps:SfMaps.Layers>
</maps:SfMaps>
How can I achieve that ? I just tried
{Binding Parent.BindingContext.MyProperty}
but this is not working. I also digged with Source property of binding, but that won't do it as I don't have reference in my DataTemplate, used as resource in the app level ResourceDictionary.
This DOESNT work ofc it does not find carouselView in the ResourceDictionary :
"{Binding Path=BindingContext.DisplayMarkerTemplateCommand, Source={x:Reference carouselView}}"
Not being able to do that breaks the whole point of having ResourceDictionary and clean templating if binding is not working from it with XAML.
THANKS !
Initially I was generating a dataGrid with AutoGeneratedColumns = True getting values from a dataTable. However the number of columns for each dataset is fixed and I would like to name them accordingly and therefore named them in the code but if the Tab was not selscted when I runed the code then I was getting an error that the Index is out of range.
I decided to do AutoGeneratedColumns = False and manually define my columns. However in the sequel my data dataGrid was empty and my data not displayed. The Data Table name is Underlyings and it is generated at runtime, before that its not even there.
Below my XAML code:
<DataGrid ItemsSource ="{Binding Path=Underlying}" AutoGenerateColumns="False" HorizontalAlignment="Left" Margin="462,145,0,203" Name="dataGrid3" Width="872" >
<DataGrid.Columns>
<DataGridTextColumn Header="In" Binding="{Binding FirstColumnName}" />
<DataGridTextColumn Header="InL" Binding="{Binding SecondColumnName}" />
<DataGridTextColumn Header="Total " Binding="{Binding ThirdColumnName}" />
</DataGrid.Columns>
</DataGrid>
And in the code thwe following
dataGrid3.ItemsSource = Underlying.DefaultView
However I think that XAML binding would not work for me because my datatable is generated at runtime so there is nothing to bind to at design time.
Any Ideas how to do so?
I think you should not set the ItemsSource property but rather use the DataContext property of the DataGrid and use templating in the XAML as in the question here: WPF: Binding to DataGrid
I have an "AddressListBox" ListBox that contains "AddressDetails" UserControl items, as shown in the .xaml file extract below. The Addresses collection is defined as
ObservableCollection< Address > Addresses
and Street, Number, PostCode, City are properties of the Address class. The binding fails, when I use the "{Binding property}" syntax shown below. The binding succeeds, when I use the "dummy" strings in the commented-out code. I have also tried "{Binding Path=property}" syntax without success. Can you suggest what syntax I should use for binding the data in the user controls?
<ListBox x:Name="AddressListBox"
DataContext="{StaticResource dataSettings}" ItemsSource="{Binding Path=Addresses, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<!--
<usercontrols:AddressDetails AddressRoad="dummy" AddressNumber="dummy2" AddressPostCode="dummy3" AddressCity="dummy4">
</usercontrols:AddressDetails>
-->
<usercontrols:AddressDetails AddressRoad="{Binding Street}" AddressNumber="{Binding Number}" AddressPostCode="{Binding PostCode}" AddressCity="{Binding City}">
</usercontrols:AddressDetails>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You need to set the datacontext on the usercontrol to the item like this.
<usercontrols:AddressDetails DataContext={Binding}
...
</usercontrols:AddressDetails>
Now your other bindings should work correctly as they are relative to the item.
I've got two CollectionViewSource bindings to the same data table Client. Each CollectionViewSource has a separate DataGrid binded to it:
(dg1: DataGrid) ----> (cvs1: CollectionViewSource) ----
|
v
(Clients: DataTable)
^
|
(dg2: DataGrid) ----> (cvs2: CollectionViewSource) ----
Or in XAML:
<CollectionViewSource x:Key="cvs1" Source="{Binding Client, Source={StaticResource MainDataSet}}"/>
<CollectionViewSource x:Key="cvs2" Source="{Binding Client, Source={StaticResource MainDataSet}}"/>
...
...
<DataGrid ItemsSource="{Binding Source={StaticResource cvs1}}" ...>
....
</DataGrid>
<DataGrid ItemsSource="{Binding Source={StaticResource cvs2}}" ...>
....
</DataGrid>
However when the application runs and I click on the first DataGrid to sort by some column, the second DataGrid is instantly sorted identically and together with the first one. This is not what I want.
As far as I know each CollectionViewSource should have its own view of the data, so am I missing anything here?
I don't know if you're still looking for a solution but I had the same issue. It's solved by creating a new CollectionViewSource. In essence it's as such:
ICollectionView cvs1= new CollectionViewSource { Source = dataSource }.View;
ICollectionView cvs2= new CollectionViewSource { Source = dataSource }.View;
This will allow you to have individual views.
I currently have a ResourceDictionary file for my WPF application, which pretty much adds every style that I could possibly want throughout all of my application's DataGrids.
Except one.
How can I add a global "IsReadOnly" setter, for all of my DataGrid's DataGridTextColumn columns ?
Basically, I use a few DataGrids, and if I want to display read-only data in a particular column, I'll just display the data using a DataGridTextColumn:
<WPFtoolkit:DataGridTextColumn Binding="{Binding Path=DOB,StringFormat='dd/MMM/yyyy'}" Header="DOB" Width="120" />
However, if I have a column which has editable data, then I'll use a DataGridTemplateColumn instead.
<WPFtoolkit:DataGridTemplateColumn xHeader="Department Name" >
<WPFtoolkit:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Width="175"
ItemsSource="{Binding Source={StaticResource AllDepartmentsDataSource}}"
SelectedValue="{Binding DepartmentID}" SelectedValuePath="DepartmentID" DisplayMemberPath="DepartmentName"
VerticalAlignment="Center"
>
</ComboBox>
</DataTemplate>
</WPFtoolkit::DataGridTemplateColumn.CellTemplate>
</tWPFtoolkit:DataGridTemplateColumn>
The problem is, for every one of my DataGridTextColumns, I specifically need to add the IsReadOnly parameter, otherwise the user can (incorrectly) edit that data:
<WPFtoolkit:DataGridTextColumn IsReadOnly="True" Binding="{Binding Path=DOB,StringFormat='dd/MMM/yyyy'}" Header="DOB" Width="120" />
Is there a way to add this "IsReadOnly" setting globally, in the ResourceDictionary file, to all of my DataGridTextColumns...?
I can add global styles to DataGrid, DataGridColumnHeader, DataGridRow, and DataGridCell, but if I try to define a style with a TargetType of DataGridTextColumn, then Visual Studio complains that DataGridTextColumn is not derived from a FrameworkElement or FrameworkContentElement.
<Style TargetType="{x:Type WPFToolkit:DataGridTextColumn}">
<Setter Property="IsReadOnly" Value="True"/>
</Style>
I can add IsReadOnly to the Grid style, but this makes all columns uneditable !
Can anyone think of an quick and easy way to add this simple property to the DataGridTextColumns ?
Update:
My solution has been (reluctantly) to add a Loaded handler to each of my DataGrids, which runs this code:
void grdGrid_Loaded(object sender, RoutedEventArgs e)
{
DataGrid dg = (DataGrid)sender;
foreach (DataGridColumn col in dg.Columns)
{
DataGridTextColumn textCol = col as DataGridTextColumn;
if (textCol != null)
{
textCol.IsReadOnly = true;
}
else
{
// This DataGridColumn isn't of type "DataGridTextColumn", so do nothing.
}
}
}
You could, of course, put this in your own DataGrid-inherited control, rather than repeating it for each of your DataGrids.
(Sigh.)
Why didn't MS make IsReadOnly an attachable property..? It would've made life so much easier!