I would like to have ListViewItem with data from binding and with 2 events.
My code:
<ListView.ItemTemplate>
<DataTemplate>
<Grid Name="MailListViewItem">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold" Text="{Binding Topic}"/>
<TextBlock Grid.Column="1" Grid.Row="0" FontSize="8" Foreground="Blue" Text="{Binding Time}"/>
<TextBlock Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Foreground="Gray" Text="{Binding Text}"/>
</Grid>
</DataTemplate>
Where should I put MouseDoubleClick="Mail_DoubleClick" MouseLeftButtonUp="Mail_MouseLeftButtonUp"?
You could define an ItemContainerStyle with EventSetters:
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="MouseLeftButtonUp" Handler="Mail_DoubleClick" />
<EventSetter Event="MouseDoubleClick" Handler="Mail_MouseLeftButtonUp" />
</Style>
</ListView.ItemContainerStyle>
...
Or you could handle the events of the Grid in the DataTemplate provided that you set its Background property to some brush:
<Grid Name="MailListViewItem" Background="Transparent" MouseLeftButtonDown="...">
If you handle MouseLeftButtonDown, there is a ClickCount property of the MouseButtonEventArgs that you can check to determine whether the element as double clicked:
private void MailListViewItem_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
//doule click
}
else
{
//click...
}
}
Related
I am trying to add user controls to the Grid and I am trying to set the Grid.Column and Grid.Row property in the DataTemplate but it does not have any effect on the rendering. Can someone help to point out what could be wrong in the code below.
I have the main window with the following code:
<ItemsControl ItemsSource="{Binding Controls}">
<ItemsControl.ItemsPanel >
<ItemsPanelTemplate>
<Grid Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<AppControls:TagInfo Grid.Row="{Binding RowIndex}"
Grid.Column="{Binding ColumnIndex}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
TagInfo.xaml.cs
public partial class TagInfo : UserControl
{
public TagInfo()
{
InitializeComponent();
}
public int RowIndex { get; set; }
public int ColumnIndex { get; set; }
}
TagInfo.xaml
<UserControl x:Class="DataSimulator.WPF.Controls.TagInfo"
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"
mc:Ignorable="d" Height="258" Width="302"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Grid Margin="2,2,2,2">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Tag"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding TagInfo.TagName}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="High High"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TagInfo.HighHigh}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="High"/>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding TagInfo.High}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Low Low"/>
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding TagInfo.LowLow}"/>
<TextBlock Grid.Row="4" Grid.Column="0" Text="Low"/>
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding TagInfo.Low}"/>
<TextBlock Grid.Row="5" Grid.Column="0" Text="Range Start"/>
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding TagInfo.RangeStart}"/>
<TextBlock Grid.Row="6" Grid.Column="0" Text="Range End"/>
<TextBox Grid.Row="6" Grid.Column="1" Text="{Binding TagInfo.RangeEnd}"/>
<Button Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="2" Content="Save"/>
</Grid>
</UserControl>
ViewModel
private ObservableCollection<Controls.TagInfo> _controls
= new ObservableCollection<Controls.TagInfo>();
public ObservableCollection<Controls.TagInfo> Controls
{
get { return _controls; }
set { _controls = value; }
}
private void AddControl()
{
if(currentRow == 3)
{
currentRow = 0;
}
if(currentColumn == 3)
{
currentColumn = 0;
currentRow++;
}
var tagInfoUserControl = new Controls.TagInfo();
tagInfoUserControl.RowIndex = currentRow;
tagInfoUserControl.ColumnIndex = currentColumn++;
_controls.Add(tagInfoUserControl);
}
I am trying to add user controls to the grid and I am trying to set the Grid.Column and Grid.Row property in the data template but it does not have any effect on the rendering
We can't do the attached property binding in a DataTemplate, creating a style for your UserControl in ItemsControl.ItemContainerStyle can make it work:
<ItemsControl ItemsSource="{Binding Controls}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="AppControls:TagInfo">
<Setter Property="Grid.Row" Value="{Binding RowIndex}"/>
<Setter Property="Grid.Column" Value="{Binding ColumnIndex}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
Screenshot:
when all columns and rows have to be of equal size and elements are consequtive, it is probably simpler to use UniformGrid. Rows and Columns properties support binding.
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Name="MainGrid" Rows="4" Columns="4"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
here is a nice example of Grid ItemsPanel here: WPF Grid as ItemsPanel for a list dynamically bound to an ItemsControl
xmal code:
<ListBox x:Name="listbox2" Margin="0,0" SelectionChanged="listbox2_SelectionChanged" Hold="listbox2_Hold" >
<ListBox.ItemContainerStyle >
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,1" BorderBrush="Gray">
<Grid Width="auto" HorizontalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" FontSize="40" Grid.Column="1" Grid.Row="0" Foreground="White" Text="{Binding NAME}"></TextBlock>
<TextBlock VerticalAlignment="Center" FontSize="25" Grid.Column="1" Grid.Row="1" Foreground="Blue" Text="{Binding PHONE}"></TextBlock>
<Image Name="c1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100" Stretch="Fill" Margin="0" Source="{Binding IMGS}" Grid.RowSpan="2" Grid.Column="0" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
class list which is bind to list box is
List < contactsclass > contacts = new List < contactsclass >();
PHONE and NAME are getter setter of the contactclass's variables
how can i get this variable's value on hold event of listbox .. i am trying following code
private void listbox2_Hold(object sender, System.Windows.Input.GestureEventArgs e)
{
//contextmenucontact = (contactsclass)(sender as ListBox).DataContext;
contextmenucontact = (contactsclass)listbox2.SelectedItem;
MessageBox.Show(contextmenucontact.name);
}
if is just the selected item is just use the ToString Function, see this:
if (listBox1.SelectedItem != null)
{
string itemText = listBox1.SelectedItem.ToString();
contextmenucontact = new contactsclass();
contextmenucontact.name = itemText;
MessageBox.Show(contextmenucontact.name);
}
I have a usercontrol with 2 ListViews in it. One for holding a list of predefined categories and one for the list with all the categories in it.
When i place the ListViews inside a <Grid> than everything works perfect.
The working xaml code (with Grid):
<Grid Style="{StaticResource ResourceKey=ContentStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListView x:Name="lstPredefinedCategories" Grid.Row="0" ItemsSource="{Binding PredefinedCategories}" SelectionMode="Multiple" Margin="20">
<ListView.Header>
<StackPanel>
<TextBlock Text="Voorgestelde categorieën" Style="{StaticResource TextBlockStyle}" FontWeight="SemiBold" Foreground="Black" />
<Rectangle Style="{StaticResource DividerStyle}" Fill="Black"/>
</StackPanel>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Left" TextWrapping="Wrap" Width="300" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="20,0">
<TextBlock Text="Alle categorieën" Style="{StaticResource TextBlockStyle}" FontWeight="SemiBold" Foreground="Black" />
<Rectangle Style="{StaticResource DividerStyle}" Fill="Black"/>
</StackPanel>
<TextBox x:Name="txtSearch" PlaceholderText="Zoek categorie" Grid.Row="1" Style="{StaticResource SearchboxStyle}" Margin="20,0" TextChanged="txtSearch_TextChanged" />
<Rectangle Grid.Row="2" Style="{StaticResource DividerStyle}" Margin="20, 0" />
<ListView x:Name="lstCategories" Grid.Row="3" Margin="20,10,20,0" ItemsSource="{Binding Categories}" SelectionMode="Multiple" SelectionChanged="lstCategories_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Left" TextWrapping="Wrap" Width="300" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Rectangle Grid.Row="4" Style="{StaticResource DividerStyle}" Margin="20, 0" />
<Grid Grid.Row="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="btnAnnuleren" Grid.Column="0" Content="Annuleren" Style="{StaticResource ButtonAnnulerenStyle}" Click="btnAnnuleren_Click"/>
<Rectangle Grid.Column="1" Fill="#A9A9A9" Width="0.5" Margin="10,0" />
<Button x:Name="btnSelecteren" Grid.Column="2" Content="Selecteren" Style="{StaticResource ButtonAnnulerenStyle}" Click="btnSelecteren_Click"/>
</Grid>
</Grid>
</Grid>
The only problem with this is that I dont get the UI behaviour that I want. If I use a grid then only the red border is scrollable (because of the ListView). But what I need is that the entire green border is scrollable.
So I want to put everything in a <ScrollViewer><StackPanel></StackPanel></ScrollViewer>.
But when I do so, I occasionally get an out-of-memory exception (sometimes the apps just freezes and close without an exception).
Here is my not working xaml with the <ScrollViewer>:
<ScrollViewer>
<StackPanel>
<ListView x:Name="lstPredefinedCategories" ItemsSource="{Binding PredefinedCategories}" SelectionMode="Multiple" Margin="20">
<ListView.Header>
<StackPanel>
<TextBlock Text="Voorgestelde categorieën" Style="{StaticResource TextBlockStyle}" FontWeight="SemiBold" Foreground="Black" />
<Rectangle Style="{StaticResource DividerStyle}" Fill="Black"/>
</StackPanel>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Left" TextWrapping="Wrap" Width="300" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="20,0">
<TextBlock Text="Alle categorieën" Style="{StaticResource TextBlockStyle}" FontWeight="SemiBold" Foreground="Black" />
<Rectangle Style="{StaticResource DividerStyle}" Fill="Black"/>
</StackPanel>
<TextBox x:Name="txtSearch" PlaceholderText="Zoek categorie" Grid.Row="1" Style="{StaticResource SearchboxStyle}" Margin="20,0" TextChanged="txtSearch_TextChanged" />
<Rectangle Grid.Row="2" Style="{StaticResource DividerStyle}" Margin="20, 0" />
<ListView x:Name="lstCategories" Grid.Row="3" Margin="20,10,20,0" ItemsSource="{Binding Categories}" SelectionMode="Multiple" SelectionChanged="lstCategories_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Left" TextWrapping="Wrap" Width="300" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Rectangle Grid.Row="4" Style="{StaticResource DividerStyle}" Margin="20, 0" />
<Grid Grid.Row="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="btnAnnuleren" Grid.Column="0" Content="Annuleren" Style="{StaticResource ButtonAnnulerenStyle}" Click="btnAnnuleren_Click"/>
<Rectangle Grid.Column="1" Fill="#A9A9A9" Width="0.5" Margin="10,0" />
<Button x:Name="btnSelecteren" Grid.Column="2" Content="Selecteren" Style="{StaticResource ButtonAnnulerenStyle}" Click="btnSelecteren_Click"/>
</Grid>
</Grid>
</StackPanel>
</ScrollViewer>
Any thoughts on why my app is freezing or get an OOM-exception?
Update
It comes because in the 2nd ListView they are too much objects loaded. So I'm gonna try to fix it with ISupportIncrementalLoading.
Or is there an other way?
The solution was to use virtualization (ISupportIncrementalLoading) like suggested in the comments.
Here you can find my implementation class of ISupportIncrementalLoading:
public class StringKeyValueIncrementalCollection : ObservableCollection<StringKeyValue>, ISupportIncrementalLoading
{
private List<StringKeyValue> allCategories;
private int lastItem = 1;
public StringKeyValueIncrementalCollection(List<StringKeyValue> categories)
{
this.allCategories = categories;
}
public bool HasMoreItems
{
get
{
if (lastItem == allCategories.Count)
{
return false;
}
else
{
return true;
}
}
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
CoreDispatcher coreDispatcher = Window.Current.Dispatcher;
return Task.Run<LoadMoreItemsResult>(async () =>
{
List<StringKeyValue> items = new List<StringKeyValue>();
for (int i = 0; i < count; i++)
{
items.Add(allCategories[i]);
lastItem++;
Debug.WriteLine(lastItem);
if (lastItem == allCategories.Count)
{
break;
}
}
await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
foreach (StringKeyValue item in items)
{
this.Add(item);
}
});
return new LoadMoreItemsResult() { Count = count };
}).AsAsyncOperation<LoadMoreItemsResult>();
}
}
And then my code in the ViewModel. As you can see, I use the StringKeyValueIncrementalCollection instead of a regular List<object>:
private StringKeyValueIncrementalCollection categories;
private StringKeyValueIncrementalCollection allCategories;
public StringKeyValueIncrementalCollection Categories
{
get { return categories; }
set
{
filteredCategories = value;
RaisePropertyChanged("Categories");
}
}
public async void LoadCategories()
{
List<StringKeyValue> temp = await this.openVlaanderenService.GetCategoriesData();
allCategories = new StringKeyValueIncrementalCollection(temp);
Categories = allCategories;
}
The only problem that you than have is that the ScollViewer will allow it's content to fill as much space as it wants, so the data just will keep loading. To fix that I did what was suggested in ISupportIncrementalLoading inside ScrollViewer not supported?
So I added a SizeChanged="ScrollViewer_SizeChanged" event to my ScrollViewer and in code behind set the size of the ListView based on the viewport size properties of the ScrollViewer:
private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
{
lstCategories.Height = scrollViewer.ViewportHeight;
}
In my project, i have two ListBox. The first is populated from JSON file. So de user select one item and click "Add" button, the item is added to ListBox 2.
But, I have an "amount" TextBox and I want that its content appears on ListBox 2 also.
Following example:
How is it my screen:
(source: infassteste.url.ph)
As it should be:
(source: infassteste.url.ph)
My code:
private void AddProd(object sender, RoutedEventArgs e)
{
if (ListBoxx.SelectedItem != null)
{
Fields fi = (Fields)this.ListBoxx.SelectedItem;
ListBoxx2.Items.Add(fi);
}
else
{
MessageBox.Show("Selecione um item para adicionar!");
}
}
My XAML:
<ListBox Name="ListBoxx"
FontSize="30"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding Items}" Margin="10,10,10,411" BorderBrush="Red">
<ListBox.Background>
<SolidColorBrush Color="#FFC3C3C3" Opacity="0.51"/>
</ListBox.Background>
<!-- Template to display each item -->
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding FNome}"/>
<TextBlock Grid.Column="1" Text="{Binding FEstado}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="ListBoxx2"
FontSize="30"
HorizontalContentAlignment="Stretch"
Margin="10,311,10,10" BorderBrush="Red">
<ListBox.Background>
<SolidColorBrush Color="#FFC3C3C3" Opacity="0.51"/>
</ListBox.Background>
<!-- Template to display each item -->
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding FNome}"/>
<TextBlock Grid.Column="1" Text="{Binding FEstado}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Add a property to your Fields class to hold the quantity. Lets call it Quantity. The Modify the ListBoxx2 ItemTemplate like this.
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding FNome}"/>
<TextBlock Grid.Column="1" Text="{Binding FEstado}"/>
<TextBlock Grid.Column="2" Text="{Binding Quantity}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
Then in the click event of the Button, add the following..
private void AddProd(object sender, RoutedEventArgs e)
{
if (ListBoxx.SelectedItem != null)
{
Fields fi = (Fields)this.ListBoxx.SelectedItem;
fi.Quantity = txtQuantity.Text; // SET THE Quantity..
ListBoxx2.Items.Add(fi);
}
else
{
MessageBox.Show("Selecione um item para adicionar!");
}
}
Then the value in the textbox is added to the object and it is bound to the ListBox ItemTemplate
Define new property to you class that is displayed in ListBox and bound and bind it to third TextBlock. (FNome, FEstado).
In your AddProd method you can get instance of your custom class from ListBoxx.SelectedItem and change your new property.
I have two grids with three rows each. The first and last row of each grid has a fixed height while the middle rows have auto height and share their height using SharedSizeGroup.
First, the content of the right grid determines the height of the size group. When the content of the right grid shrinks so that the content of the left grid determines the height of the size group, the overall size of the left grid is not adjusted correctly.
See the following sample app. Click the increase button to increase the size of the textblock in the right grid. The size of the left grid changes accordingly. Now decrease the size. When the textblock becomes smaller than the textblock in the left grid, the total size of the left grid doesn't shrink. Is this a bug or am i missing something?
<StackPanel Orientation="Horizontal" Grid.IsSharedSizeScope="True">
<StackPanel Orientation="Vertical" Width="100">
<Grid Background="Green">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition SharedSizeGroup="Group1" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<TextBlock Background="Blue" Grid.Row="0" />
<TextBlock Background="Red" Grid.Row="1" Name="textBlock1" Height="100" />
<TextBlock Background="Blue" Grid.Row="2" />
</Grid>
<TextBlock Text="{Binding Path=ActualHeight, ElementName=grid1}" />
</StackPanel>
<StackPanel Orientation="Vertical" Width="100">
<Grid Background="Green">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition SharedSizeGroup="Group1" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<TextBlock Background="Blue" Grid.Row="0" />
<TextBlock Background="Red" Grid.Row="1" Name="textBlock2" Height="150" />
<TextBlock Background="Blue" Grid.Row="2" />
</Grid>
<TextBlock Text="{Binding Path=ActualHeight, ElementName=grid2}" />
</StackPanel>
<Button Height="24" Click="Button_Click_1" VerticalAlignment="Top">Increase</Button>
<Button Height="24" Click="Button_Click_2" VerticalAlignment="Top">Decrease</Button>
</StackPanel>
private void Button_Click_1(object sender, RoutedEventArgs e)
{
textBlock2.Height += 30;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
textBlock2.Height -= 30;
}
The rows are staying the same height - the size of the second TextBlock is changing, while the size of the first TextBlock remains 100.
To demonstrate this, make the following changes:
Add ShowGridLines="True" to each of your Grids
Change your named TextBlocks to show their ActualHeight as their text:
<TextBlock Background="Red" Grid.Row="1" Name="textBlock2" Height="150"
Text="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}"/>
You will see that the SharedSizeGroup row will be the maximum ActualHeight of the two TextBlocks.
Update: A Short Project To Show What's Happening
I've created a quick-n-dirty project to show what's happening. It turns out that when the right grid gets smaller than the original size, the left grid does an Arrange but not a Measure. I am not sure I understand this completely - I have posted a follow-up question with this same solution.
Here is the solution that I created, based on your original. It simply wraps the basic grid in a custom class that spews out info (via event) when Measure and Arrange are called. In the main window, I just put that info into a list box.
InfoGrid and InfoGridEventArgs classes
using System.Windows;
using System.Windows.Controls;
namespace GridMeasureExample
{
class InfoGrid : Grid
{
protected override Size ArrangeOverride(Size arrangeSize)
{
CallReportInfoEvent("Arrange");
return base.ArrangeOverride(arrangeSize);
}
protected override Size MeasureOverride(Size constraint)
{
CallReportInfoEvent("Measure");
return base.MeasureOverride(constraint);
}
public event EventHandler<InfoGridEventArgs> ReportInfo;
private void CallReportInfoEvent(string message)
{
if (ReportInfo != null)
ReportInfo(this, new InfoGridEventArgs(message));
}
}
public class InfoGridEventArgs : EventArgs
{
private InfoGridEventArgs()
{
}
public InfoGridEventArgs(string message)
{
this.TimeStamp = DateTime.Now;
this.Message = message;
}
public DateTime TimeStamp
{
get;
private set;
}
public String Message
{
get;
private set;
}
}
}
Main Window XAML
<Window x:Class="GridMeasureExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GridMeasureExample"
Title="SharedSizeGroup" Height="500" Width="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Column="0"
Grid.Row="0"
Orientation="Horizontal"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.IsSharedSizeScope="True">
<StackPanel Orientation="Vertical" Width="100">
<local:InfoGrid x:Name="grid1" Background="Green" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition SharedSizeGroup="Group1" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<TextBlock Background="Blue" Grid.Row="0" Text="Row 0"/>
<TextBlock Background="Red" Grid.Row="1" Name="textBlock1" Height="100"
Text="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}"/>
<TextBlock Background="Blue" Grid.Row="2" Text="Row 2" />
</local:InfoGrid>
<TextBlock Text="{Binding Path=ActualHeight, ElementName=grid1}" />
</StackPanel>
<StackPanel Orientation="Vertical" Width="100">
<local:InfoGrid x:Name="grid2" Background="Yellow" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition SharedSizeGroup="Group1" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<TextBlock Background="Orange" Grid.Row="0" Text="Row 0" />
<TextBlock Background="Purple" Grid.Row="1" Name="textBlock2" Height="150"
Text="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}"/>
<TextBlock Background="Orange" Grid.Row="2" Text="Row 2" />
</local:InfoGrid>
<TextBlock Text="{Binding Path=ActualHeight, ElementName=grid2}" />
</StackPanel>
</StackPanel>
<ListBox x:Name="lstInfo"
Grid.Column="1"
Grid.Row="0"
Margin="10,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<UniformGrid Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="2"
Columns="2"
HorizontalAlignment="Center"
Margin="5">
<Button x:Name="btnIncrease" Margin="4,0">Increase</Button>
<Button x:Name="btnDecrease" Margin="4,0">Decrease</Button>
</UniformGrid>
</Grid>
</Window>
Main Window Constructor (only code in code-behind)
public Window1()
{
InitializeComponent();
btnIncrease.Click += (s, e) =>
{
lstInfo.Items.Add(String.Format("{0} Increase Button Pressed", DateTime.Now.ToString("HH:mm:ss.ffff")));
textBlock2.Height += 30;
};
btnDecrease.Click += (s, e) =>
{
lstInfo.Items.Add(String.Format("{0} Decrease Button Pressed", DateTime.Now.ToString("HH:mm:ss.ffff")));
if (textBlock2.ActualHeight >= 30)
textBlock2.Height -= 30;
};
grid1.ReportInfo += (s, e) => lstInfo.Items.Add(String.Format("{0} Left Grid: {1}", e.TimeStamp.ToString("HH:mm:ss.ffff"), e.Message));
grid2.ReportInfo += (s, e) => lstInfo.Items.Add(String.Format("{0} Right Grid: {1}", e.TimeStamp.ToString("HH:mm:ss.ffff"), e.Message));
}