Bind to single object in viewmodel - silverlight

I got this property in my viewmodel:
private PushPinModel selectedPushPinModel;
public PushPinModel SelectedPushPinModel
{
get { return selectedPushPinModel; }
set
{
selectedPushPinModel = value;
RaisePropertyChanged(() => SelectedPushPinModel);
}
}
And I want to bind the view to show which one is selected:
<ContentControl DataContext="{Binding SelectedPushPinModel}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Grid Height="100" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="20*"/>
<RowDefinition Height="38*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="91*"/>
<ColumnDefinition Width="389*"/>
</Grid.ColumnDefinitions>
<Border Opacity="0.95" Width="480" Padding="0,0,0,0" BorderThickness="0" HorizontalAlignment="Left" BorderBrush="Transparent" Background="White" Grid.ColumnSpan="2" Grid.RowSpan="2"/>
<Image Width="70" Height="70" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding Icon}" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" />
<TextBlock Text="{Binding Header}" Grid.Column="1" Grid.Row="0" Style="{StaticResource TextboxLabelStyle}"/>
<TextBlock Text="{Binding Body}" Grid.Column="1" Grid.Row="1" Style="{StaticResource DefaultTextBlockStyle}"/>
</Grid>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl >
However I can't get it to work. The bindings is not showing in the view and I'm not getting any binding errors. Is it the correct way to bind to a single object?
I much rather having it like this instead of binding directly with {Binding SelectedPushPinModel.Body} which more dirty.
Any suggestions how to accomplish this?
Thanks

Try this:
<Label Content="{Binding SelectedPushPinModel}" />
See what that gives you (if anything). Also, check the 'output' window for errors.
This line:
<ContentControl DataContext="{Binding SelectedPushPinModel}">
will only work if the DataContext for the ViewModel (Class) has been properly bound higher on the page. If it isn't then the Label binding provided above will show blank.

Solved it, replaced DataContext on the ContentControl with Content
<ContentControl Content="{Binding SelectedPushPinModel}" VerticalAlignment="Top">
Thanks to sircodesalot for pointing me to the right direction!

Related

Two ListBoxes with two (almost similar) templates

