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?
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++;
}
}
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;
}
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.
I have a datagrid:
<Grid x:Name="MainDataGrid" Grid.Row="5" >
<data:DataGrid x:Name="datagrid" AutoGenerateColumns="False" HorizontalAlignment="Stretch" IsReadOnly="True" VerticalAlignment="Top" ItemsSource="{Binding DataList}" Height="220" Margin="5">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="#" Binding="{Binding Number}" />
<data:DataGridTextColumn Header="Business Process" Width="300" Binding="{Binding BusinessProcess}" />
<data:DataGridTextColumn Header="Sub Process" Width="300" Binding="{Binding SubProcess}" />
<data:DataGridTextColumn Header="ITAC" Width="100" Binding="{Binding Itac}" />
<data:DataGridTextColumn Header="Status" Width="200" Binding="{Binding Status}" />
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
Which is currently bound to some dummy data I created in the ViewModel:
public class ItacViewModel : ViewModelBase
{
public List<data> DataList { get; set; }
public ItacViewModel()
{
var dataList = new List<data>
{
new data(1, "Fixed Asset", "Depreciation", "UL-AC1", "Under Review"),
new data(2, "Fixed Asset", "Depreciation", "UL-AC2", "Complete"),
new data(3, "Order to Cash", "Invoicing", "UL-AC3", "Under Review"),
new data(4, "Order to Cash", "Shipping Goods", "UL-AC4", "Under Review"),
new data(5, "Order to Cash", "Depreciation", "UL-AC5", "Complete"),
new data(6, "Order to Cash", "Depreciation", "UL-AC6", "Under Review"),
new data(7, "Order to Cash", "Depreciation", "UL-AC7", "Complete"),
new data(8, "Stock and Make", "Depreciation", "UL-AC8", "Under Review"),
new data(9, "Stock and Make", "Depreciation", "UL-AC9", "Under Review"),
new data(10, "General Accounting & Reporting", "Depreciation", "UL-AC10", "Complete")
};
DataList = dataList;
}
}
I wish to be able to filter the data when a Radio Button is selected (The Radio Button names match those in the second column in the datagrid):
<StackPanel Margin="2">
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="All Business Processes" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="Fixed Asset" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="Order to Cash" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="Purchase to Pay" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="Stock and Make" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="General Accounting and Reporting" FontStyle="Italic" />
</StackPanel>
<TextBlock Text=" " />
</StackPanel>
So far I have not been able to make this work.
EDIT
Here is all my code so far:
MAINPAGE.XAML
<UserControl x:Class="TabControl.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="800">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<controls:TabControl Margin="3">
<controls:TabItem Header="Local / Monitoring Controls" />
<controls:TabItem Header="IBM Controls" />
<controls:TabItem Header="ITAC's" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Border BorderThickness="1" BorderBrush="WhiteSmoke" Background="#A1B9DD" CornerRadius="2" >
<StackPanel Orientation="Horizontal" >
<TextBlock Text="ITAC's - IT Automated Controls in Key Financial Systems" FontSize="12" FontWeight="Bold" Margin="5" />
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="Date Last Updated: " />
<TextBlock Text="Test Date, needs binding" />
</StackPanel>
</StackPanel>
</Border>
<Border BorderThickness="1" BorderBrush="WhiteSmoke" Background="#A1B9DD" CornerRadius="2">
<TextBlock Text="ERP controls from Sirius" FontStyle="Italic" Margin="5" />
</Border>
</StackPanel>
<Grid x:Name="Controls" Grid.Row="1" Background="#A1AEC3">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Row="0" Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="WhiteSmoke" Background="#A1B9DD" CornerRadius="2" Margin="1" >
<TextBlock Text="IT Automated Controls (Europe)" FontSize="12" FontWeight="Bold" Margin="5"/>
</Border>
<StackPanel Grid.Row="1" Grid.Column="0" Margin="0,0,10,0" >
<TextBlock Text="Total Active Controls" FontWeight="Bold" Margin="5,5,5,0" TextAlignment="Right" />
<TextBlock Text="ITAC's Under Review" Margin="5,5,5,0" TextAlignment="Right" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="Outstanding Issues from Previous Months" Margin="5,5,5,0" TextAlignment="Right" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Margin="10,0,0,0" >
<TextBox Width="200" TextAlignment="Center" Text="33" />
<TextBox Width="200" TextAlignment="Center" Text="5" />
<TextBox Width="200" TextAlignment="Center" Text="0" />
</StackPanel>
</Grid>
<Grid x:Name="ITACs" Grid.Row="2" Background="#A1AEC3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.Row="0" Grid.Column="0" BorderThickness="1" BorderBrush="WhiteSmoke" Background="#A1B9DD" CornerRadius="2" Margin="1" >
<StackPanel Orientation="Horizontal" Margin="3">
<StackPanel Orientation="Horizontal" >
<RadioButton GroupName="BusinessProcessTitle" />
<TextBlock Text="All ITAC's" FontWeight="Bold" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="100,0,0,0" >
<RadioButton GroupName="BusinessProcessTitle" />
<TextBlock Text="ITAC's Requiring Review" FontWeight="Bold" />
</StackPanel>
</StackPanel>
</Border>
<Border Grid.Row="1" Grid.RowSpan="2" Grid.Column="0" BorderThickness="1" BorderBrush="WhiteSmoke" CornerRadius="2" Margin="1" >
<StackPanel Margin="2">
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="All Business Processes" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1" />
<TextBlock Text="Fixed Asset" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="Order to Cash" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="Purchase to Pay" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="Stock and Make" FontStyle="Italic" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<RadioButton GroupName="BusinessProcessesGroup" />
<TextBlock Text="General Accounting and Reporting" FontStyle="Italic" />
</StackPanel>
<TextBlock Text=" " />
</StackPanel>
</Border>
<Border Grid.Row="0" Grid.Column="1" BorderThickness="1" BorderBrush="WhiteSmoke" Background="#A1B9DD" CornerRadius="2" Margin="1" >
<Grid >
<TextBlock Text="ITAC Description" FontWeight="Bold" HorizontalAlignment="Left" Margin="3" />
<TextBlock Text="UL-AC1" FontStyle="Italic" HorizontalAlignment="Right" Margin="3"/>
</Grid>
</Border>
<Border CornerRadius="2" Grid.Row="1" Grid.Column="1" BorderThickness="1" BorderBrush="WhiteSmoke">
<TextBlock TextWrapping="Wrap" Margin="3"
Text="Based on the asset class in the master data, the ERP system automatically calculates correct amounts for depreciation at the start of the depreciation run." />
</Border>
<Border CornerRadius="2" Grid.Row="2" Grid.Column="1" BorderThickness="1" BorderBrush="WhiteSmoke">
<StackPanel Orientation="Horizontal" Margin="1">
<TextBlock Text="Issue: " Margin="3,0,0,0" />
<TextBlock Text="Change Request to be created - Query Update Required" />
</StackPanel>
</Border>
</Grid>
<Grid x:Name="MainDataGrid" Grid.Row="5" >
<data:DataGrid x:Name="datagrid" AutoGenerateColumns="False" HorizontalAlignment="Stretch" IsReadOnly="True" VerticalAlignment="Top" ItemsSource="{Binding DataList}" Height="220" Margin="5">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="#" Binding="{Binding Number}" />
<data:DataGridTextColumn Header="Business Process" Width="300" Binding="{Binding BusinessProcess}" />
<data:DataGridTextColumn Header="Sub Process" Width="300" Binding="{Binding SubProcess}" />
<data:DataGridTextColumn Header="ITAC" Width="100" Binding="{Binding Itac}" />
<data:DataGridTextColumn Header="Status" Width="200" Binding="{Binding Status}" />
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
</Grid>
</controls:TabItem>
<controls:TabItem Header="User Access" />
<controls:TabItem Header="User Provisioning" />
<controls:TabItem Header="About" />
</controls:TabControl>
</Grid>
</UserControl>
MAINPAGE.XAML.CS
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.DataContext = new ItacViewModel();
}
}
DATA.CS
public class data
{
public int Number { get; set; }
public string BusinessProcess { get; set; }
public string SubProcess { get; set; }
public string Itac { get; set; }
public string Status { get; set; }
public data(int number, string businessProcess, string subProcess, string itac, string status)
{
Number = number;
BusinessProcess = businessProcess;
SubProcess = subProcess;
Itac = itac;
Status = status;
}
}
ITACVIEWMODEL.CS
public class ItacViewModel : ViewModelBase
{
public List DataList { get; set; }
public ItacViewModel()
{
var dataList = new List<data>
{
new data(1, "Fixed Asset", "Depreciation", "UL-AC1", "Under Review"),
new data(2, "Fixed Asset", "Depreciation", "UL-AC2", "Complete"),
new data(3, "Order to Cash", "Invoicing", "UL-AC3", "Under Review"),
new data(4, "Order to Cash", "Shipping Goods", "UL-AC4", "Under Review"),
new data(5, "Order to Cash", "Depreciation", "UL-AC5", "Complete"),
new data(6, "Order to Cash", "Depreciation", "UL-AC6", "Under Review"),
new data(7, "Order to Cash", "Depreciation", "UL-AC7", "Complete"),
new data(8, "Stock and Make", "Depreciation", "UL-AC8", "Under Review"),
new data(9, "Stock and Make", "Depreciation", "UL-AC9", "Under Review"),
new data(10, "General Accounting & Reporting", "Depreciation", "UL-AC10", "Complete")
};
DataList = dataList;
}
}
Instead of binding your DataGrid to List<data> you should bind data to ICollectionView. ICollectionView makes operations like grouping, filtering etc very simple to implement on some Data.
Take a look at this simple yet informative article on how to achieve filtering in WPF through ICollectionView
Edit
As Silverlight doesn't support provide an implementation of ICollectionView out of the box take a look at this or this article
Here's the trivial way: modify the Visibility of your Datagrid columns depending on the state of your radiobuttons.
XAML:
<data:DataGridTextColumn x:Name="colFixedAsset" Header="Status" Width="200" Binding="{Binding Status}" />
<RadioButton x:Name="radioFixedAsset" GroupName="BusinessProcessesGroup" IsChecked="False" Checked="radioFixedAsset_Checked" Unchecked="radioFixedAsset_Unchecked" />
Code behind:
private void radioFixedAsset_Checked(object sender, RoutedEventArgs e)
{
this.colFixedAsset.Visibility = System.Windows.Visibility.Visible;
}
private void radioFixedAsset_Unchecked(object sender, RoutedEventArgs e)
{
this.colFixedAsset.Visibility = System.Windows.Visibility.Collapsed;
}
If you're a MVVM purist, then add boolean properties to your view model and bind the IsChecked properties of your radiobuttons to those booleans. Also bind the Visibility property of your datagrid columns to those booleans using a converter.