Overriding parent control's datacontext with local datacontext - wpf

I have a Groupbox in which i have multiple Textboxes. All these Textbox derive their Datacontext from that of Groupbox but one of the Textbox in the group needs a different Datacontext.
<GroupBox Header="My Group" Height="150" Width="1132" DataContext="{Binding ContextA}" >
<Grid>
<Label x:Name="lblA" Content="Policy Number:" Margin="6,12,970,92" />
<TextBox x:Name="txtbA" Margin="155,12,0,0" HorizontalAlignment="Left" Height="24" TextWrapping="Wrap" Text="{Binding ValueA}" VerticalAlignment="Top" Width="278" Grid.ColumnSpan="2"/>
<Label x:Name="lblB" Content="Policy Type:" Margin="612,10,334,88" Height="30"/>
<TextBox x:Name="txtbB" Margin="801,12,0,0" HorizontalAlignment="Left" Height="24" TextWrapping="Wrap" DataContext="{Binding ContextB}" Text="{Binding ValueB}" VerticalAlignment="Top" Width="278"/>
</Grid>
</GroupBox>
In the above code txtbA uses the Datacontext same as that of Groupbox.
I want txtbB to have a separate Datacontexti.e. ContextB
But the ContextB is not getting assigned to txtbB. How to solve the problem?
Note:
ContextAand ContextB= list of Entity Framework models.

WPF binding engine look for property in current DataContext. So, in your case binding engine is looking for property ContextB in class ContextA since textBox is inheriting DataContext from parent GroupBox.
What you can do is use more verbose definition for ContextA like this:
<GroupBox Header="My Group" Height="150" Width="1132"
DataContext="{Binding}"> <-- HERE Or can remove setting DC altogether.
<Grid>
<Label x:Name="lblA" Content="Policy Number:" Margin="6,12,970,92" />
<TextBox x:Name="txtbA" Margin="155,12,0,0" HorizontalAlignment="Left"
Height="24" TextWrapping="Wrap"
Text="{Binding ContextA.ValueA}" <-- HERE
VerticalAlignment="Top"
Width="278" Grid.ColumnSpan="2"/>
<Label x:Name="lblB" Content="Policy Type:" Margin="612,10,334,88"
Height="30"/>
<TextBox x:Name="txtbB" Margin="801,12,0,0" HorizontalAlignment="Left"
Height="24"
TextWrapping="Wrap" DataContext="{Binding ContextB}"
Text="{Binding ValueB}" VerticalAlignment="Top" Width="278"/>
</Grid>
</GroupBox>

Related

How to remove element from collection at child control level

I've created UserControl for adding/removing attributes using the buttons. It has ItemsControl with ObservableCollection of attributes bound to it as a ViewModel and button for adding new attribute to collection. Each new attribute creates an entity in collection which is also a UserControl with bound attribute ViewModel and button for deleting itself.
I wanted to write this functionality so the single attribute control (and other controls) can be reusable - and I use it in a few places. Currently adding new attributes works properly, but I can't find any working way for delete button to work properly and remove object from the collection.
I tried to refer through this.Parent, but CustomAttributeControl's parent is null, I tried to refer through Tag or use Prism.Core, but I couldn't implement anything properly for this to work and I couldn't find anyone with similar nested controls problem to base on. It's easy when there is no nested control for single attribute, but here I can't come up with anything. I'm fairly new to WPF and I feel there should be an easy way to do this.
single attribute control
attribute control's XAML:
<UserControl x:Class="xxx.UI.CustomAttributeControl"
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:models="clr-namespace:xxx.ViewModels.Attributes"
mc:Ignorable="d" >
<DockPanel Width="auto" HorizontalAlignment="Stretch" Margin="0,2">
<TextBox Text="{Binding Name}" Height="20" TextWrapping="Wrap" Width="160"/>
<TextBlock Width="60"/>
<ComboBox x:Name="DataType" Height="20" Width="120" SelectionChanged="DataType_SelectionChanged"/>
<TextBlock Width="10"/>
<TextBox Text="{Binding ListValues}" x:Name="ListValues" Height="20" TextWrapping="Wrap" Width="120"/>
<DockPanel HorizontalAlignment="Right">
<CheckBox IsChecked="{Binding Visible}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="20,0"/>
<Button x:Name="Delete" Content="X" Width="22" Height="20" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="20,0"/>
</DockPanel>
</DockPanel>
</UserControl>
list control
list control's XAML:
<UserControl x:Class="xxx.UI.CustomAttributesControl"
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:xxx.UI"
mc:Ignorable="d">
<StackPanel>
<Label FontSize="20">Custom attributes</Label>
<StackPanel>
<DockPanel HorizontalAlignment="Stretch">
<Label Width="160" HorizontalAlignment="Left" HorizontalContentAlignment="Center">Attribute name</Label>
<TextBlock Width="60"/>
<Label Width="120" HorizontalAlignment="Left" HorizontalContentAlignment="Center">Attribute type</Label>
<TextBlock Width="10"/>
<Label Width="120" HorizontalAlignment="Left" HorizontalContentAlignment="Center">List values</Label>
<DockPanel HorizontalAlignment="Right">
<Label Width="60" HorizontalAlignment="Right" HorizontalContentAlignment="Center">Visible</Label>
<Label Width="60" HorizontalAlignment="Right" HorizontalContentAlignment="Center">Delete</Label>
</DockPanel>
</DockPanel>
<ItemsControl ItemsSource="{Binding}"> <!-- it's binding ObservableCollection of custom attributes from parent control -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CustomAttributeControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<DockPanel HorizontalAlignment="Right">
<Button Margin="20,10" Click="AddAttribute">+ Add attribute</Button>
</DockPanel>
</StackPanel>
</StackPanel>
</UserControl>
Code for adding attribute in .xaml.cs:
private void AddAttribute(object sender, RoutedEventArgs e)
{
var attributes = (ObservableCollection<CustomAttribute>)DataContext;
attributes.Add(new CustomAttribute());
}

