Alignment of ListBox items - wpf

I am trying to set the alignment of the contents in the ListBox below. I have wrapped the ListBox inside a ScrollViewer to make it scroll horizontally.
Each element of the Listbox is a Stackpanel and I am trying to align each one to the Top and to set the width to auto for each.
Right now, the stackpanels are centered vertically and the width of each one is the same and is represented by the width of the largest panel.
I have put HorizontalContentAlignment="Left" and VerticalContentAlignment="Top", as I have read in similar posts but it does not change anything.
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" >
<ListBox ItemsSource="{Binding Termene}" SelectedItem="{Binding SelectedTermenCondica}" HorizontalContentAlignment="Left" VerticalContentAlignment="Top">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate >
<DataTemplate >
<StackPanel Margin="2" >
<StackPanel.Resources>
<CollectionViewSource Source="{Binding Dosare}" x:Key="dosareView" IsLiveSortingRequested="True" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Ora" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<Style x:Key="NoFocusColumStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
</StackPanel.Resources>
<TextBlock Text="{Binding NumeComplet, StringFormat='Complet {0}'}" HorizontalAlignment="Center" FontWeight="Bold" VerticalAlignment="Top"></TextBlock>
<TextBlock Text="{Binding TermenCB, StringFormat='Termen: {0}'}" HorizontalAlignment="Center" FontWeight="Bold" VerticalAlignment="Top"></TextBlock>
<DataGrid IsSynchronizedWithCurrentItem="True" CellStyle="{StaticResource NoFocusColumStyle}" IsReadOnly="True" ItemsSource="{Binding Source={StaticResource dosareView}}" Style="{StaticResource DGRapaorte}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="Nr. dosar" Binding="{Binding NumarDosar}"/>
<DataGridTextColumn CanUserSort="True" SortDirection="Ascending" SortMemberPath="Ora" Header="Ora" Binding="{Binding Ora, StringFormat={}{0:HH:mm}}" />
<DataGridTextColumn Header="Obiect" Binding="{Binding Obiect}"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
Later edit:
I have added some data (three items in Termene to show you how it looks. I have blurred them out, but you can see the issue.
Here is how it looks right now:
Scrolled further:
Now, here is how I would like it to look like:
As you can see, the height and width of every item is set with the width and height of the largest item.

Replace the Uniformgrid part with this:
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
Source: https://stackoverflow.com/a/3565590/4394435
This example worked for me:
<Window x:Class="WpfMVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfMVVM"
mc:Ignorable="d"
Title="MainWindow" Height="500" Width="500">
<ListBox ItemsSource="{Binding Items}" VerticalContentAlignment="Top">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="2">
<TextBlock Text="test" HorizontalAlignment="Center" FontWeight="Bold" />
<TextBlock Text="blub" HorizontalAlignment="Center" FontWeight="Bold" />
<DataGrid IsSynchronizedWithCurrentItem="True" IsReadOnly="True"
ItemsSource="{Binding DataGridItems}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Nr. dosar" Binding="{Binding Text}" />
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
with this viewModel
public class DataViewModel
{
public DataViewModel()
{
}
public List<Item> Items { get; set; } = new List<Item>()
{
new Item(){DataGridItems = new List<DataGridItem>(){new DataGridItem() { Text = "a"} }},
new Item(){DataGridItems = new List<DataGridItem>(){new DataGridItem() { Text = "aaaaaaaaaaa"} }},
new Item(){DataGridItems = new List<DataGridItem>(){new DataGridItem() { Text = "aaaaaaaaaaaaaaaaaa"} }},
new Item(){DataGridItems = new List<DataGridItem>()
{
new DataGridItem() { Text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
new DataGridItem() { Text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
new DataGridItem() { Text = "aaa"},
new DataGridItem() { Text = "aaaaaaaaaa"}
}}
};
}
public class Item
{
public List<DataGridItem> DataGridItems { get; set; }
}
public class DataGridItem
{
public string Text { get; set; }
}

Related

Use ControlTemplate from resource in a DataGridColumn

I created a datagrid that is populated from a list. The list implementation is like this.
ObservableCollection<CFImportResult> CFImportResults
public class CFImportResult
{
public string CFComponentName { get; set; }
public string CFport { get; set; }
public PortType CFPortType { get; set; }
public string PlatformCompName { get; set; }
public string PlatformCompPort { get; set; }
public PortType PlatformCompType { get; set; }
public string Result { get; set; }
}
Here two of the grid columns are special that they shows both an image and a text. XAML is given below.
<DataGrid ItemsSource="{Binding Path=CFImportResults}" Height="500" AutoGenerateColumns="False" CanUserAddRows="False" VerticalAlignment="Top" Background="Transparent" VerticalScrollBarVisibility="Auto" BorderBrush="Gray">
<DataGrid.Columns>
<DataGridTextColumn Header="CF Component" Binding="{Binding Path=CFComponentName}" Width="140"/>
<DataGridTemplateColumn Header="CF port" Width="140">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16" Source="{Binding CFPortIcon}"/>
<TextBox Text="{Binding CFport}" BorderBrush="Transparent"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Platform Component" Binding="{Binding Path=PlatformCompName}" Width="140"/>
<DataGridTemplateColumn Header="Platform port" Width="140">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16" Source="{Binding PlatformCompIcon}"/>
<TextBox Text="{Binding PlatformCompPort}" BorderBrush="Transparent"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Status" Binding="{Binding Path=Result}" Width="140"/>
</DataGrid.Columns>
</DataGrid>
This is working fine. Now I want to move the DataTemplate part to the ResourceDictionary section. I tried to create a ControlTemplate with the TextBox and Image controls. But i don't know how to use it inside the DataGridTextColumn (It doesn't have any ItemSource field). Is this really possible?
<ResourceDictionary>
<ControlTemplate x:Key="PortTemplate" TargetType="{x:Type DataGridCell}">
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16" Source="{Binding CFPortIcon}"/>
<TextBox Text="{Binding CFport}" BorderBrush="Transparent"/>
</StackPanel>
</ControlTemplate>
</ResourceDictionary>
<DataGridTextColumn Header="CF port" ????="{StaticResource PortTemplate}" Width="140"/>
Move the DataTemplates to the ResourceDictionary and give them an x:Key:
<DataTemplate x:Key="a">
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16" Source="{Binding CFPortIcon}"/>
<TextBox Text="{Binding CFport}" BorderBrush="Transparent"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="b">
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16" Source="{Binding PlatformCompIcon}"/>
<TextBox Text="{Binding PlatformCompPort}" BorderBrush="Transparent"/>
</StackPanel>
</DataTemplate>
You can then set the CellStyle properties of the DataGridTemplateColumns using the StaticResource markup extension like this:
<DataGrid ItemsSource="{Binding Path=CFImportResults}" Height="500" AutoGenerateColumns="False" CanUserAddRows="False" VerticalAlignment="Top" Background="Transparent" VerticalScrollBarVisibility="Auto" BorderBrush="Gray">
<DataGrid.Columns>
<DataGridTextColumn Header="CF Component" Binding="{Binding Path=CFComponentName}" Width="140"/>
<DataGridTemplateColumn Header="CF port" Width="140" CellStyle="{StaticResource a}" />
<DataGridTextColumn Header="Platform Component" Binding="{Binding Path=PlatformCompName}" Width="140"/>
<DataGridTemplateColumn Header="Platform port" Width="140" CellStyle="{StaticResource b}" />
<DataGridTextColumn Header="Status" Binding="{Binding Path=Result}" Width="140"/>
</DataGrid.Columns>
</DataGrid>
A DataGridTextColumn has no concept of a template though.
Also note that you still need to define two separate data templates because the binding paths in them differ.

Getting ContextMenu on DataGrid in WPF/MVVM

UPDATE!!!
I've discovered that even this doesn't work when I put it in the DataGrid:
<DataGrid.ContextMenu>
<ContextMenu >
<MenuItem Header="Add Divider" Click="MenuItem_Click" />
</ContextMenu>
</DataGrid.ContextMenu>
This definitely works in a dummy project set up from scratch. So I don't think I'm having binding problems or datacontext problems.... I'm not getting that far. I suspect that some other part of the program is intercepting and handling the context menu (or right click). I didn't write the original code and it's a large code base. Can someone give me an idea what I should be looking for? What would stop the ContextMenu on the DataGrid from being called. Note that the DataGrid is in a ScrollViewer and StackPanel and the whole control is part of a larger window. In fact, it is one of many tabs.
-END UPDATE
I'm pulling my hair out trying to get a context menu on my DataGrid in my WPF/MVVM project. I post the XAML and ViewModel below. I would like to be able to right click on a row and call a command in the ViewModel that would change one of the column entries for that row.
The XAML (I call out what I think are the key points below)
<UserControl x:Class="Sears.UserInterface.Views.Technician.Alerts.AlertsLogView"
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:Sears.UserInterface.Views.Technician.Alerts"
xmlns:converters="clr-namespace:Common.Controls.Converters;assembly=Common.Controls"
mc:Ignorable="d"
d:DesignHeight="800"
d:DesignWidth="1200">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
</UserControl.Resources>
<StackPanel Orientation="Horizontal">
<ScrollViewer>
<DataGrid Width="1000"
Margin="0"
HorizontalAlignment="Left"
AutoGenerateColumns="False"
Background="Transparent"
DataContext="{Binding}"
HeadersVisibility="Column"
ItemsSource="{Binding Alerts}"
SelectedItem="{Binding SelectedItemProperty, Mode=TwoWay}"
RowBackground="Transparent"
RowHeight="30"
Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}"
>
**<DataGrid.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Command="{Binding CloseAlertCommand}" Header="Close Alert"/>
</ContextMenu>
</DataGrid.ContextMenu>**
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" Header="Id">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Id}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="TimeStamp">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding AlertTime}" >
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Severity">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Severity}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="AlertText">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding AlertText}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Details">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Details}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Active">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Active}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Acknowledged">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Acknowledged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Reported">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Reported}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Status}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Resolution">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Resolution}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Category">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center"
Padding="5"
Text="{Binding Category}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
</StackPanel>
Notice the DataGrid.ContextMenu part. I've searched StackOverflow and tried various ideas to get the contextmenu showing up. Nothing. This particular example uses "Tag". I also tried putting the contextmenu in the resources sections as:
<ContextMenu x:Key="DataRowContextMenu" DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}}">
<MenuItem x:Name="RowContMenuTransfer" Header="Close Alert" Command="{Binding DataContext.CloseAlertCommand}" CommandParameter="{Binding}" >
</MenuItem>
</ContextMenu>
The "Tag" way of doing it results in no binding errors. You just right click and nothing! Other ways (which I can post) gave binding errors in the output window. Possibly of note is the fact that the DataGrid is inside a ScrollViewer and StackPanel.
Here is the ViewModel
public class AlertsLogViewModel : ViewModelBase, IAlertsLogViewModel, IDisposable
{
private IAlertManager _model;
private readonly object _lock = new object();
private ICommand _closeAlertCommand;
public AlertsLogViewModel(IAlertManager model) : base("AlertsLogViewModel")
{
Alerts = new ObservableCollection<IAlert>();
_model = model ?? throw new ArgumentNullException("model");
_model.AlertStatusUpdated += _model_AlertStatusUpdated;
UpdateAlerts();
}
public IAlert SelectedItemProperty { get; set; }
public ICommand CloseAlertCommand
{
get { return _closeAlertCommand ?? (_closeAlertCommand = new DelegateCommand(CloseAlert)); }
}
private void CloseAlert()
{
_model.CloseAlert(SelectedItemProperty.SystemErrorGuid);
}
public ObservableCollection<IAlert> Alerts { get; private set; }
private void _model_AlertStatusUpdated(object sender, DataAccess.AlertStatusEventArgs e)
{
UpdateAlerts();
}
private void UpdateAlerts()
{
RunOnDispatcher(() =>
{
lock (_lock)
{
var modelAlerts = _model.GetAlerts().OrderBy(p => (int)p.Status).ThenByDescending(p => p.AlertTime);
Alerts.Clear();
if (modelAlerts != null)
{
foreach (var alert in modelAlerts)
{
Alerts.Add(alert);
}
}
}
}
);
NotifyPropertyChanged("Alerts");
}
public void Dispose()
{
if (_model != null)
_model.AlertStatusUpdated -= _model_AlertStatusUpdated;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Note the CloseAlertCommand and SelectedItemProperty. I do see that SelectedItemProperty is being called when I left click, but not right click. CloseAlert is never called.
Finally, in case it's relevant, let me mention that the AlertsLogView is inside a Technicial.xaml page and it is here that it's bound to the ViewModel:
<TabItem Header="Alerts"
PreviewMouseDown="OnPreviewMouseDown"
PreviewTouchDown="OnPreviewTouchDown">
<alertlog:AlertsLogView Margin="5"
DataContext="{Binding AlertsLogViewModel}" />
</TabItem>
Many thanks for any hints, references, pointers or solutions!
-Dave
So, as I have already written in comments, the binding works. I have thought, that you get ContextMenu invoked, but you write you didn't. MouseRightButtonClick can be intercepted by several things:
Implicit or explicit styles for grid or it's parents(If explicit -
comment it out, if implicit - set your own dummy style)
Behaviors for grid or it's parents(comment it out)
Code behind(check, whether there are event handlers in grid or it's parents)
Make it consistently and you will find what is responsible for the issue.

I need Horizontal view of list boxes

I am working on list boxes in WPF. I want to show the list boxes in horizontal direction. My code is
<Grid>
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
<ItemsControl x:Name="list" >
<ItemsControl.ItemTemplate>
<HierarchicalDataTemplate>
<Border Padding="5,0,0,2">
<WrapPanel Orientation="Horizontal">
<ListBox Name="mylistBox" Width="200" Height="200">
<Label Content="{Binding name}"/>
<Label Content="{Binding phone}"/>
<Label Content="{Binding email}"/>
<TextBox Name="NameTxt" Width="20" Height="20" Text="{Binding Path=Contact1.name}"></TextBox>
</ListBox>
</WrapPanel>
</Border>
</HierarchicalDataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
and my program looks like in the picture (Vertical)
Can anyone tell me how I can change the view?
thanks in advance.
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
<ItemsControl x:Name="list" ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<HierarchicalDataTemplate>
<Border Padding="5,0,0,2">
<ListBox Name="mylistBox"
Width="200"
Height="200">
<Label Content="{Binding name}" />
<Label Content="{Binding phone}" />
<Label Content="{Binding email}" />
<TextBox Name="NameTxt"
Width="20"
Height="20"
Text="{Binding Path=Contact1.name}" />
</ListBox>
</Border>
</HierarchicalDataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Your itemscontrol doesn't provide a custom ItemsPanel, then a StackPanel is used as a default with vertical Orientation.
Try add:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
You can either use a WrapPanel or a StackPanel depending on your requirements.
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
The documentation for IsItemsHost has an example of a horizontal list box.
Try a WrapPannel, which will lay the items out horizontally until there is no more room, and then move to the next line.
You also could use a UniformGrid, which will lay the items out in a set number of rows or columns.
The way we get the items to arange using these other panels in a ListView, ListBox, or any form of ItemsControl is by changing the ItemsPanel property. By setting the ItemsPanel you can change it from the default StackPanel that is used by ItemsControls. With the WrapPanel we also should set the widths as shown here.
<ListView>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
ItemWidth="{Binding (ListView.View).ItemWidth, RelativeSource={RelativeSource AncestorType=ListView}}"
MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
ItemHeight="{Binding (ListView.View).ItemHeight, RelativeSource={RelativeSource AncestorType=ListView}}" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
...
</ListView>
I post this answer because of informational purposes as an alternative way of doing things:
Entities/Classes:
public class Person
{
public string Name { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public Contact Contact1 { get; set; }
}
public class Contact
{
public string Name { get; set; }
}
Code Behind:
Persons = new List<Person>( );
for ( int i = 0; i < 15; i++ )
{
Persons.Add( new Person( )
{
Name = String.Format( "Name {0}" , i ) ,
Phone = String.Format( "Phone 0000000-00{0}" , i ) ,
Email = String.Format( "Emailaddress{0}#test.test" , i ) ,
Contact1 = new Contact { Name = String.Format("Contact name = {0}", i) }
} );
}
list.DataContext = Persons;
Xaml proposal 1:
<ListBox x:Name="list" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Label Content="{Binding Path=Name}"/>
<Label Content="{Binding Path=Phone}"/>
<Label Content="{Binding Path=Email}"/>
<TextBox Height="20" DataContext="{Binding Path=Contact1}" Text="{Binding Path=Name}" Width="110"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
Xaml proposal 2:
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ItemsControl x:Name="list" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListBox>
<Label Content="{Binding Path=Name}"/>
<Label Content="{Binding Path=Phone}"/>
<Label Content="{Binding Path=Email}"/>
<TextBox Height="20" DataContext="{Binding Path=Contact1}" Text="{Binding Path=Name}" Width="110"/>
</ListBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>

accordion contenttemplate communication with viewmodel

In a silverlight 5 mvvm project I have the following code:
View:
<navigation:Page x:Class="LobDemo.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
DataContext="{Binding Source={StaticResource Locator}, Path=Main}" >
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<toolkit:DockPanel Grid.Column="0">
<toolkit:Accordion Name="accordion1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Path=MenuItems}"
Margin="5,5,5,5">
<toolkit:Accordion.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</toolkit:Accordion.ItemTemplate>
<toolkit:Accordion.ContentTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Path=SubMenuItems}"
Margin="2 2 0 0"
BorderThickness="0"
SelectedItem="{Binding Path=SelectedMenuItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</toolkit:Accordion.ContentTemplate>
</toolkit:Accordion>
</toolkit:DockPanel>
</Grid>
ViewModel: (I'm only showing the required properties)
public ObservableCollection<MenuItem> MenuItems
{
get { return _menuItems; }
set
{
_menuItems = value;
RaisePropertyChanged("MenuItems");
}
}
public object SelectedMenuItem
{
get { return _selectedMenuItem; }
set
{
_selectedMenuItem = value;
RaisePropertyChanged("SelectedMenuItem");
}
}
MenuItem:
public string Name { get; set; }
public ObservableCollection<SubMenuItem> SubMenuItems { get; set; }
SubMenuItem:
public string Name { get; set; }
The code is working fine, my MenuItems are visible in the accordion control, the SubMenuItems are also loaded in the listbox. The problem comes when I select one of the items in the listbox, I want the selected item reported back to my ViewModel as SelectedMenuItem. But the property SelectedMenuItem is never filled, so I'm guessing the code cannot resolve the location of the property.
Can somebody point out what I'm doing wrong?
I found the solution for my problem, I've updated the Accordion.ContentTemplate code in the view, the code now looks like this:
<toolkit:Accordion.ContentTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Path=SubMenuItems}"
Margin="2 2 0 0"
BorderThickness="0"
SelectedItem="{Binding RelativeSource={RelativeSource AncestorType=navigation:Page}, Path=DataContext.SelectedMenuItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
With this code, the view now finds the SelectedMenuItem property in the ViewModel

WPF: CellEditingTemplate how can I set focus on the inner control by double click or on click

I wrote a usercontrol of DataGrid with CellEditingTemplate. The DataTemplate of this editing-Template is a TextBox, and the cursor will go into the textbox by three times click, what can i do, if i want set the cursor on the textbox by double click or one click?
Here is my code:
<Window x:Class="MultiLineEditDataGrid.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MultiLineEditDataGrid"
Title="MainWindow" Height="350" Width="525">
<Grid DataContext="{Binding Source={x:Static Application.Current}, Path=CompanyManager}">
<Grid.RowDefinitions>
<RowDefinition Height="270"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Companies}" CanUserAddRows="False" AutoGenerateColumns="False">
<DataGrid.Resources>
<DataTemplate x:Key="cellTemplate">
<TextBlock Text="{Binding Description}"/>
</DataTemplate>
<DataTemplate x:Key="cellEditingTemplate">
<local:MultiLineTextBox Text="{Binding Description}"/>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Company" Binding="{Binding Name}"/>
<DataGridTemplateColumn Header="Description"
CellTemplate="{StaticResource cellTemplate}"
CellEditingTemplate="{StaticResource cellEditingTemplate}"/>
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="1" Content="Add" Command="{Binding AddCommand}"/>
</Grid>
MultiLineTextBox is the TextBox which i inherit from textbox, and override OnKeyDown method.
MultiLineTextBox's code:
public class MultiLineTextBox : TextBox
{
/// <summary>
/// On Key Down.
/// </summary>
/// <param name="e"></param>
protected override void OnKeyDown ( KeyEventArgs e )
{
base.OnKeyDown ( e );
string oldText = Text;
ModifierKeys keys = Keyboard.Modifiers;
if ( e.Key == Key.Enter )
{
if ( ( Keyboard.Modifiers & ModifierKeys.Control ).Equals ( ModifierKeys.Control ) )
{
int index = SelectionStart;
oldText = oldText.Insert ( index, Environment.NewLine );
Text = oldText;
Select ( index + 1, 0 );
e.Handled = true;
}
else
{
e.Handled = false;
}
}
else if ( e.Key == Key.Escape )
{
Text = oldText;
e.Handled = false;
}
}
}
I don't know why but the previous answer didn't work in my case. I found and alternative solution here http://madcoderspeak.blogspot.ca/2010/04/set-keyboard-focus-when-user-begins.html
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<TextBox x:Name="editCommentTextBox" Text="{Binding Comment, Mode=TwoWay}"
FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
</TextBox>
<Label Content="{Binding Text, ElementName=editCommentTextBox, Converter={StaticResource CharCounterConverter}}"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
I find a way to resolve this problem, and here is my code.
<Window x:Class="MultiLineEditDataGrid.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MultiLineEditDataGrid"
Title="MainWindow" Height="350" Width="525">
<Grid DataContext="{Binding Source={x:Static Application.Current}, Path=CompanyManager}">
<Grid.RowDefinitions>
<RowDefinition Height="270"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Companies}" CanUserAddRows="False" AutoGenerateColumns="False">
<DataGrid.Resources>
<DataTemplate x:Key="cellTemplate">
<TextBlock Text="{Binding Description}"/>
</DataTemplate>
<DataTemplate x:Key="cellEditingTemplate">
<local:MultiLineTextBox x:Name="multiLineTxt" Text="{Binding Description}"/>
<DataTemplate.Triggers>
<Trigger SourceName="multiLineTxt" Property="IsVisible" Value="True">
<Setter TargetName="multiLineTxt" Property="FocusManager.FocusedElement" Value="{Binding ElementName=multiLineTxt}"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Company" Binding="{Binding Name}"/>
<DataGridTemplateColumn Header="Description"
CellTemplate="{StaticResource cellTemplate}"
CellEditingTemplate="{StaticResource cellEditingTemplate}"/>
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="1" Content="Add" Command="{Binding AddCommand}"/>
</Grid>

Resources