Bind ItemsSource to Column of ComboBoxes - c#

As per title. The column is in a DataTemplate.
This is what I have currently:
var test = FindChildControl<ComboBox>(this, "PrintCode") as ComboBox;
test.ItemsSource = listPrintCode;
MessageBox.Show(test.Items.Count.ToString());
FindChildControl method:
private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
{
int childNumber = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < childNumber; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(control, i);
var fe = child as FrameworkElement;
// Not a framework element or is null
if (fe == null) return null;
if (child is T && fe.Name == ctrlName)
{
// Found the control so return
return child;
}
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
return null;
}
XAML - Template
<DataTemplate x:Key="lbCommsItemSetTemplate">
<Grid Margin="0" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" />
<TextBlock Grid.Row="0" Grid.Column="0" Foreground="Blue" Margin="40,0,0,0"
Text="{Binding CommonDesc}" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Serial:" Margin="0,0,0,0"/>
<TextBlock Grid.Row="1" Grid.Column="0" Foreground="Blue" Margin="35,0,0,0"
Text="{Binding Serial}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="lbIssueTemplate">
<Grid Margin="0" Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" />
<TextBlock Grid.Row="0" Grid.Column="0" Foreground="Blue" Margin="50,0,0,0"
Text="{Binding CommonDesc}" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="Qty:" Margin="10,0,0,0"/>
<TextBox Grid.Row="0" Grid.Column="1" Foreground="Blue" Margin="35,0,0,0"
Text="{Binding LoanQty}" PreviewTextInput="UIElement_OnPreviewTextInput" MaxLength="4"
GotKeyboardFocus="UIElement_OnGotKeyboardFocus" MaxLines="1"/>
<ComboBox x:Name="PrintCode" Grid.Row="0" Grid.Column="2" ItemsSource="{Binding}"
SelectedValuePath="PrintCode" DisplayMemberPath="PrintCode"/>
<CheckBox Grid.Row="0" Grid.Column="3" IsChecked="{Binding PrintShortSerial}"/>
</Grid>
</DataTemplate>
XAML - ListBox that implements the Template
<telerik:RadListBox Grid.Row="0" Grid.Column="2" Margin="0, 5, 5, 5"
x:Name="listBoxIssue" HorizontalAlignment="Left" VerticalAlignment="Top"
Height="690" Width="793"
ItemTemplate="{StaticResource lbIssueTemplate}" ItemsSource="{Binding}"
SelectionMode="Multiple" Drop="ListBoxIssue_OnDrop"/>
The message box is just simply to confirm that 'listPrintCode' and 'FindChildControl' is working as intended. But the ComboBox didn't display anything, even if it's just 1 ComboBox. If I apply the codes to a normal ComboBox not part of the template, it's all fine. I think there's an obvious flaw in my code, which is that there's nothing that seems to apply to all ComboBoxes in the column. So my question is, how do I bind my ItemsSource as the column of the comboboxes?
Note: The number of rows (ComboBoxes) are not fixed.

Related

How to add row style to ListBox ItemTemplate in silverlight

I have problem in add alternate row style for ListBox.ItemTemplate
This is the way I code
<ListBox x:Name="NListBox" ItemsSource="{Binding NList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedItem,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource CommonListBoxStyle}" Loaded="NListBox_Loaded">
<ListBox.ItemTemplate >
<DataTemplate >
<Grid Margin="0" Width="1600"
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*"/>
<ColumnDefinition Width="2*" ></ColumnDefinition>
<ColumnDefinition Width="2*" ></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock FontSize="20" Loaded="TextBlock_Loaded" Grid.ColumnSpan="3" Text="{Binding H}" />
<TextBlock Grid.Row="0" Grid.Column="1" FontSize="12" HorizontalAlignment="Right">Publish Date</TextBlock>
<TextBlock Grid.Row="0" Grid.Column="3" FontSize="12" Text="{Binding PublishDate,StringFormat=\{0:dd.MM.yy\}}"
/>
<TextBlock Grid.Row="1" FontSize="15" TextWrapping="Wrap" Grid.ColumnSpan="3" Text="{Binding Description}"
Height="50" />
<TextBlock Grid.Row="2" Grid.Column="0" FontSize="12" Text="{Binding link}" />
<TextBlock Grid.Row="2" Grid.Column="1" FontSize="12" HorizontalAlignment="Right">Expiry Date</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="3" FontSize="12" Text="{Binding ExpiryDate,StringFormat=\{0:dd.MM.yy\}}"
/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This the why I did this
.xml
<converters:RowStyleConverter x:Key="RowStyleConverter"/>
<ListBox>
<ListBox.ItemTemplate >
<DataTemplate >
<Grid Background="{Binding Converter={StaticResource RowStyleConverter}}"></Grid>
</DataTemplate >
</ListBox.ItemTemplate >
</ListBox>
C#
public class RowStyleConverter : IValueConverter
{
int counter = 0;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (counter % 2 == 1)
{
return new SolidColorBrush(Color.FromArgb(255, 233, 252, 251));
}
else
{
return new SolidColorBrush(Color.FromArgb(255, 220, 239, 238));
}
counter++;
}
}