Databinding to Property of class that in another class with property

What is the correct way to perform databinding if the property (the context in this case) that i bind to is a class (LatestReading class) with its property (Unit).
The datacontext is set to the root of the class. Here's the hierarchy of my class. MonitoringPoint.LatestReading.Unit
<DataTemplate x:Key="TrackBallInfoTemplate"
DataType="{x:Type winGRAPH_Core:MonitoringNode}">
<StackPanel Margin="3">
<Grid Height="Auto">
<StackPanel Height="Auto"
VerticalAlignment="Top"
Orientation="Horizontal">
<TextBlock TextWrapping="Wrap"
Text="{Binding DataPoint.Value, FallbackValue=0.00}"
FontWeight="Bold"
FontSize="16" />
<TextBlock TextWrapping="Wrap"
Text="{Binding LatestReading.Unit, FallbackValue=°C}"
Margin="2,3,0,0" />
</StackPanel>
</Grid>
<Grid Height="Auto">
<TextBlock TextWrapping="Wrap"
Text="{Binding DataPoint.Category, FallbackValue=time}"
d:LayoutOverrides="Width, Height"
FontStyle="Italic"
Margin="0,2,0,0" />
</Grid>
</StackPanel>
</DataTemplate>
If the type that is assigned to your DataContext is a LatestReading then just use the property Unit. The DataContext already set at a higher level (if you've remembered to set it - it's a common mistake to forget) automatically cascades to the child controls.

I unable to get child control from ListBox control in WPF using MVVM

