<ScrollViewer Width="600"
Grid.Row="1"
PanningMode="Both"
extensions:TouchScrolling.IsEnabled="True"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Disabled">
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Width="175"
Grid.Row="0"
Grid.Column="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="170" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" >
<Grid MinWidth="{Binding ElementName=backgroundImage, Path=ActualWidth}" >
<StackPanel HorizontalAlignment="Center"
Orientation="Horizontal" >
<Image Height="160"
Source="man.png" />
</StackPanel>
</Grid>
</Grid>
<TextBlock TextWrapping="Wrap"
Grid.Row="1"
FontSize="10"
Text="Bomber jacket..." />
</Grid>
</Border>
<Border Width="175"
Grid.Row="0"
Grid.Column="1">...
</Border>
<Border Width="175"
Grid.Row="0"
Grid.Column="2">...
</Border>
<Border Width="175"
Grid.Row="0"
Grid.Column="3">...
</Border>
</Grid>
</ScrollViewer>
I have above xaml. In scrollViewer i have some items. I want to initialize it with data from database. How to do this?
I need to screate some ItemControl for common XAML and bind to properties. But how can i manage to bind every item in list to be binded to that ItemControl ?
I found this topic where i understand how to build same xaml for list items, but one problem is there - How to set Grid.Column for each item?
An ItemsControl is used to draw a UI for a collection of items.
So to start with, you need your collection of items from the database.
public ObservableCollection<MyItem> MyCollection { get; set; }
To draw this using an ItemsControl, you would use XAML like this :
<ScrollViewer Height="100">
<ItemsControl ItemsSource="{Binding MyCollection}" />
</ScrollViewer>
This will use the default UI for an ItemsControl, which is to loop through each item in the collection, and for each one render a TextBlock with the Text property displaying the .ToString() of the item.
So what actually renders is something like
<ScrollViewer>
<StackPanel>
<TextBlock /> <!-- DataContext is MyCollection[0] -->
<TextBlock /> <!-- DataContext is MyCollection[1] -->
<TextBlock /> <!-- DataContext is MyCollection[2] -->
</StackPanel>
</ScrollViewer>
The ItemsControl lets you modify different parts of the template though.
For example, to change the <StackPanel> in the XAML above, you would set the ItemsPanel property to use a Grid instead.
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Or to change the TextBlock to something else, you could change the ItemTemplate
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="175" ...>
<TextBlock Text="{Binding Name}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
This would make your output render something like this
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Width="175" ...> <!-- DataContext is MyCollection[0] -->
<TextBlock Text="{Binding Name}" />
</Border>
<Border Width="175" ...> <!-- DataContext is MyCollection[1] -->
<TextBlock Text="{Binding Name}" />
</Border>
<Border Width="175" ...> <!-- DataContext is MyCollection[2] -->
<TextBlock Text="{Binding Name}" />
</Border>
</Grid>
</ScrollViewer>
To set Grid.Column, it's actually a bit trickier. An ItemsControl actually wraps each item in a <ContentPresenter> so each item in the XAML above would actually render more like this :
<ContentPresenter>
<Border Width="175" ...> <!-- DataContext is MyCollection[0] -->
<TextBlock Text="{Binding Name}" />
</Border>
</ContentPresenter>
To set a property like Grid.Column, it needs to be set on the ContentPresenter that wraps each item. And that's what the ItemContainerStyle is used for.
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column"
Value="{Binding ColumnIndex}" />
<Setter Property="Grid.Row"
Value="{Binding RowIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
So assuming you were binding to
public ObservableCollection<MyItem> MyCollection { get; set; }
and MyItem looked like this
public class MyItem
{
public int RowIndex { get; set; }
public int ColumnIndex { get; set; }
public string Name { get; set; }
}
Your final XAML might look something like this
<ItemsControl ItemsSource="{Binding MyCollection}">
<!-- ItemsPanelTemplate -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- ItemContainerStyle -->
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column"
Value="{Binding ColumnIndex}" />
<Setter Property="Grid.Row"
Value="{Binding RowIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
<!-- ItemTemplate -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="175" ...>
<TextBlock Text="{Binding Name}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And it would render something like this :
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- DataContext is MyCollection[0] -->
<ContentPresenter Grid.Row="{Binding RowIndex}" Grid.Column="{Binding ColumnIndex}">
<Border Width="175" ...>
<TextBlock Text="{Binding Name}" />
</Border>
</ContentPresenter>
<!-- DataContext is MyCollection[1] -->
<ContentPresenter Grid.Row="{Binding RowIndex}" Grid.Column="{Binding ColumnIndex}">
<Border Width="175" ...>
<TextBlock Text="{Binding Name}" />
</Border>
</ContentPresenter>
<!-- DataContext is MyCollection[2] -->
<ContentPresenter Grid.Row="{Binding RowIndex}" Grid.Column="{Binding ColumnIndex}">
<Border Width="175" ...>
<TextBlock Text="{Binding Name}" />
</Border>
</ContentPresenter>
</Grid>
</ScrollViewer>
If i'm right what you mean is that you want to bind a list of items to your xaml. To do this you can use a GridView.
In a Gridview you bind a list of items and define a template for each of these items.
<GridView ItemsSource="{Binding MyList}">
<Gridview.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding foo}"/>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid MaximumRowsOrColumns="4" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
As you can see. the gridview items template defines how each item in the list is going to be displayed. When you overwrite the itemspanel you can set MaximumRowsOrColumns and Orientation to define how many items each row will have and which way the rows are facing.
Related
I have a simple View Model class (I'm omitting the INPC implementation for brevity):
public class MyViewModel : INotifyPropertyChanged
{
public int ID { get; set; }
public ObservableCollection<int> Items { get; }
public int SelectedItemIndex { get; set; }
}
My problem is with my XAML. The above class is contained in another ObservableCollection in the parent object, so it's coded as a DataTemplate:
<DataTemplate x:Key="MyDataTemplate" DataType="x:MyViewModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Target="{Binding ElementName=ID}">
<Bold>ID:</Bold>
</Label>
<TextBox Grid.Column="1"
x:Name="ID"
Height="25"
Text="{Binding Path=ID}"
VerticalAlignment="Top" />
<Label Grid.Column="2"
Target="Items:">
<Bold>Rooms:</Bold>
</Label>
<Grid Grid.Column="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListBox Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
ItemsSource="{Binding Path=Items}"
SelectedIndex="{Binding Path=SelectedItemIndex, Mode=TwoWay}"
x:Name="Items">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type system:Int32}">
<TextBox Text="{Binding Path=., Mode=TwoWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Column="1"
Grid.Row="0"
Content="{Binding Path=AddButtonCaption}"
Command="local:EditorCommands.AddElement"
CommandParameter="{Binding}"
Height="25"
VerticalAlignment="Top" />
<Button Grid.Column="1"
Grid.Row="1"
Content="{Binding Path=DeleteButtonCaption}"
Command="local:EditorCommands.DeleteElement"
CommandParameter="{Binding}"
Height="25"
VerticalAlignment="Top" />
</Grid>
</Grid>
</DataTemplate>
There are a few problems with this XAML:
The TextBox does not occupy the full width of the ListBox.
The binding on the same TextBox isn't working.
How do I fix these problems?
1) Give your ListBox ItemContainerStyle property a style and set its HorizontalContentAlignment property:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
2) Are you sure? Seems to be working fine for me. If you want it to update as you type then set the binding's UpdateSourceTrigger property to PropertyChanged:
<TextBox Grid.Column="1"
x:Name="_ID"
Height="25"
Text="{Binding Path=ID, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Top" />
Note that I've changed the TextBox's x:Name to "_ID" here because it was causing a conflict with the way I'm testing it (ID is also a property in the Window. Could also be confusing whatever framework is handling your bindings, so if the above doesn't work then try that as well.
Could some identify why the following is not working please, I am trying to implement a Chat Message window where each Message will render a different style dependent on the MessageDirection. For this I am using a ItemsControl which is bound to the Messages property
In the ChatWindow class I have the following
public static readonly DependencyProperty MessagesProperty = DependencyProperty.Register(
"Messages",
typeof(ObservableCollection<Message>),
typeof(ChatWindow),
new PropertyMetadata(null));
public ObservableCollection<Message> Messages
{
get
{
return (ObservableCollection<Message>)this.GetValue(MessagesProperty);
}
set
{
this.SetValue(MessagesProperty, value);
}
}
I have the following defined in a ResourceDictionary
<ScrollViewer x:Name="srcMessages" Margin="0,0,0,0" VerticalScrollBarVisibility="Visible">
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Messages, RelativeSource={RelativeSource AncestorType={x:Type chat:ChatWindow}}}" x:Name="Messages">
<ItemsControl.ItemTemplate>
<DataTemplate>
<chat:MessageContentPresenter Content="{Binding}">
<chat:MessageContentPresenter.InboundTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="94" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<TextBlock Text="Username One" FontSize="10" Foreground="#adadad"></TextBlock>
<TextBlock Text=" - " FontSize="10" Foreground="#adadad"></TextBlock>
<TextBlock Text="11:45 AM" FontSize="10" Foreground="#adadad"></TextBlock>
</StackPanel>
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="18" />
<ColumnDefinition Width="65" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="6" />
<ColumnDefinition Width="230" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="1" Height="60" Width="60" Source="pack://siteoforigin:,,,/Resources/noavatar.png" StretchDirection="Both" Stretch="Fill">
<Image.Clip>
<EllipseGeometry Center="30,30" RadiusX="30" RadiusY="30" />
</Image.Clip>
</Image>
<Polygon Grid.Column="3" Points="0,0 -4,3 0,6 0,0" StrokeThickness="2" HorizontalAlignment="Right" VerticalAlignment="Center" Fill="#d8d7dc" Stroke="#d8d7dc"></Polygon>
<Border Grid.Column="4" BorderBrush="#d8d7dc" BorderThickness="1" Background="#d8d7dc" Padding="5">
<TextBlock TextWrapping="Wrap" Text="This is a message in a chat window..." VerticalAlignment="Top" FontSize="12" Foreground="#000000"></TextBlock>
</Border>
</Grid>
</Grid>
</DataTemplate>
</chat:MessageContentPresenter.InboundTemplate>
<chat:MessageContentPresenter.OutboundTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="94" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" HorizontalAlignment="Right" Orientation="Horizontal">
<TextBlock Text="Username One" FontSize="10" Foreground="#adadad"></TextBlock>
<TextBlock Text=" - " FontSize="10" Foreground="#adadad"></TextBlock>
<TextBlock Text="11:45 AM" FontSize="10" Foreground="#adadad"></TextBlock>
</StackPanel>
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="230" />
<ColumnDefinition Width="6" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="65" />
<ColumnDefinition Width="18" />
</Grid.ColumnDefinitions>
<Image Grid.Column="4" Height="60" Width="60" Source="pack://siteoforigin:,,,/Resources/noavatar.png" StretchDirection="Both" Stretch="Fill">
<Image.Clip>
<EllipseGeometry Center="30,30" RadiusX="30" RadiusY="30" />
</Image.Clip>
</Image>
<Polygon Grid.Column="2" Points="0,0 4,3 0,6 0,0" StrokeThickness="2" HorizontalAlignment="Right" VerticalAlignment="Center" Fill="#4fcd00" Stroke="#4fcd00"></Polygon>
<Border Grid.Column="1" BorderBrush="#4fcd00" BorderThickness="1" Background="#4fcd00" Padding="5">
<TextBlock TextWrapping="Wrap" Text="This is a message in a chat window..." VerticalAlignment="Top" FontSize="12" Foreground="#000000"></TextBlock>
</Border>
</Grid>
</Grid>
</DataTemplate>
</chat:MessageContentPresenter.OutboundTemplate>
</chat:MessageContentPresenter>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
And the MessageContentPresenter is as below
public class MessageContentPresenter : ContentControl
{
#region Public Properties
public DataTemplate InboundTemplate { get; set; }
public DataTemplate OutboundTemplate { get; set; }
#endregion
#region Methods
protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
var message = newContent as Message;
if (message.Direction == MessageDirection.Inbound)
{
this.ContentTemplate = this.InboundTemplate;
}
else
{
this.ContentTemplate = this.OutboundTemplate;
}
}
#endregion
}
When I run this code all works fine and the OnContentChanged method is executed once for each item in the Messages collection. The issue is that both the InboundTemplate and the OutboundTemplate are null.
I really cannot see what the problem is so and why the two templates are both null, any help greatly appreciated.
Indeed, you can use DataTemplateSelector.
But another option is to use the DataTemplate + ContentControl and Style:
First, drop your MessageContentPresenter class as we do not need it. Consequently, you need to remove your ItemsControl.ItemTemplate from your XAML.
Secondly, add DataTemplate + ContentControl and Style to your Window.Resources.
Try this to give you some lead:
<DataTemplate DataType="{x:Type local:Message}">
<ContentControl Content="{Binding Direction}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding Direction}" Value="{x:Static local:MessageDirection.Inbound}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Button Background="Green">Inbound</Button>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Direction}" Value="{x:Static local:MessageDirection.Outbound}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Button Background="Red">Outbound</Button>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
Having some problems with my MVVM Application.
So the scenario is the following:
In my MainWindow.xaml, I have a ContentControl placed in a Grid Column, its content is bind to the CurrentViewModel which will be rendered to the appropriate View (in this case, Overview.xaml).
<ContentControl Grid.Row="1" Grid.Column="1" Content="{Binding CurrentViewModel}">
Within this particular view (Overview.xaml) there are multiple UserControls placed within a StackPanel.
<ScrollViewer CanContentScroll="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<StackPanel CanVerticallyScroll="True" CanHorizontallyScroll="True">
<views:DiagramView DataContext="{Binding Path=DiagramViewModel, Source={StaticResource Locator}}" />
<views:IncomeCollectionView DataContext="{Binding Path=IncomesViewModel, Source={StaticResource Locator}}" />
<views:ExpenseCollectionView DataContext="{Binding Path=ExpensesViewModel, Source={StaticResource Locator}}" />
<views:CheckCollectionView DataContext="{Binding Path=ChecksViewModel, Source={StaticResource Locator}}" />
<views:BalanceCollectionView DataContext="{Binding Path=BalancesViewModel, Source={StaticResource Locator}}" />
<views:VacationCollectionView DataContext="{Binding Path=VacationsViewModel, Source={StaticResource Locator}}" />
<views:KHCollectionView DataContext="{Binding Path=KhViewModel, Source={StaticResource Locator}}" />
<views:OctaviaCollectionView DataContext="{Binding Path=OctaviaViewModel, Source={StaticResource Locator}}" />
</StackPanel>
</ScrollViewer>
Each UserControl within this StackPanel has a very similar look (obviously there are more stuff in the XAML). There is no constant value regarding Width or Height within my application.
<ListView ItemsSource="{Binding Source={StaticResource groupedCollection}}" SelectedItem="{Binding CurrentItem}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Items[0].CurrentCategory}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="12" Rows="1" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding GeneratedColumn}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding EncryptedAmount}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Got paid on " />
<TextBlock Text="{Binding Date}" />
</StackPanel>
<Button Content="details"
Command="{Binding Path=DataContext.ShowDialogCommand,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
CommandParameter="QuickEdit"/>
<Button Content="remove" Command="{Binding RemoveCommand}" CommandParameter="Income removed." />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The problem is that I can't seem to make the vertical scrollviewer work. It is displayed because I make it visible, but it's disabled. Obviously the StackPanel is gonna grow indefintely, but isn't there a way for it to calculate how much space is needed? Because most of the content is just cut off right now.
So I tried to put scrollviewer in every possible place, but they're all disabled.
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<ScrollViewer>
<ContentPresenter Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So then I tried dropping the StackPanel implementation and tried it with a Grid.
Nope, it doesn't work either.
Obviously I'm missing some basis solution here, but just can't figure it out.
Any ideas would be appreciated, seems like a very common scenario to be honest.
Cheers
<ScrollViewer CanContentScroll="True"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<views:DiagramView DataContext="{Binding Path=DiagramViewModel, Source={StaticResource Locator}}" />
<views:IncomeCollectionView Grid.Row="1" DataContext="{Binding Path=IncomesViewModel, Source={StaticResource Locator}}" />
<views:ExpenseCollectionView Grid.Row="2" DataContext="{Binding Path=ExpensesViewModel, Source={StaticResource Locator}}" />
<views:CheckCollectionView Grid.Row="3" DataContext="{Binding Path=ChecksViewModel, Source={StaticResource Locator}}" />
...etc...
</Grid>
</ScrollViewer>
Edit: The DiagramView UserControl contains the following:
<UserControl x:Class="Expense.Manager.WPF.Views.DiagramView"
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:pie="clr-namespace:Expense.Manager.WPF.CustomPie"
xmlns:local="clr-namespace:Expense.Manager.WPF.Shared"
mc:Ignorable="d">
<UserControl.Resources>
<local:BoolToBrushConverter x:Key="BoolToBrushConverter" />
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Income this month: " />
<TextBlock>
<TextBlock.Text>
<PriorityBinding FallbackValue="Retrieving data...">
<Binding Path="EncryptedCurrentMonthIncome" Mode="TwoWay" IsAsync="True" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<pie:PieChart Data="{Binding PieChartIncomeData, Mode=TwoWay}" Width="250" PieWidth="130" PieHeight="130" Height="140" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Expenses this month: " />
<TextBlock>
<TextBlock.Text>
<PriorityBinding FallbackValue="Retrieving data...">
<Binding Path="CurrentMonthExpense" Mode="TwoWay" IsAsync="True" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<pie:PieChart Data="{Binding PieChartExpenseData, Mode=TwoWay}" Width="250" PieWidth="130" PieHeight="130" Height="140" />
</StackPanel>
<StackPanel Grid.Column="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding VacationsLeft}" />
<TextBlock Text=" days left" />
</StackPanel>
<ItemsControl ItemsSource="{Binding VacationsPerYearCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Margin="5, 0, 0, 0" Height="25" Width="4" Fill="{Binding Converter={StaticResource BoolToBrushConverter}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Bank savings:" />
<TextBlock Text="{Binding BankSavings}" />
</StackPanel>
</StackPanel>
</Grid>
IncomeCollectionView:
<UserControl x:Class="Expense.Manager.WPF.Views.IncomeCollectionView"
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:views="clr-namespace:Expense.Manager.WPF.Views"
mc:Ignorable="d">
<UserControl.Resources>
<CollectionViewSource x:Key="groupedCollection" IsLiveGroupingRequested="True" Source="{Binding Collection}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="CurrentCategory" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding DisplayName}" Foreground="White" FontWeight="SemiBold" Padding="5" Background="SteelBlue" />
<ListView Grid.Row="1" ItemsSource="{Binding Source={StaticResource groupedCollection}}" SelectedItem="{Binding CurrentItem}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Items[0].CurrentCategory}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Columns="12" Rows="1" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding GeneratedColumn}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding EncryptedAmount}" />
<TextBlock Grid.Row="1" Text="{Binding Date}" />
<Button Grid.Row="2" Content="details"
Command="{Binding Path=DataContext.ShowDialogCommand,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
CommandParameter="QuickEdit"/>
<Button Grid.Row="3" Content="remove" Command="{Binding RemoveCommand}" CommandParameter="Income removed." />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
and where it is used:
why is the listview not resizing itself after resizing the window itself?
<ScrollViewer CanContentScroll="True" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<views:IncomeCollectionView Grid.Row="1" DataContext="{Binding Path=IncomesViewModel, Source={StaticResource Locator}}" />
</Grid>
</ScrollViewer>
I tried dropping the StackPanel implementation and tried it with a Grid. Nope, it doesn't work either.
That's almost correct, apart from the last sentence. Using a Grid is half of the answer, because the StackPanel has no functionality to resize its items... you just need to inform the ScrollViewer when to scroll. Take this example:
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Rectangle Fill="Cyan" />
<Rectangle Grid.Row="1" Fill="Green" />
<Rectangle Grid.Row="2" Fill="Red" />
<Rectangle Grid.Row="3" Fill="Blue" />
<Rectangle Grid.Row="4" Fill="Orange" />
<Rectangle Grid.Row="5" Fill="Purple" />
<Rectangle Grid.Row="6" Fill="Yellow" />
</Grid>
</ScrollViewer>
This XAML will make the ScrollViewer ScrollBar appear (once the Window.Height is small enough), but if you remove the RowDefinition.Height values (thereby giving each row a proportion of the whole Grid.Height), you'll see your previous situation where no ScrollBar appears.
Now, none of us want to hard code constant values into our UIs, but you can do this using the Auto setting on the RowDefinition.Height properties instead. Unlike these Rectangles, your controls will all have some Height, so your solution is to set each of your Grid.RowDefinitions like this:
<RowDefinition Height="Auto" />
This will provide your controls with as much space as they need within the Grid and therefore (hopefully) they will have more Height together than the ScrollViewer and therefore the ScrollViewer will display its vertical ScrollBar.
I have a databound list box and a text block in my application
Initially the listbox will be populated with some values (More than 10 values). i tried to scroll the list. But I couldn't. When I Click on the list and drag the mouse up, the list goes further down. The effect is more or like pulling down the list.
The xaml code is as follows. please help.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="RequestFilterTxtBlock" Grid.Row="0" Text="-" FontWeight="Bold" FontStyle="Italic" TextDecorations="Underline"/>
<ScrollViewer Grid.Row="1">
<ListBox x:Name="Requests1" ItemsSource="{Binding Details_OC}" SelectionChanged="Requests_SelectionChanged" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,2" BorderBrush="White">
<Grid HorizontalAlignment="Stretch" Width="450">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<CheckBox x:Name="CheckBox1" Grid.Column="0" IsChecked="{Binding Path=IsComplete, Mode=TwoWay}" Grid.RowSpan="2" Checked="CheckBox1_Checked" Unchecked="CheckBox1_Unchecked" />
<TextBlock x:Name="WorkOrderID" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" Text="{Binding WORKORDERID}" VerticalAlignment="Top"/>
<TextBlock x:Name="date" Text="{Binding Path=DUEBYTIME}" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>
Thank you.
Your ScrollViewer is currently wrapped around only the ListBox. Bearing in mind the ListBox has its own ScrollViewer this will result in unpredictable behaviour.
I would wrap your Grid with a ScrollViewer and disable the ListBox one so that you can scroll your TextBlock and ListBox smoothly.
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="RequestFilterTxtBlock" Grid.Row="0" Text="-" FontWeight="Bold" FontStyle="Italic" TextDecorations="Underline"/>
<ListBox x:Name="Requests1" ItemsSource="{Binding Details_OC}" SelectionChanged="Requests_SelectionChanged" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,2" BorderBrush="White">
<Grid HorizontalAlignment="Stretch" Width="450">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<CheckBox x:Name="CheckBox1" Grid.Column="0" IsChecked="{Binding Path=IsComplete, Mode=TwoWay}" Grid.RowSpan="2" Checked="CheckBox1_Checked" Unchecked="CheckBox1_Unchecked" />
<TextBlock x:Name="WorkOrderID" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" Text="{Binding WORKORDERID}" VerticalAlignment="Top"/>
<TextBlock x:Name="date" Text="{Binding Path=DUEBYTIME}" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</ScrollViewer>
I achieved what i wanted. I didn't even need to include the scroll viewer. I just needed to change the row definition of the grid (row of the list box) from 'auto' to '*'. That worked as expected.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Name="RequestFilterTxtBlock" Grid.Row="0" Text="-" FontWeight="Bold" FontStyle="Italic" TextDecorations="Underline"/>
<ListBox x:Name="Requests1" ItemsSource="{Binding Details_OC}" SelectionChanged="Requests_SelectionChanged" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,2" BorderBrush="White">
<Grid HorizontalAlignment="Stretch" Width="450">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<CheckBox x:Name="CheckBox1" Grid.Column="0" IsChecked="{Binding Path=IsComplete, Mode=TwoWay}" Grid.RowSpan="2" Checked="CheckBox1_Checked" Unchecked="CheckBox1_Unchecked" />
<TextBlock x:Name="WorkOrderID" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" Text="{Binding WORKORDERID}" VerticalAlignment="Top"/>
<TextBlock x:Name="date" Text="{Binding Path=DUEBYTIME}" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I'm looking to create a simple layout for a WPF project I'm working on.
I tried styling Datagrid and GridView's but none of them work as I want, plus I don't want items to be editable / selectable, or columns to be sorted or anything like that. Basically I just want a simple dynamic table layout with no bells and whistles.
Any advice on how to recreate this would be greatly appreciated.
Update: I need the number of rows to be dynamic based on an ObservableCollection
Use HeaderedItemsControl, XAML
<!-- templates -->
<DataTemplate x:Key="itemWithDeleteButton">
<Grid Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=DocumentName, Mode=OneWay}" />
<Button Grid.Column="1" Command="{Binding DeleteCommand}"/>
</Grid>
</DataTemplate>
<Style TargetType="{x:Type HeaderedItemsControl}" x:Key="DeletedGrid">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="4*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="Document Name"
VerticalAlignment="Center"
FontWeight="Bold"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="Actions"
VerticalAlignment="Center"
FontWeight="Bold"/>
<Grid Grid.Row="1" Grid.ColumnSpan="2" Width="Auto" Height="Auto" Background="White">
<ItemsPresenter/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<!-- control -->
<HeaderedItemsControl Style="{StaticResource DeletedGrid}" Margin="0,0,0,10"
Grid.Row="4" Grid.ColumnSpan="2" ItemTemplate="{StaticResource itemWithDeleteButton}"
ItemsSource="{Binding GridData}">
ViewModel
public class GridItem
{
public string DocumentName { get; set; }
public ICommand DeleteCommand { get; set; }
}
public class MyViewModel
{
public ObservableCollection<GridItem> GridData { get; set; }
}
This is just something similar. For the second column you would probably use a button for Delete of maybe just click event on a TextBlock. To get that exact formatting is going to take some tweaking.
<ListView.View>
<GridView AllowsColumnReorder="False" x:Name="gvCurDocFields">
<GridViewColumn Width="120">
<GridViewColumnHeader Content="Field" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Text="{Binding Path=FieldDefApplied.FieldDef.DispName, Mode=OneWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader Content="Value" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Left" Margin="0" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Text="{Binding Path=DispValue, Mode=OneWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
You can use the Grid layout for this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32" /> <!-- Header row -->
<RowDefinition Height="Auto" /> <!-- One for each row of data -->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <!-- Document Name column -->
<ColumnDefinition Width="200" /> <!-- Actions column -->
</Grid.ColumnDefinitions>
</Grid>