I have 2 Listboxes with 2 data templates that are almost identical except that one of them contains TextBox instead of ComboBox.
First Template :
<DataTemplate x:Key="OldPanelsTemplate" DataType="{x:Type VM:CustomPanelBoard}">
<Grid Height="60" Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Height="60" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" BorderBrush="Blue" BorderThickness="1" Width="35" Background="Blue"
Margin="0 0 2 0" >
<TextBlock Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Blue"
Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}, Path=(ItemsControl.AlternationIndex),
Converter={StaticResource IncrementerConverter}}" />
</Border>
<TextBlock Grid.Column="1" Text="{Binding Name}" />
<TextBlock Grid.Column="2" Text="{Binding DistributionSystemName}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="Number of circuits to be copied: "/>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding NumberOfCircuitsToBeCopied}" />
</Grid>
</DataTemplate>
Second Template :
<DataTemplate x:Key="NewPanelsTemplate" DataType="{x:Type VM:CustomPanelBoard}">
<Grid Height="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Height="60" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" BorderBrush="Blue" BorderThickness="1" Width="35" Background="Blue"
Margin="0 0 2 0" >
<TextBlock Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Blue"
Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}, Path=(ItemsControl.AlternationIndex),
Converter={StaticResource IncrementerConverter}}" />
</Border>
<TextBlock Grid.Column="1" Text="{Binding Name}" />
<ComboBox Grid.Column="2" ItemsSource="{Binding ValidDistributionSystemsForPanel}"
SelectedItem="{Binding SelectedValidDistributionSystemsForPanel}" HorizontalAlignment="Stretch"
IsHitTestVisible="{Binding DistributionSystemNotAssigned}" IsEnabled="{Binding DistributionSystemNotAssigned}"
ItemTemplate="{StaticResource DistributionSystemTemplate}" >
</ComboBox>
<TextBlock Grid.Row="1" Grid.Column="1" Text="Number of available ways: "/>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding NumberOfAvailableWays}" />
</Grid>
</DataTemplate>
As you can see they are both almost identical except for this part :
<ComboBox Grid.Column="2" ItemsSource="{Binding ValidDistributionSystemsForPanel}"
SelectedItem="{Binding SelectedValidDistributionSystemsForPanel}" HorizontalAlignment="Stretch"
IsHitTestVisible="{Binding DistributionSystemNotAssigned}" IsEnabled="{Binding DistributionSystemNotAssigned}"
ItemTemplate="{StaticResource DistributionSystemTemplate}" >
</ComboBox>
The problem is whenever i change anything in one of them i have to change the same thing in the other also ... Any way that can merge them in some way and make the combobox the only variable that changes according to which listbox is calling the template ?
Here an attempt on how you can achieve that, but I have to admit that it is messy but answers your question blindly! a better approach would be to properly implement a DataTemplateSelector.
The idea is to decouple the changing parts into two separate DataTemplates and put them into the resources, one with the Combobox and one for the TextBlock in your case:
<DataTemplate x:Key="DataTemplateCombobox">
<ComboBox ItemsSource="{Binding ValidDistributionSystemsForPanel}" ...>
</ComboBox>
</DataTemplate>
<DataTemplate x:Key="DataTemplateTextblock" >
<TextBlock Text="{Binding DistributionSystemName}" ... />
</DataTemplate>
Now those controls will be replaced with a ContentPresenter in your main (common) DataTemplate. The ContentPresenter uses a ContentTemplateSelector to select which sub-DataTemplate to used based on the name of the ListBox on which this DataTemplate is applied, this is why the Content is bound directly o the ListBox using ancestry binding:
<local:ValueDataTemplateSelector x:Key="TemplateSelector"
DefaultDataTemplate="{StaticResource DataTemplateTextblock}"
ComboboxDataTemplate="{StaticResource DataTemplateCombobox}"
TextBlockDataTemplate="{StaticResource DataTemplateTextblock}" />
<DataTemplate x:Key="OldPanelsTemplate">
<Grid Height="60" Margin="0" Name="OldPanelsTemplateGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Height="60" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" BorderBrush="Blue" BorderThickness="1" Width="35" Background="Blue"
Margin="0 0 2 0" >
<TextBlock Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Blue" Text="tex" />
</Border>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}" />
<ContentPresenter ContentTemplateSelector="{StaticResource TemplateSelector}" Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" Grid.Row="0" Grid.Column="2">
</ContentPresenter>
<TextBlock Grid.Row="1" Grid.Column="1" Text="Number of circuits to be copied: "/>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding NumberOfCircuitsToBeCopied}" />
</Grid>
</DataTemplate>
And here how your DataTemplateSelector should be implemented (basically):
public class ValueDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultDataTemplate { get; set; }
public DataTemplate ComboboxDataTemplate { get; set; }
public DataTemplate TextBlockDataTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var lb = item as ListBox;
if (lb is null)
return DefaultDataTemplate;
if (lb.Name == "ListOne")
return ComboboxDataTemplate;
if (lb.Name == "ListTwo")
return TextBlockDataTemplate;
return DefaultDataTemplate;
}
}
Finally, since your sub-DataTemplates lose their DataContexts due to the Content of the ContentPresenter being bound to the ListBox directly, then just hook their DataContexts again using ElementName Binding or something:
<DataTemplate x:Key="DataTemplateCombobox">
<ComboBox DataContext="{Binding ElementName=OldPanelsTemplateGrid, Path=DataContext}" ItemsSource="{Binding ValidDistributionSystemsForPanel}" >
</ComboBox>
</DataTemplate>
<DataTemplate x:Key="DataTemplateTextblock" >
<TextBlock Text="{Binding DistributionSystemName}" DataContext="{Binding ElementName=OldPanelsTemplateGrid, Path=DataContext}"/>
</DataTemplate>
OldPanelsTemplateGrid is the First Grid in the main DataTemplate that should have the valid ListBoxItem DataContext.
Here is the full Xaml code:
</Window ...
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="450" Width="800" >
<Window.Resources>
<DataTemplate x:Key="DataTemplateCombobox">
<ComboBox DataContext="{Binding ElementName=OldPanelsTemplateGrid, Path=DataContext}" ItemsSource="{Binding ValidDistributionSystemsForPanel}" >
</ComboBox>
</DataTemplate>
<DataTemplate x:Key="DataTemplateTextblock" >
<TextBlock Text="{Binding DistributionSystemName}" DataContext="{Binding ElementName=OldPanelsTemplateGrid, Path=DataContext}"/>
</DataTemplate>
<local:ValueDataTemplateSelector x:Key="TemplateSelector"
DefaultDataTemplate="{StaticResource DataTemplateTextblock}"
ComboboxDataTemplate="{StaticResource DataTemplateCombobox}"
TextBlockDataTemplate="{StaticResource DataTemplateTextblock}" />
<DataTemplate x:Key="OldPanelsTemplate">
<Grid Height="60" Margin="0" Name="OldPanelsTemplateGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Height="60" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" BorderBrush="Blue" BorderThickness="1" Width="35" Background="Blue"
Margin="0 0 2 0" >
<TextBlock Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Blue" Text="tex" />
</Border>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}" />
<ContentPresenter ContentTemplateSelector="{StaticResource TemplateSelector}" Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" Grid.Row="0" Grid.Column="2">
</ContentPresenter>
<TextBlock Grid.Row="1" Grid.Column="1" Text="Number of circuits to be copied: "/>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding NumberOfCircuitsToBeCopied}" />
</Grid>
</DataTemplate>
</Window.Resources>
<!--DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=2,AncestorType=DataTemplate}}"-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox x:Name ="ListOne" ItemsSource="{Binding MyCollection}" ItemTemplate="{StaticResource OldPanelsTemplate}"/>
<ListBox x:Name ="LisTwo" ItemsSource="{Binding MyCollection}" ItemTemplate="{StaticResource OldPanelsTemplate}" Grid.Row="1"/>
</Grid>
I managed to solve it by merging them in one template like this:
<DataTemplate x:Key="NewOldPanelsTemplate" DataType="{x:Type VM:CustomPanelBoard}">
<Grid Height="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Height="60" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" BorderBrush="Blue" BorderThickness="1" Width="35" Background="Blue"
Margin="0 0 2 0" >
<TextBlock Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Blue"
Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}, Path=(ItemsControl.AlternationIndex),
Converter={StaticResource IncrementerConverter}}" />
</Border>
<TextBlock Grid.Column="1" Text="{Binding Name}" />
<!-- To have same template for new and old panels we had the two elements (combobox and textblock) for distribution system and toggle visibility by converters according to their groupbox title -->
<ComboBox Grid.Column="2" ItemsSource="{Binding ValidDistributionSystemsForPanel}"
SelectedItem="{Binding SelectedValidDistributionSystemsForPanel}" HorizontalAlignment="Stretch"
IsHitTestVisible="{Binding DistributionSystemNotAssigned}" IsEnabled="{Binding DistributionSystemNotAssigned}"
ItemTemplate="{StaticResource DistributionSystemTemplate}"
Visibility="{Binding RelativeSource={RelativeSource AncestorType=GroupBox, Mode=FindAncestor}, Path=Header,Converter={StaticResource NewPanelsTemplateVisibilityConverter}}">
</ComboBox>
<TextBlock Grid.Column="2" Text="{Binding DistributionSystemName}"
Visibility="{Binding RelativeSource={RelativeSource AncestorType=GroupBox, Mode=FindAncestor}, Path=Header,Converter={StaticResource OldPanelsTemplateVisibilityConverter}}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="Number of available ways: "/>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding NumberOfAvailableWays}" />
</Grid>
</DataTemplate>
and control the visibility of variable parts(ComboBox and TextBlock in my case) with converters like this :
public class OldPanelsTemplateVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((string)value == "Old Panels")
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
}
public class NewPanelsTemplateVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((string)value == "Old Panels")
{
return Visibility.Collapsed;
}
return Visibility.Visible;
}}
The solution above is based on that each of my listboxes is surrounded by groupbox with certain header (In other cases you may want to use ListBox Names in the converter as visibility toggle)
Thanks to #PavelAnikhouski for the idea of converters.
Also i tried the solution of DataTemplateSelector proposed by #SamTheDev and it worked also (Thanks #SamTheDev), but i preferred the converter solution because i didn't feel comfortable with the idea of losing datacontext through using content presenter (The bottom line here is both solutions work and no one is more elegant it is just personal preference)