I am in serious trouble. I have listbox control in which i have many combo box. whenever select the value in combo box, i have to make other controls as hidden. i am using MVVM pattren. i am unable to get the child controls from ListBox control but i can get the ListBox control in viewmodel. How can i get these controls in viewmodel? Is it possible? I am using framework 4.0. i have shown the code below which write in view.
<ListBox x:Name="lstItems" MaxHeight="300" FontSize="11" Margin="12,0,20,38" ItemsSource="{Binding Source={StaticResource listedView}, Path=myItemsSource, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<ListBox.ItemTemplate >
<DataTemplate>
<Border BorderBrush="Blue" Margin="0,4,0,4" BorderThickness="1" CornerRadius="5">
<StackPanel Orientation="Horizontal">
<Label Content="Show rules where:" Name="lblshowrules"></Label>
<ComboBox x:Name="cboShowRuleWhere" Height="20" Width="200" ItemsSource="{Binding Source={StaticResource listedView}, Path=FilterRules}" DisplayMemberPath="RuleName" SelectedValuePath="RuleId" SelectedValue="{Binding Source={StaticResource listedView}, Path=SelectedRuleName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" ></ComboBox>
<Grid Height="29" HorizontalAlignment="Left" Name="grid1" VerticalAlignment="Top" Width="496" Grid.Row="1" Margin="0,0,0,0">
<ComboBox Height="21" HorizontalAlignment="Left" Margin="6,4,0,0" x:Name="cboRuleCondtion" VerticalAlignment="Top" Width="212" />
<TextBox Height="20" HorizontalAlignment="Left" Margin="242,3,0,0" x:Name="txtValue" VerticalAlignment="Top" Width="245" Visibility="Hidden"/>
<ComboBox Height="21" HorizontalAlignment="Left" Margin="224,3,0,0" x:Name="cboValue" VerticalAlignment="Top" Width="205" Visibility="Hidden" />
<DatePicker Height="28" HorizontalAlignment="Left" Margin="242,-3,0,0" x:Name="dtpFromDate" VerticalAlignment="Top" Width="98" Visibility="Hidden" />
<DatePicker Height="31" HorizontalAlignment="Left" Margin="346,-3,0,0" x:Name="dtpToDate" VerticalAlignment="Top" Width="98" Visibility="Hidden"/>
</Grid>
<Button Name="cmdAddLevel" Padding="0" Margin="-1,1,0,-1" Width="75" Command ="{Binding Source={StaticResource listedView}, Path=AddLevelCommand, UpdateSourceTrigger=PropertyChanged}" BorderBrush="White" BorderThickness="1" Height="25" HorizontalContentAlignment="Center">
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16" HorizontalAlignment="Left" Margin="1,0,0,-1">
</Image>
<TextBlock Text="Add Level" FontWeight="Bold" Height="16" Width="70" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="8,2,0,-1" />
</StackPanel>
</Button>
<Label Name="lblDeleteLevel" Margin="3,0,0,0" Width="75" TabIndex="7" HorizontalAlignment="Left">
<Hyperlink >
<TextBlock Text="Delete Level" />
</Hyperlink>
</Label>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
Please help me. once again, i want to know how to get the child control from parent control... Is it possible?
Using the MVVM pattern, you should not be referencing any of the controls directly. Alternatively, you should create a boolean property on your viewmodel that decides if various controls should be visible. Then bind the Visibility property of the controls you want to hide to this property, using a converter.
See this previous Q/A for details on visibility converters: Link

Can't get focus on a TextBox inside a ListBox using Silverlight

I'm having a little trouble in silverlight with a databound ListBox containing databound TextBox elements. The items display correctly in the list and the TextBox is populated correctly but I can't get focus on the TextBox in the list. If I hover over the edges of the TextBox it highlights but it won't let me click into it to edit the text. Any ideas?
My XAML looks like this:
<ListBox x:Name="listImages">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="LayoutRoot" Background="White">
<Image Height="102" HorizontalAlignment="Left" Name="imgThumb" Stretch="UniformToFill" VerticalAlignment="Top" Width="155" Source="{Binding ImageFilename, Converter={StaticResource ImageConverter}}" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="154,25,0,0" Name="txtAltText" VerticalAlignment="Top" Width="239" Text="{Binding Alt}" />
<dataInput:Label Height="19" HorizontalAlignment="Left" Margin="154,6,0,0" Name="lblAltText" VerticalAlignment="Top" Width="239" Content="Alt Text" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I swapped the content for this and it now works, I think it was having an issue with the Grid container:
<ListBox x:Name="listImages">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Height="102" HorizontalAlignment="Left" Name="imgThumb" Stretch="UniformToFill" VerticalAlignment="Top" Width="155" Source="{Binding ImageFilename, Converter={StaticResource ImageConverter}}" Margin="5" />
<StackPanel>
<dataInput:Label Height="19" HorizontalAlignment="Left" Name="lblAltText" VerticalAlignment="Top" Width="239" Content="Alt Text" />
<TextBox Height="23" HorizontalAlignment="Stretch" Name="txtAltText" VerticalAlignment="Top" Text="{Binding Alt}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

ItemsSource on wpf ComboBox getting reset?

