I have 2 XAML where the first one will shows a list of the second one during runtime. The 1st xaml code is below.
1. BrowserWindowView.xaml
<Page
x:Class="AffiliaTool.Lib.View.BrowserWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:AffiliaTool.Lib.View"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tk="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:vm="using:AffiliaTool.Lib.ViewModel"
mc:Ignorable="d">
<Page.DataContext>
<vm:BrowserWindowViewModel />
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="41" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Button Width="100" Content="NEW TAB">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:InvokeCommandAction Command="{Binding OnNewTabClicked}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</Button>
</Grid>
<tk:TabView
Name="TabViewBar"
Grid.Row="1"
ItemsSource="{Binding Tabs, Mode=TwoWay}">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Loaded">
<core:ChangePropertyAction
PropertyName="TabViewBar"
TargetObject="{Binding}"
Value="{Binding ElementName=TabViewBar, Mode=TwoWay}" />
<core:InvokeCommandAction Command="{Binding OnTabViewLoaded}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
<tk:TabView.ItemHeaderTemplate>
<DataTemplate>
<TextBlock Text="Hello Tab" />
</DataTemplate>
</tk:TabView.ItemHeaderTemplate>
<tk:TabView.ItemTemplate>
<DataTemplate>
<local:BrowserTabWidget DataContext="{Binding}" />
</DataTemplate>
</tk:TabView.ItemTemplate>
</tk:TabView>
</Grid>
</Page>
This first xaml is use to spawn a new window and displays the first WebView object in the initial tab item. The 2nd xaml code that will renders WebView is like below.
2. BrowserTabWidget.xaml
<UserControl
x:Class="AffiliaTool.Lib.View.BrowserTabWidget"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:AffiliaTool.Lib.ViewModel"
mc:Ignorable="d">
<UserControl.DataContext>
<vm:BrowserTabViewModel />
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="41" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid x:Name="Toolbar" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="42" />
<ColumnDefinition Width="42" />
<ColumnDefinition Width="42" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="42" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Background="Transparent">
<Button.Content>
<TextBlock
Margin="0,0,4,0"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="18"
Foreground="#f06a35"
Text="" />
</Button.Content>
</Button>
<Button Grid.Column="1" Background="Transparent">
<Button.Content>
<TextBlock
Margin="0,0,4,0"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="18"
Foreground="#f06a35"
Text="" />
</Button.Content>
</Button>
<Button Grid.Column="2" Background="Transparent">
<Button.Content>
<TextBlock
Margin="0,0,4,0"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="18"
Foreground="#f06a35"
Text="" />
</Button.Content>
</Button>
<TextBox
Grid.Column="3"
Height="32"
Margin="4,0"
Background="White"
BorderBrush="#f06a35"
BorderThickness="1"
FontSize="18" />
<Button Grid.Column="4" Background="Transparent">
<Button.Content>
<TextBlock
Margin="0,0,4,0"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="18"
Foreground="#f06a35"
Text="" />
</Button.Content>
</Button>
</Grid>
<WebView x:Name="WebBrowser" Grid.Row="1">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Loaded">
<core:ChangePropertyAction
PropertyName="WebBrowser"
TargetObject="{Binding}"
Value="{Binding ElementName=WebBrowser, Mode=TwoWay}" />
<core:InvokeCommandAction Command="{Binding OnBrowserLoaded}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</WebView>
</Grid>
</UserControl>
For the 1st xaml I have a ViewModel class code like below, and it has RelayCommand to handle "NEW TAB" button click.
namespace AffiliaTool.Lib.ViewModel
{
public class BrowserWindowViewModel : ViewModelBase
{
private List<BrowserTabViewModel> _tabs;
private RelayCommand _onNewTabClicked;
private RelayCommand _onTabViewLoaded;
private IWebScrapper _scrapper;
private TabView _tabView;
public BrowserWindowViewModel()
{
_tabs = new List<BrowserTabViewModel>();
}
public IWebScrapper Scrapper
{
set
{
_scrapper = value;
}
}
public TabView TabViewBar
{
get
{
return _tabView;
}
set
{
Set("TabViewBar", ref _tabView, value);
}
}
public List<BrowserTabViewModel> Tabs
{
get
{
return _tabs;
}
private set { }
}
public RelayCommand OnTabViewLoaded
{
get
{
return _onTabViewLoaded ?? (_onTabViewLoaded = new RelayCommand(() =>
{
Debug.WriteLine(">>> TAB VIEW LOADED...");
}));
}
}
public RelayCommand OnNewTabClicked
{
get
{
return _onNewTabClicked ?? (_onNewTabClicked = new RelayCommand(() =>
{
var tab = new BrowserTabViewModel
{
Scrapper = _scrapper
};
Tabs.Add(tab);
}));
}
}
}
}
My question is: why everytime I click the "NEW TAB" button which should add new BrowserTabViewModel object into the List and resulting additional Tab created in the UI not working? I cannot add new TAB into the TabView element in the first XAML? No error detected.
I have been struggling for 2 days now, trying to add new TabViewItem in MVVM way, or is there anymore MVVM framework that may enable this feature?
Related
I have viewlist in which contain elements. When I click on them, my ItemViewModel handler clicks. Then I can select information about that element. Afthe I must to open new page in which will be all information about it. For example like hypertext in browser.
<Border MaxHeight="300" MaxWidth="1140" CornerRadius="25" Margin="73,269,65,182">
<Grid x:Name="MainGrid" RenderTransformOrigin="0.5,0.5" Margin="0,0,10,-3">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListView Width="1031" ItemsSource="{Binding GetTopItem}"
ScrollViewer.VerticalScrollBarVisibility="Disabled" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Hidden"
Background="{x:Null}" BorderBrush="{x:Null}" Foreground="#DD000000"
x:Name="ListBook">
<ListView.DataContext>
<vm:BookMainVM/>
</ListView.DataContext>
<ListView.ItemTemplate>
<DataTemplate>
<Border HorizontalAlignment="Left" CornerRadius="25,25,25,25" BorderThickness="1" BorderBrush="#FF474747" Height="288" Margin="0,0,0,0" MouseDown="Border_MouseDown" >
<Grid Grid.Column="0" Height="Auto" Width="216" Margin="-1" IsEnabled="False">
<Grid.InputBindings>
<MouseBinding Gesture="LeftClick"
Command="{Binding DataContext.DelegateCommands,
RelativeSource={RelativeSource AncestorType=ListView}}"
CommandParameter="{Binding}">
</MouseBinding>
</Grid.InputBindings>
<Grid.RowDefinitions>
<RowDefinition Height="49*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="18*"/>
</Grid.RowDefinitions>
<Border CornerRadius="25,25,0,0" RenderTransformOrigin="0.5,0.5">
<Border.Background>
<ImageBrush ImageSource="{Binding Img_src}" Stretch="Fill" />
</Border.Background>
</Border>
<Label Content="{Binding Rate}" Background="#FFBFBFBF" RenderTransformOrigin="0.5,0.5" Grid.Row="1" FontSize="11" FontFamily="Meiryo UI" HorizontalContentAlignment="Center"/>
<Border CornerRadius="0,0,25,25" Grid.Row="2" Background="#FF8F8F8F">
<TextBlock Margin="6,0,0,0" Text="{Binding Name}" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Grid.Row="2" Height="61" Width="190"/>
</Border>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Border>
class ItemMainVM:ViewModel
{
private LibraryModel libraryModel;
private ItemDb itemsDb;
private const string Dir = "D:\\repos\\Frame\\Frame\\src";
public ItemMainVM()
{
libraryModel = new LibraryModel();
itemsDb = new BooksDb();
DelegateCommands = new DelegateCommand(o => EventHandler(o));
}
public ObservableCollection<BookPreviewInfo> GetTopItem
{
get
{
return libraryModel.GetTopItems();
}
}
public ICommand DelegateCommands { get; }
public void EventHandler(dynamic item)
{
itemDb.SelectItemId(item.Id);
}
}
Code Behind is empty.
When I click an element and executing EventHandler in ItemMainVM. And next must be create new page with new ElementViewModel.
ElementViewModel should to get information about element in ItemMainVM.
As the title implies, I'm trying to bind an element to inner usercontrol data context, but it's a bit complicated.
First of all, here is a snippet of my xaml view:
<TabControl Grid.Row="0" Grid.Column="1" Margin="5" TabStripPlacement="Top"
Style="{StaticResource TabControlStyle}" FontSize="16">
<TabItem Header="Local Settings" IsEnabled="{Binding ElementName=localSettings, Path=IsEnabled}">
<tabViews:LocalSettingsView x:Name="localSettings" DataContext="{Binding TabsVM, Converter={StaticResource dictionaryToViewModel}, ConverterParameter={x:Static enums:TabsEnum.LocalSettings}}" />
</TabItem>
... more TabItems ...
</TabControl>
As you can see, I've tried (without any luck) to bind it with element name, but it didn't work as expected.
I'm getting this exception in output window:
System.Windows.Data Error: 40 : BindingExpression path error: 'IsEnabled' property not found on 'object' ''LocalSettingsView' (Name='localSettings')'. BindingExpression:Path=IsEnabled; DataItem='LocalSettingsView' (Name='localSettings'); target element is 'TabItem' (Name=''); target property is 'IsEnabled' (type 'Boolean')
Here are the relevant code sections:
Binded property
private Dictionary<string, ITabViewModel> _tabsVM;
public Dictionary<string, ITabViewModel> TabsVM
{
get
{
if (_tabsVM == null)
{
_tabsVM = new Dictionary<string, ITabViewModel>()
{
{ "Network", new NetworkViewModel() },
{ "Cru", new CRUViewModel() },
{ "LocalSettings", new LocalSettingsViewModel() },
{ "Connectivity", new ConnectivityViewModel() },
{ "Security", new SecurityViewModel() },
};
}
return _tabsVM;
}
}
Converter
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Dictionary<string, ITabViewModel> _tabsVM = value as Dictionary<string, ITabViewModel>;
if (_tabsVM == null)
return null;
string param = Enum.GetName(typeof(TabsEnum), parameter);
ITabViewModel _selectedVM;
bool success = _tabsVM.TryGetValue(param, out _selectedVM);
if (success)
return _selectedVM;
else
return null;
}
and finally, TabsEnum
public enum TabsEnum
{
LocalSettings,
Network,
Connectivity,
Security,
Cru,
}
Edit
I'm adding the LocalSettingsView & it's ViewModel relevant part
<UserControl x:Class="ContentTemplateTest.Views.TabViews.LocalSettingsView"
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"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ContentTemplateTest;component/Styles/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<DockPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Hospital Name" />
<TextBox x:Name="hospitalTextBox" Grid.Row="0" Grid.Column="1" Text="DEMO - 000000" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Full Address" />
<TextBox Grid.Row="1" Grid.Column="1" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Department" />
<TextBox Grid.Row="2" Grid.Column="1" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="Date and Time" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding DateAndTime}" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="Interface Language" />
<ComboBox Grid.Row="4" Grid.Column="1" ItemsSource="{Binding Languages}"
SelectedItem="{Binding SelectedInterfaceLang}"/>
<TextBlock Grid.Row="5" Grid.Column="0" Text="Manual Language" />
<ComboBox Grid.Row="5" Grid.Column="1" ItemsSource="{Binding Languages}"
SelectedItem="{Binding SelectedManualLang}"/>
<TextBlock Grid.Row="6" Grid.Column="0" Text="Units" />
<ComboBox Grid.Row="6" Grid.Column="1" ItemsSource="{Binding Units}"
SelectedItem="{Binding SelectedUnit}"/>
<TextBlock Grid.Row="7" Grid.Column="0" Text="Video Settings" />
<ComboBox Grid.Row="7" Grid.Column="1" ItemsSource="{Binding VideoSettings}"
SelectedItem="{Binding SelectedVideoFormat}"/>
<TextBlock Grid.Row="8" Grid.Column="0" Text="Keyboard Input Language" />
<ComboBox Grid.Row="8" Grid.Column="1" ItemsSource="{Binding Languages}"
SelectedItem="{Binding SelectedKeyboardLang}"/>
</Grid>
<Grid VerticalAlignment="Bottom" DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Width="100" Height="100" Margin="50">
<Image Source="../../src/Save.png" Width="40" Height="40" Margin="20" />
</Button>
<Button Grid.Column="1" Width="100" Height="100" Margin="50">
<Image Source="../../src/Cancel.png" Width="40" Height="40" Margin="20" />
</Button>
<Button Grid.Column="2" Width="100" Height="100" Margin="50">
<Image Source="../../src/Export.png" Width="40" Height="40" Margin="20" />
</Button>
</Grid>
</DockPanel>
and the relevant property:
public bool IsEnabled
{
get { return false; }
}
How can I achieve my goal?
Thanks!
Pretty simple solution.
Just move to DataContext to the TabItem
<TabItem Header="Local Settings" IsEnabled="{Binding IsEnabled}"
DataContext="{Binding TabsVM, Converter={StaticResource dictionaryToViewModel}, ConverterParameter={x:Static enums:TabsEnum.LocalSettings}}" >
<tabViews:LocalSettingsView />
</TabItem>
I am trying to create a flipview on the an ItemDetailpage. I am using the default template provided in visual studio when creating a grid app.
Pages in the App: GroupItemsPage, GroupDetailPage, ItemDetailPage
The problem is, I am getting this error when I click on an item on the GroupItemsPage or GroupDetailPage:
Object reference not set to an instance of an object.
Error details:
System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=AppError
StackTrace: at AppError.ItemDetailPage.<navigationHelper_LoadState>d__0.MoveNext()
This is my code:
GroupItemsPage.xaml
<Page
x:Name="pageRoot"
x:Class="AppError.GroupedItemsPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AppError"
xmlns:data="using:AppError.Data"
xmlns:common="using:AppError.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<x:String x:Key="ChevronGlyph"></x:String>
<!--
Collection of grouped items displayed by this page, bound to a subset
of the complete item list because items in groups cannot be virtualized
-->
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="true"
ItemsPath="Items"
d:Source="{Binding Groups, Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"/>
</Page.Resources>
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Horizontal scrolling grid -->
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.RowSpan="2"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Title}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="60" Margin="15,0,15,0"/>
<TextBlock Text="{Binding Subtitle}" Foreground="{ThemeResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid GroupPadding="0,0,70,0"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="0,0,0,2">
<Button Foreground="{ThemeResource ApplicationHeaderForegroundThemeBrush}"
AutomationProperties.Name="Group Title"
Click="Header_Click"
Style="{StaticResource TextBlockButtonStyle}" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" Margin="0,-11,10,10" Style="{StaticResource SubheaderTextBlockStyle}" TextWrapping="NoWrap" />
<TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-11,0,10" Style="{StaticResource SubheaderTextBlockStyle}" TextWrapping="NoWrap" />
</StackPanel>
</Button>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
Style="{StaticResource NavigationBackButtonNormalStyle}"
VerticalAlignment="Top"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button"/>
<TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1"
IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40"/>
</Grid>
</Grid>
GroupItemsPage.xaml.cs
namespace AppError
{
public sealed partial class GroupedItemsPage : Page
{
private NavigationHelper navigationHelper;
private ObservableDictionary defaultViewModel = new ObservableDictionary();
public NavigationHelper NavigationHelper
{
get { return this.navigationHelper; }
}
public ObservableDictionary DefaultViewModel
{
get { return this.defaultViewModel; }
}
public GroupedItemsPage()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += navigationHelper_LoadState;
}
private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var sampleDataGroups = await SampleDataSource.GetGroupsAsync();
this.DefaultViewModel["Groups"] = sampleDataGroups;
}
void Header_Click(object sender, RoutedEventArgs e)
{
// Determine what group the Button instance represents
var group = (sender as FrameworkElement).DataContext;
// Navigate to the appropriate destination page, configuring the new page
// by passing required information as a navigation parameter
this.Frame.Navigate(typeof(GroupDetailPage), ((SampleDataGroup)group).UniqueId);
}
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
// Navigate to the appropriate destination page, configuring the new page
// by passing required information as a navigation parameter
var itemId = ((SampleDataItem)e.ClickedItem).UniqueId;
this.Frame.Navigate(typeof(ItemDetailPage), itemId);
}
}
GroupDetailpage.xaml
<Page
x:Name="pageRoot"
x:Class="AppError.GroupDetailPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AppError"
xmlns:data="using:AppError.Data"
xmlns:common="using:AppError.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!-- Collection of items displayed by this page -->
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Items}"
d:Source="{Binding Groups[0].Items, Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"/>
</Page.Resources>
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{Binding Group}"
d:DataContext="{Binding Groups[0], Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Horizontal scrolling grid -->
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Items In Group"
TabIndex="1"
Grid.RowSpan="2"
Padding="120,126,120,50"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Height="110" Width="480" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="110" Height="110">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap"/>
<TextBlock Text="{Binding Subtitle}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
<TextBlock Text="{Binding Description}" Style="{StaticResource BodyTextBlockStyle}" MaxHeight="60"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.Header>
<StackPanel Width="480" Margin="0,4,14,0">
<TextBlock Text="{Binding Subtitle}" Margin="0,0,0,20" Style="{StaticResource SubheaderTextBlockStyle}" MaxHeight="60"/>
<Image Source="{Binding ImagePath}" Height="400" Margin="0,0,0,20" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
<TextBlock Text="{Binding Description}" Margin="0,0,0,0" Style="{StaticResource BodyTextBlockStyle}"/>
</StackPanel>
</GridView.Header>
<GridView.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<Setter Property="Margin" Value="52,0,0,2"/>
</Style>
</GridView.ItemContainerStyle>
</GridView>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
Style="{StaticResource NavigationBackButtonNormalStyle}"
VerticalAlignment="Top"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button"/>
<TextBlock x:Name="pageTitle" Text="{Binding Title}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1"
IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40"/>
</Grid>
</Grid>
GroupDetailPage.xaml.cs
namespace AppError
{
public sealed partial class GroupDetailPage : Page
{
private NavigationHelper navigationHelper;
private ObservableDictionary defaultViewModel = new ObservableDictionary();
public NavigationHelper NavigationHelper
{
get { return this.navigationHelper; }
}
public ObservableDictionary DefaultViewModel
{
get { return this.defaultViewModel; }
}
public GroupDetailPage()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += navigationHelper_LoadState;
}
private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var group = await SampleDataSource.GetGroupAsync((String)e.NavigationParameter);
this.DefaultViewModel["Group"] = group;
this.DefaultViewModel["Items"] = group.Items;
}
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
// Navigate to the appropriate destination page, configuring the new page
// by passing required information as a navigation parameter
var itemId = ((SampleDataItem)e.ClickedItem).UniqueId;
this.Frame.Navigate(typeof(ItemDetailPage), itemId);
}
}
ItemDetailPage.xaml
<Page
x:Name="pageRoot"
x:Class="AppError.ItemDetailPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AppError"
xmlns:data="using:AppError.Data"
xmlns:common="using:AppError.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<CollectionViewSource
x:Name="itemViewSource"
Source="{Binding Items}"
d:Source="{Binding Groups[0].Items, Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"/>
</Page.Resources>
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{Binding Item}"
d:DataContext="{Binding Groups[0].Items[0], Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--
TODO: Content should be placed within the following grid
to show details for the current item
-->
<FlipView
Grid.Row="1"
x:Name="flipView"
Margin="50,0,0,0"
ItemsSource="{Binding Source={StaticResource itemViewSource}}">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="500"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel>
<Border>
<Image Source="{Binding ImagePath}"/>
</Border>
<TextBlock Text="{Binding Description}" Padding="0,30,0,0" TextWrapping="Wrap"/>
</StackPanel>
<Grid Grid.Column="1" Margin="30,0,0,0">
<TextBlock Text="{Binding Content}" TextWrapping="Wrap"/>
</Grid>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
Style="{StaticResource NavigationBackButtonNormalStyle}"
VerticalAlignment="Top"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button"/>
<TextBlock x:Name="pageTitle" Text="{Binding Title}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1"
IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40"/>
</Grid>
</Grid>
ItemDetailPage.xaml.cs
namespace AppError
{
public sealed partial class ItemDetailPage : Page
{
private NavigationHelper navigationHelper;
private ObservableDictionary defaultViewModel = new ObservableDictionary();
public NavigationHelper NavigationHelper
{
get { return this.navigationHelper; }
}
public ObservableDictionary DefaultViewModel
{
get { return this.defaultViewModel; }
}
public ItemDetailPage()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += navigationHelper_LoadState;
}
private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var group = await SampleDataSource.GetGroupAsync((String)e.NavigationParameter);
var item = await SampleDataSource.GetItemAsync((String)e.NavigationParameter);
this.DefaultViewModel["Group"] = group;
this.DefaultViewModel["Items"] = group.Items;
this.flipView.SelectedItem = item;
}
}
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;
}
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));
}