Access ListBoxItem-Controls from code-behind

in my Silverlight 4 application I have a listbox for which I created an itemtemplate:
<DataTemplate x:Key="ItemTemplate">
<Grid Background="{StaticResource BrushCharacteristicListBoxItemBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="TextBlockCharacteristicName" Text="{Binding Name}" TextTrimming="WordEllipsis" ToolTipService.ToolTip="{Binding Name}" Margin="6,0,2,0" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock x:Name="TextBlockSeperator" Text="=" Grid.Column="1" VerticalAlignment="Center" />
<Border Grid.Column="2" HorizontalAlignment="Right" Margin="2,2,6,2" Background="{Binding FunctionState, Converter={StaticResource ConvertCharacteristicFunctionState2Color}}">
<TextBlock x:Name="TextBlockCharacteristicValue" Text="{Binding CalculatedValue, Converter={StaticResource ConvertDouble2Display}}" Padding="2,0" Foreground="{StaticResource BrushCharacteristicListBoxItemBackground}" ToolTipService.ToolTip="{Binding ValueOrFunc}" MaxWidth="72"/>
</Border>
</Grid>
</DataTemplate>
Now I want to access the Controls defined in the template (i.e. TextBlockCharacteristicName) from the code behind. I need this to manually adapt the size of the Controls, which can't be done in an other way.
I hooked into the LayoutUpdated event, but did not found a way to access the controls.
I have tried it with
((StackPanel)ListBoxCharacteristics.GetItemsHost()).Children
which gives me a the list of the ListBoxItems, but there seems to be no way to get the controls from there. Can anyway help me out with this problem?
Thanks in advance,
Frank
Get the small VisualTreeEnumeration chunk of code from this blog: Visual Tree Enumeration.
Now you can find your "TextBlockCharacteristicName" elements with this code:-
foreach (var textBlock in ListBoxCharacteristics.Descendents()
.OfType<TextBlock>()
.Where(t => t.Name == "TextBlockCharacteristicName") )
{
// Do stuff with each Text block.
}

