Dynamically adding controls to View from MVVM - wpf

In WPF, I am using the MVVM model.
I have a View with a Dockpanel and I want to add dynamically StackPanels with a Label and TextBox for all Harddisks found over the Binding.
Therefore my XAML looks like:
<DockPanel Grid.Row="1" HorizontalAlignment="Stretch" Margin="5">
<ItemsControl ItemsSource="{Binding Harddisks}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="2.5,0,0,0">
<Label Content="{Binding Path=Label}" />
<TextBox Text="{Binding Path=GB_Free}" Width="100" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
It should be four Labels and TextBoxes, but only the first Label and TextBox are shown.
Why?

Your items in your ItemsControl are not actually direct children of the DockPanel. You need to change the ItemsControl to specify that the DockPanel is the Panel. The following will cause the ItemsControl to create a DockPanel and place all the items inside it (rather than the StackPanel that ItemsControl uses by default).
More Info: MSDN: ItemsControl.ItemsPanel Property
<ItemsControl ItemsSource="{Binding Harddisks}">
<ItemsControl.ItemsPanel>
<DockPanel Grid.Row="1" HorizontalAlignment="Stretch" Margin="5" />
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="2.5,0,0,0">
<Label Content="{Binding Path=Label}" />
<TextBox Text="{Binding Path=GB_Free}" Width="100" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Related

Synchronize the size of controls that lay in different ItemsCollections

I want to synchronize the width of two controls.
<!--DataContext-->
<DockPanel LastChildFill="True" x:Name="HeaderDockPanel">
<DockPanel LastChildFill="True" MinHeight="60" DockPanel.Dock="Top" DataContext="{Binding Month}" d:DataContext="{d:DesignInstance Type=local:Month}" >
<TextBlock Text="{Binding Name}" Style="{StaticResource TitleTextBlock}" DockPanel.Dock="Left" />
<!--this shoud to set the Width-->
<!--Nested_1 DataContext Model_1-->
<local:DaysLine HorizontalAlignment="Left" Width="{Binding ElementName=HeaderDockPanel, Path=DataContext.DaysHeaderWidth, Mode=TwoWay}" />
</DockPanel>
<!--Nested_1 DataContext Model_2-->
<ListView Grid.Row="1" ItemsSource="{Binding CarBusiness}">
<ItemsControl.ItemTemplate>
<DataTemplate >
<DockPanel d:DataContext="{d:DesignInstance Type=local:CarBusiness}" LastChildFill="True">
<TextBlock Text="{Binding Name}" Style="{StaticResource TitleTextBlock}" DockPanel.Dock="Left" Margin="-6 0 0 0"/>
<!--this shoud to get the Width-->
<!--Nested_2 DataContext Model_3-->
<ItemsControl ItemsSource="{Binding Business}" Style="{StaticResource HorizontalItemsControl}" Width="{Binding DaysHeaderWidth}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:BusinessTextBlock d:DataContext="{d:DesignInstance Type=local:Business}" Business="{Binding}" ColumnWidth="20" HorizontalAlignment="Left" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
</DockPanel>
The problem is that i can't find the source by RelativeSource Binding use FindByName.
The target control whatch on nested DataContext that is an item of the first and i cant set it in without adding to all this models the MyWidth property.
Is there a some enother way to bind them more correct?
I am thinking about a static property but it is not as correct as i want because i have planned to have a several instances of this control.

Set Label Content vertical Center in ItemsControl

Got this XAML for my Data Binded Label:
<ItemsControl
Name="itClblArtiksel"
ItemsSource="{Binding ArtikelInfo}"
Margin="925,45,0,0"
Width="89"
Height="31"
HorizontalAlignment="Left"
VerticalAlignment="Top"
BorderThickness="1"
BorderBrush="Black"
FontWeight="Bold"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label
x:Name="lblArtikelNr"
Content="{Binding ArtNr}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
i already tried to set the VerticalContentAlignment of the ItemsControl and Label to Center but the content dont get centered... any ideas?
EDIT
Picture to demonstrate the situation:
as you can see the bold one (so the one with <itemcontrol>) are in the air
EDIT 2
The accepted answer gave me the final solution:
<ItemsControl Name="itClblArtiksel" ItemsSource="{Binding ArtikelInfo}" VerticalContentAlignment="Center" Height="37" Margin="925,45,236,38" BorderThickness="1" BorderBrush="Black" FontWeight="Bold">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Height="37">
<Label
VerticalAlignment="Center"
x:Name="lblArtikelNr"
Content="{Binding ArtNr}"
/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
setting a Grid around the Label with the same Height as the ItemsControland setting then the VerticalAlignment to Center was the workaround.
This will center the labels vertically within their parents. In your case, this will have no effect because the items are only as tall as their content.
<DataTemplate>
<Label
VerticalAlignment="Center"
x:Name="lblArtikelNr"
Content="{Binding ArtNr}"
/>
</DataTemplate>
If you want them to be visibly centered vertically, you need to give them room for that to happen:
<DataTemplate>
<Grid Height="100">
<Label
VerticalAlignment="Center"
x:Name="lblArtikelNr"
Content="{Binding ArtNr}"
/>
</Grid>
</DataTemplate>
But since your ItemsControl has a fixed height of 31, this will simply make the items larger than their parent, pushing the label out of sight. You need to remove that. I also urge you to consider getting accustomed to using StackPanel and Grid for layout, rather than setting very large margins on everything. The margins method makes it hard to rearrange your UI.
How about setting the VerticalAlignment property of the Label to Center?
<Label x:Name="lblArtikelNr" Content="{Binding ArtNr}" VerticalAlignment="Center" />
This works for me:
<ItemsControl
BorderThickness="1"
BorderBrush="Black"
FontWeight="Bold">
<ItemsControl.Items>
<system:String>wefwefwefwe</system:String>
<system:String>wefwefwefwe</system:String>
<system:String>wefwefwefwe</system:String>
<system:String>wefwefwefwe</system:String>
</ItemsControl.Items>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type system:String}">
<Label Height="50" Foreground="Black" Content="{Binding}" BorderThickness="1"
BorderBrush="Black" VerticalContentAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