Bind element to inner UserControl data context

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>

Mahapps : ScrollViewer update list on event KeyDown in WPF ( C # )

I have a problem I can not solve.
As you can see in the picture , there is a label , a textobx and a ScrollViewer .
Now , I have to update the ScrollViewer when the user searches through the textbox .
Part of an event every time you make a keydown .
So if I write Statut ... should put first in the file list with the names "statuto rai"
the list can have N elements
Image list:
Xaml code:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"></RowDefinition>
<RowDefinition Height="25"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="GhostWhite"/>
<Grid Grid.Row="1" Background="Gray"/>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Documenti allegati</TextBlock>
<Border Grid.Row="1" Margin="3" BorderBrush="White" Height="22" Background="#fff">
<TextBox BorderBrush="#465E76" KeyDown="TextBox_KeyDown" BorderThickness="0" FontSize="10" Background="#fff" Foreground="#565656" controls:TextBoxHelper.Watermark="Ricerca Locale" FontFamily="{StaticResource Lato Thin}" HorizontalContentAlignment="Center" ></TextBox>
</Border>
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Hidden" PanningMode="Both" Name="scrollDocuments">
<ItemsControl ItemsSource="{Binding Path=attachmentsList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Grid.Column="0" Grid.Row="0">
<Button Grid.ColumnSpan="2">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="450"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="#fff"></Grid>
<TextBlock Foreground="#565656" FontFamily="{StaticResource Lato Semibold}" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="10" Margin="10,3,0,0" Style="{DynamicResource Lato-Semibold}" Text="{Binding contList}"/>
<Image Source="/Resources/Images/icon-document-browser.png" HorizontalAlignment="Left" Margin="22,-12,0,0" Width="22"/>
<TextBlock Foreground="#565656" FontFamily="{StaticResource Lato Semibold}" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="10" Margin="21,32,0,0" Style="{DynamicResource Lato-Semibold}" Text="{Binding FileSizeConverted}"/>
<TextBlock Foreground="#565656" FontFamily="{StaticResource Lato Semibold}" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="12" Margin="55,-10,0,0" Style="{DynamicResource Lato-Semibold}" Text="{Binding Name}"/>
<TextBlock Foreground="#565656" FontFamily="{StaticResource Lato Semibold}" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="12" Margin="55,-10,10,0" Style="{DynamicResource Lato-Semibold}" Text="{Binding ModifiedDate}"/>
<TextBlock Foreground="#565656" FontFamily="{StaticResource Lato Semibold}" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="10" Margin="55,25,10,0" FontWeight="Bold" Style="{DynamicResource Lato-Semibold}" Text="Nessuna copia locale"/>
<Border Grid.Row="0" Grid.ColumnSpan="2" BorderBrush="#DDD" BorderThickness="0,0,0,1"></Border>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<Viewbox Grid.Row="2" Name="testoNessunAllegato" Visibility="Collapsed" Margin="20">
<TextBlock Text="Nessun allegato disponibile."></TextBlock>
</Viewbox>
</Grid>
CodeBehind event code:
private void TextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
string find = ((TextBox)sender).Text;
attachmentsList = attachmentsList.Where(x => x.Name == find).ToList();
InitializeComponent();
}
in practice I do the intelligiente research, so every time I insert a letter filtrale list , and print it again , of course real time .
I hope I explained myself .
Thank you
I see you use bindings, in this case there is a much better stuff to reach your goal. It's CollectionView.
Here is a simple app for you which more or less fullfill your requirements:
View
<StackPanel Orientation="Horizontal">
<Label Content="Search" />
<TextBox MinWidth="30" Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<ListBox ItemsSource="{Binding Data}" />
UpdateSorceTrigger=PropertyChanges updates FilterText in ViewModel every time when you press any key.
Data is a ICollectionView
ViewModel
public ICollectionView Data { get; private set; }
...
// Create default view for the list
Data = CollectionViewSource.GetDefaultView(list);
// Set filter delegate for CollectionView
Data.Filter = FilterData;
....
private bool FilterData(object obj)
{
DataContainer cont = (DataContainer)obj;
return string.IsNullOrEmpty(FilterText) || cont.Name.StartsWith(FilterText, StringComparison.OrdinalIgnoreCase);
}
private string myfiltertext;
public string FilterText
{
get { return myfiltertext; }
set
{
myfiltertext = value;
// Refresh collection view after Filter text modification
Data.Refresh();
}
}

Out of memory exception while using <ScrollViewer> with multiple ListViews in it

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;
}

Grid height not adjusting properly when a row height with SharedSizeGroup changes

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));
}

Categories

Resources