Windows Phone 7 Silverlight DataTemplate HyperlinkButton content

I'm trying to make a list that is populated by external data and I have a datatemplate for it.
Each element of the list is composed of an image and two textblocks, and is linked to a specific page.
I'm trying to do this but when I wrap the structure with an HyperlinkButton, I just get a blank page.
I don't know if I'm doing something stupid wrong or it's not possible to have so many items in an HyperlinkButton. If it's not possible to do it this way, can someone guide me to the best solution to do this? Here's the code:
<Grid x:Name="ContentPanel" Margin="0,140,0,0" Background="White">
<ListBox HorizontalAlignment="Stretch" Name="itemList" VerticalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<HyperlinkButton>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="480">
<Grid.Background>
<ImageBrush ImageSource="/app;component/Images/degradat_cela.png" Stretch="UniformToFill" AlignmentY="Top" AlignmentX="Left" />
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="430*" />
</Grid.ColumnDefinitions>
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="38" Width="38" Grid.RowSpan="2" Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="#FFFF003F" Padding="1">
<Image HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="listImage" Width="36" Height="36" Source="{Binding image}" />
</Border>
<TextBlock Margin="5 12 0 0" Grid.Column="1" Grid.Row="0" Name="title" Foreground="Black" Text="{Binding title}" FontWeight="Bold" FontSize="18" />
<TextBlock Margin="5 0 0 8" Grid.Column="1" Grid.Row="1" Name="description" Foreground="Black" Text="{Binding subtitle}" FontSize="14" />
</Grid>
</HyperlinkButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I will also accept any suggestions to make my code better, as I'm new to .NET and I probably don't do things the best way!
Remove the HyperlinkButton and instead use the SelectionChanged event of the ListBox. So add this property to your ListBox:
SelectionChanged="myListBox_SelectionChanged"
Then in your code behind do this:
private void myListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if ((sender as ListBox).SelectedIndex == -1)
return;
NavigationService.Navigate(new System.Uri(string.Format("/Drilldown.xaml?Index={0}",(sender as ListBox).SelectedIndex),System.UriKind.Relative));
}
This code assumes a drilldown page that uses a query string to change it's layout. This is just for example. If instead of index you wanted to reference some property of the bound item you could instead do something like this (assuming an ID property):
int itemID = ((sender as ListBox).SelectedItem as MyApp.Model.myItem).ID;
NavigationService.Navigate(new System.Uri(string.Format("/Drilldown.xaml?ID={0}",itemID),System.UriKind.Relative));

