WPF - Bind to selecteditem of listbox between user controls - wpf

I have two usercontrols, the first with a listbox that is bound to a list of Customers that displays some simple details for each customer.
The second user control I would like to be a more detailed view of whichever customer is selected in the listbox of the first usercontrol.
Is it possible to set up a binding in the second control to bind to the selected item in the first user control?
My List box:
<ListBox Name="lstCustomer" ItemsSource="{Binding Customers}" >
<ListBox.Resources>
<DataTemplate DataType="{x:Type MyApplication:Customers}">
<Label Grid.Row="0" Content="{Binding Customer.name}" FontSize="14" FontWeight="Bold" Padding="5" />
<Label Grid.Row="1" Grid.Column="0" Content="{Binding Customer.telephone}" Padding="10,5" />
</Grid>
</Grid>
</DataTemplate>
</ListBox.Resources>
</ListBox>
Detailed view Usercontrol (So Far)
<Grid x:Name="containingGrid" DataContext="{Binding ElementName=lstCustomers, Path=SelectedItem}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Customer.name}" FontSize="23"/>
</Grid>
Thanks
Greg

I would suggest to have a property in your ViewModel of Customer object say SelectedCustomer and bind it to the SelectedItem of your listbox like this -
<ListBox Name="lstCustomer" ItemsSource="{Binding Customers}"
SelectedItem = "{Binding SelectedCustomer}" >
. . . . .
</ListBox>
Since you mentioned that both user controls are in same view, so i am assuming that they share a same ViewModel. In that case you can simply set the data context this way -
<Grid x:Name="containingGrid" DataContext="{Binding SelectedCustomer}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontSize="23"/>
</Grid>

Yes, you can - if you give the listbox a name of CustomerList then you can bind to its SelectedItem property using a binding like "{Binding ElementName=CustomerList, Path=SelectedItem}".

Related

How to refine the DataContext locally for a Grid?

I can't find the way to move the reference to property P1 at Grid level.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding P1.Name}"/>
<TextBox Grid.Row="1" Text="{Binding P1.Age}"/>
</Grid>
P1 is a property of the View-Model instance set as DataContext for the Window. It references a Person instance with Name and Age properties. Is there a possibility to "refine" this DataContext for the Grid, so that cells can be bound like:
<Grid DataContext="P1">
<TextBox Grid.Row="0" Text="{Binding Name}"/>
<TextBox Grid.Row="1" Text="{Binding Age}"/>
</Grid>
I'm trying to do this so that different Grid can be bound to different Person (P1, P2, ...).
As kindly suggested by #ASh, the correct syntax is to use a Binding object to set the DataContext. If two Person instances P1 and P2 where to be shown side-by-side, this code would work:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- Binding first grid DataContext to P1 -->
<Grid Grid.Column="0" DataContext="{Binding P1}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding Name}"/>
<TextBox Grid.Row="1" Text="{Binding Age}"/>
</Grid>
<!-- Binding second grid DataContext to P2 -->
<Grid Grid.Column="1" DataContext="{Binding P2}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding Name}"/>
<TextBox Grid.Row="1" Text="{Binding Age}"/>
</Grid>
</Grid>

ItemsControl Height Issue

I am trying to have the height of an itemscontrol be set to what is defined in the grid row definitions. If I set the Height on the itemscontrol manually, it of course affects the control. How can I bind to or achieve this behavior? I just want my itemscontrol size to be determined by the grid. Thanks!
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="600"/>
<RowDefinition Height="500"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ItemsControl Grid.Row="1" Grid.Column="0" Name="MIPRegion" cal:RegionManager.RegionName="MIPRegion" />
</Grid>
</ScrollViewer>
You can bind to the ActualHeight property of the RowDefinition.
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="rowDef0" Height="600"/>
<RowDefinition x:Name="rowDef1" Height="500"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ItemsControl Height="{Binding Path=ActualHeight, ElementName=rowDef1}"
Grid.Row="1" Grid.Column="0" Name="MIPRegion"
cal:RegionManager.RegionName="MIPRegion" />
</Grid>
</ScrollViewer>
Try this
I havent use Actualheight and actualwidth for binding as Width and height itself is of type GridLength.
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="600"/>
<RowDefinition x:Name="RowHeight" Height="500"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" x:Name="ColumnWidth"/>
</Grid.ColumnDefinitions>
<ItemsControl Grid.Row="1" Background="Green" Width="{Binding ElementName=ColumnWidth,Path=Width}" Height="{Binding ElementName=RowHeight,Path=Height}" Grid.Column="0" Name="MIPRegion" >
</ItemsControl>
</Grid>
</ScrollViewer>
In my case RowDefinition's Height was set * and it only worked when I bound the ItemsControl.Height to the Height property, not the ActualHeight. I then realized that such a binding between double and GridLenght is not correct.
(Value produced by BindingExpression is not valid for target property.; Value='*' BindingExpression:Path=Height;) But still I confirm that in some case binding to the ActualHeight is not working as expected.