I have a ComboBox setup in xaml and have set the ItemsSource binding. When I run the project nothing shows up in the ComboBox. If I inspect it with snoop the ItemsSource of the ComboBox is blank.
Anyone come across this before?
I checked the binding errors this is the error it displays
System.Windows.Data Error: 39 : BindingExpression path error: 'WasteTypeData' property not found on 'object' ''JobItems' (HashCode=28494546)'. BindingExpression:Path=WasteTypeData; DataItem='JobItems' (HashCode=28494546); target element is 'ComboBox' (Name='CboWasteTypes'); target property is 'ItemsSource' (type 'IEnumerable')
WasteTypeData is a public property of ObservableCollection<WasteTypes>.
This is what I have set as the binding of the ComboBox and if I debug the app WasteTypeData is populated with the list of WasteTypes as expected.
I can't figure out why it's looking for WasteTypeData on object JobItems. The WasteTypeData property is not found on the object JobItems.
JobItemsData is a public property of ObservableCollection<JobItems>.
My xaml has a ListBox with its ItemsSource Binding set to JobItemsData.
The ListBox has a DataTemplate with a couple of TextBoxes and one ComboBox. All the TextBoxes display their data properly.
Here's xaml if it will help shed any light on what's going on:
<UserControl
x:Class="WorkItems.View.ViewJobItems"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:JobItemsViewModel="clr-namespace:WorkItems.ViewModel"
Height="300" Width="500">
<ListBox
x:Name="LstJobItems"
ItemsSource="{Binding JobItemsData}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel
Grid.Column="0"
Margin="5">
<StackPanel
Orientation="Horizontal"
Margin="0,5,0,0">
<Label
Content="Customer Details"
FontWeight="Bold"
FontSize="24"></Label>
</StackPanel>
<StackPanel
Orientation="Horizontal">
<Line
StrokeThickness="3"></Line>
</StackPanel>
<StackPanel
Orientation="Horizontal"
Margin="0,5,0,0">
<Label
Content="Customer: "
FontWeight="Bold"
Width="110" />
<TextBox
Text="{Binding Customer, Mode=OneWay}"
Width="200" />
</StackPanel>
<StackPanel
Orientation="Horizontal"
Margin="0,5,0,0">
<Label
Content="Address: "
FontWeight="Bold"
Width="110" />
<TextBox
Text="{Binding Address1, Mode=OneWay}"
Width="200" />
</StackPanel>
<StackPanel
Grid.Column="1"
Margin="5">
<StackPanel
Orientation="Horizontal"
Margin="0,5,0,0">
<Label
Content="Job Details"
FontWeight="Bold"
FontSize="24"></Label>
</StackPanel>
<StackPanel
Orientation="Horizontal">
<Line
StrokeThickness="3"></Line>
</StackPanel>
<StackPanel
Orientation="Horizontal"
Margin="0,5,0,0">
<Label
Content="Date: "
FontWeight="Bold"
Width="110" />
<TextBox
Text="{Binding JobDate, Mode=OneWay}"
Width="200" />
</StackPanel>
<StackPanel
Orientation="Horizontal"
Margin="0,5,0,0">
<Label
Content="Waste Type: "
FontWeight="Bold"
Width="110" />
<ComboBox
x:Name="CboWasteTypes"
IsEditable="False"
ItemsSource="{Binding Path=WasteTypeData}"
DisplayMemberPath="WasteType"
SelectedValuePath="WasteTypeID"
SelectedValue="{Binding WasteTypeID}"
Width="200" />
</StackPanel>
<StackPanel
Orientation="Horizontal"
Margin="0,5,0,0">
<Label
Content="Status: "
FontWeight="Bold"
Width="110" />
<TextBox
Text="{Binding Status, Mode=OneWay}"
Width="200" />
</StackPanel>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Thanks
Paul
Check the Output window for any binding errors. You may have misspelled something or not set the DataContext correctly.
I think its failing because when you use {Binding Path=WasteTypeData} in your combobox, it expects to find it as a property in JobsItems instead of the observable collection, since that is what the parent control (your ListBox) is bound to.
Add WasteTypeData as a static resource in your user control, then bind your combobox to that, specifying it using "{Binding Source={StaticResource..."
<UserControl
...
xmlns:local="WorkItems"
...
Height="300" Width="500">
<UserControl.Resources>
<local:WasteTypeData x:Key="WasteTypeData"/>
</UserControl.Resources>
..
<ComboBox
x:Name="CboWasteTypes"
IsEditable="False"
ItemsSource="{Binding Source={StaticResource WasteTypeData}}"
DisplayMemberPath="WasteType"
SelectedValuePath="WasteTypeID"
SelectedValue="{Binding WasteTypeID}"
Width="200" />
See if that helps!

Resources