WPF - Usercontrol height does not size properly

I have an issue I cannot figure out. I hope I can explain things enough.
Basically, I have a usercontrol that I'm looking to use as a sort of in window modal dialog.
<Grid>
<Rectangle Opacity=".75" Fill="White"/>
<Border Width="425" BorderBrush="LightGray" BorderThickness="2" CornerRadius="20,0,20,0" Padding="3">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="15"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!-- First Name -->
<Label Grid.Row="0" Grid.Column="0" Content="First Name:"/>
<TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding FirstName}" Margin="3"/>
<!-- Last Name -->
<Label Grid.Row="0" Grid.Column="3" Content="Last Name:"/>
<TextBox Grid.Row="0" Grid.Column="4" Grid.ColumnSpan="2" Text="{Binding LastName}" Margin="3"/>
<!-- Address -->
<Label Grid.Row="1" Grid.Column="0" Content="Address:"/>
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="5" Text="{Binding Address}" HorizontalAlignment="Stretch" Margin="3"/>
<!-- City -->
<Label Grid.Row="2" Grid.Column="0" Content="City:"/>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding City}" Margin="3"/>
<!-- State -->
<Label Grid.Row="2" Grid.Column="2" Content="State:"/>
<ComboBox Grid.Row="2" Grid.Column="3" ItemsSource="{Binding States}" SelectedValue="{Binding State}" Margin="3"/>
<!-- Zip Code -->
<Label Grid.Row="2" Grid.Column="4" Content="Zip Code:"/>
<TextBox Grid.Row="2" Grid.Column="5" Text="{Binding ZipCode}" Margin="3"/>
<Button Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="6" Width="100" HorizontalAlignment="Center" Content="Save" Command="{Binding SaveCustomerCommand}"/>
</Grid>
</Border>
</Grid>
I also have a resourcedictionary containing a datatemplate to connect this usercontrol to it's viewmodel.
<DataTemplate DataType="{x:Type vm:CreateCustomerViewModel}">
<view:CreateCustomerView/>
</DataTemplate>
Finally, in the main window viewmodel, I create an instance of the control's viewmodel, and in the main window view, I am using an itemscontrol and binding it's itemssource property to the instance of the control's viewmodel.
<ItemsControl Height="600" Grid.Row="0" ItemsSource="{Binding CreateCustomerViewModel}" Grid.RowSpan="2" />
Now, my issue is using the itemscontrol in the main window, I've tried a few different ways, but I cannot get the control to be the height of the window. I'm not sure if I shouldn't be using an itemscontrol, or what I'm doing wrong. Any help is very much appreciated.
ItemsControl is for collections. By default it uses a StackPanel to contain its child elements, which disallows stretching in the stack direction (Vertical by default). For a single item use ContentControl (the base of things like Button and Label) instead:
<ContentControl Height="600" Grid.Row="0" Content="{Binding CreateCustomerViewModel}" Grid.RowSpan="2" />
You could try the following:
Put your ItemsControl in a Grid.
Declare your ItemsControl with VerticalContentAlignment="Stretch".
It shouldn't make any difference because it's the default setting, but declare your ItemsControl with VerticalAlignment="Stretch" and try removing the Height="600".

WPF ListBox: how to update data with binding

I have listbox that displays information about list of objects:
<ListBox Grid.Column="0" Height="152" Name="CustomersList" HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I would show more detailed information about selected item in another block, but I don't know (and can't find) how to bind selected item to those block data context. I guess it should be something like this:
<Grid Grid.Column="1" DataContext="{Binding Path=ItemSelected, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="250"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Id" VerticalAlignment="Center" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=Id}" VerticalAlignment="Center"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Name" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Path=Name}" VerticalAlignment="Center"/>
<StackPanel Grid.Row="2" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Add new" />
<Button Content="Store changes" />
</StackPanel>
</Grid>
But the problem is that data item to be binded to the grid is not specified anywhere and I don't know how to do that.
Any suggestion would be wellcome.
Thanks!
P.S. I've tried to specify CustomersList.ItemsSource as DataContext for the Grid - this didn't give any result.
You can bind to the SelectedItem property of the ListBox, one way is using ElementName.
<Grid DataContext="{Binding ElementName=CustomersList, Path=SelectedItem}"> </Grid>

Resources