TreeViewItem Tooltip Binding Not Working

I have a treeview. It's bound to an ObservableCollection called Nodes. The bound data on the tool tips is not showing:
<controls:TreeViewEx BorderThickness="0"
ItemsSource="{Binding Nodes}"
SelectedItemEx="{Binding SelectedTreeNode, Mode=TwoWay}">
<controls:TreeViewEx.ToolTip>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Row="0"
Grid.Column="0"
Source="/FMG.UI.WPF;component/Media/Images/job_128.png"
Height="16"
Width="16"/>
<TextBox Grid.Row="0"
Grid.Column="1"
Text="Job: "
FontWeight="Bold"/>
<TextBox Grid.Row="0"
Grid.Column="2"
Text="{Binding ToolTipHeader}"/>
<Border Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Height="2"
BorderBrush="Gray"/>
<TextBox Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3"
Text="{Binding ToolTipDetails}"/>
</Grid>
</controls:TreeViewEx.ToolTip>
</controls:TreeViewEx>
The tooltip pops up, but the ToolTipHeader and and ToolTipDetails are blank. The Output window says it can't find them on the view model. How do I make the binding look on the Node, not the view model?
You probably want to move the code; use the TreeView.ItemContainerStyle and add a Setter for the ToolTip, this will set a node-level tool-tip.
e.g.
<controls:TreeViewEx.ItemContainerStyle>
<Style TargetType="controls:TreeViewItemEx"> <!-- Guessing at item type name here -->
<Setter Property="Tooltip">
<Setter.Value>
<!-- Move your tooltip here -->
</Setter.Value>
</Setter>
</Style>
</controls:TreeViewEx.ItemContainerStyle>
Of course the DataContext for all the bindings in the tooltip will be the current item, if you want the context of the tree-view specify a RelativeSource that finds it (also prepend "DataContext" on the Path, otherwise you bind to properties directly on the tree-view).

How Datacontext is specified can not understand

Here in mMaterialCentreGroupListView.xaml file, this line is written for MaterialCentreGroupView . But I can not see any data context for accessing viewmodel's property. It is working good. Below is code.
<vw:MaterialCentreGroupView
Style="{StaticResource DetailedViewStyle}"
DataContext="{Binding SelectedMaterialCentreGroup}"/>
the view
<UserControl x:Class="MyBooks.View.MaterialCentreGroupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MinWidth="290" MaxWidth="290" Padding="20"
Background="#eee">
<UserControl.Resources>
<ResourceDictionary Source="ViewResources.xaml" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label
Grid.Row="0" Grid.Column="0"
Content="{Resx ResxName=MyBooks.Properties.Strings, Key=AccountCategoryListView_Name_Label}"
HorizontalAlignment="Right"/>
<TextBox
x:Name="CategoryName"
MaxLength="50"
Style="{StaticResource FormControlStyle}"
Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
Text="{Binding Path=Name, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
Please explain to me what happen and how binding is occur?
I would assume the DataContext is either set in the code-behind (file named the same as the .xaml file but with .cs extension). Look for code like DataContext = new SomeViewModel();
Or, if this UserControl is being used within another control, the DataContext could be either explicitly set on it or, if not, it would be inherited from its parent (which may or may not be inherited from its parent, and so on, if not set explicitly in either the XAML or code-behind).
look 'Resx' binding
<Label
Grid.Row="0" Grid.Column="0"
Content="{Resx ResxName=MyBooks.Properties.Strings, Key=AccountCategoryListView_Name_Label}"
HorizontalAlignment="Right"/>
more information about resx binding and usage ,refer the below link
Resx binding and usage

Not able to refer a control in code behind in VS 2008 with WPF

I don't know why but for some reason I am not able to refer to my tbText control in my code behind file. Here is the XAML part:
<ComboBox.ItemTemplate>
<DataTemplate>
<ItemsControl x:Name="ic">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
</Grid>
**<TextBlock x:Name="tbText" Grid.Column="0" Grid.Row="0" Margin="10" />**
<Image Grid.Column="1" Margin="10" Grid.Row="0" Width="100" Height="100" Stretch="Fill">
</Image>
</ItemsControl>
</DataTemplate>
</ComboBox.ItemTemplate>
I cannot refer to the "tbText" control.
You can't refer to it because it is inside an Items control.
You'd have to search the ItemsControl children in order to find the textbox.
See Finding control within wpf items control for ways to do this.

Resources