TextBox not stretching horizontally

I am unable to stretch the textbox horizontally fit its container.
NOTE:
I do set the HorizontalAlignment property.
I also tried binding the width of the textbox to its containers width.
Neither worked for me.
<ListView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding ConsoleLines}" Background="Black" >
<ListView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding ElementName=UserControl, Path=DataContext.Command, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="OnTextChanged" KeyDown="OnKeyDown"
HorizontalAlignment="Stretch" Padding="5" Background="Black" Foreground="LightGray" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Try setting the ListView.HorizontalContentAlignment Property to Stretch instead. From the linked page:
... you can set the HorizontalContentAlignment property to Stretch, which stretches the child element to fill the allocated space of the parent element
You must have misunderstood the answer, because it certainly does stretch each item across the entire width of the GridView. Try this:
<ListView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding ConsoleLines}"
Background="Black" HorizontalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<TextBox Text="Some simple text" Background="White"
Foreground="LightGray" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
you should set the HorizontalContentAlignment="Stretch" of the ListView
<ListView ItemsSource="{Binding Collection, Source={StaticResource viewmodel}}" Background="Black" HorizontalContentAlignment="Stretch" >
<ListView.ItemTemplate>
<DataTemplate>
<TextBox HorizontalAlignment="Stretch" Padding="0" Background="Green" Foreground="White" Text="" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

WPF - adding user control to listbox

I am trying to add a usercontrol to a ListBox.
My usercontrol contains a collection of basic elements like textbox and dropdowns, in a fashion so that it creates a row of elements.
The code for ListBox in my main window is as -
<GroupBox FontWeight="SemiBold" Foreground="#FF0CAEF9" Name="gbAddProducts" Style="{x:Null}" Header="ADD PRODUCTS" HorizontalAlignment="Left" Margin="0,256,0,0" VerticalAlignment="Top" Width="990" Height="207">
<ListBox Name="lstboxAddProduct" ItemsSource="{Binding Path=AddNewProductRowViewModelList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" BorderThickness="0" Margin="0,10,-2,23">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<ContentControl Content="{Binding AddNewProductRowViewModel}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<Validation.ErrorTemplate>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder x:Name="aepForError"/>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent}" Foreground="White" Background="#DC000C" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</ListBox>
</GroupBox>
Here AddNewProductRowViewModelList is my user control list containing 5 controls.
The Problem that I see is that when I run the code, the screen has 5 rows, ie I can click on the area to figure out theer are 5 rows as that section gets highlighted. But they are not visible.
Could it be some 'bring to front' sort of issue.
Please advise.
Thanks in advance.
I would do it this way instead:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<ContentControl>
<local:AddNewProductRowView Datacontext="{Binding AddNewProductRowViewModel}"/>
</ContentControl>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>

Showing a collection of items inside of a ItemsControl horizontally

Here is the XAML markup:
<ScrollViewer Grid.Column="1" Grid.Row="2" HorizontalScrollBarVisibility="Disabled" Width="990">
<StackPanel Margin="50 0 0 40">
<ItemsControl x:Name="streamList" ItemsSource="{Binding StreamInformations}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10" Orientation="Horizontal" >
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageUrl}" Height="60" />
<StackPanel Margin="10 0 0 0" VerticalAlignment="Center">
<TextBlock Foreground="Black" Text="{Binding ChannelName}" FontSize="12" />
<TextBlock Foreground="#999" Text="{Binding PlayerName}" FontSize="10" />
<TextBlock Foreground="#999" Text="{Binding ViewCount}" FontSize="10" />
</StackPanel>
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
And this is how it looks:
I'd like these items to appear horizontally and flow down when it reaches the edge of the StackPanel.
It seems that currently, each item in my DataContext collection is creating it's own StackPanel, so this isn't what I want.
Any suggestions?
If you change the ItemsPanel template to either a WrapPanel or horizontal StackPanel, you can achieve the effect you are after...
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<!--other stuff here-->
</ItemsControl.ItemTemplate>
</ItemsControl>
In this snippet, the ItemsPanel is set to a WrapPanel oriented horizontally. The ItemTemplate would include the binding and styling you already have...

Resources