I have this XAML code and i want to access either the AccountNameTextBox or the elipse few lines below in order to display that some of the Accounts in the list are expired by adding something next to the name (ex. YouTube(Expired)) or by turning the elipse red. The thing is that i can't access them. I have tried using the VisualTreeHelper functions i saw here
How can I find WPF controls by name or type? and even tried creating some of my own but nothing works. A thing i noticed was that when i used "VirtualTreeHelper.GetChild" on accountListBox the output was a Border Control and it was the only child.
The code is below.
`<StackPanel x:Name="MainStackPanel" Grid.Row="1" Grid.RowSpan="2" DataContext="{StaticResource ResourceKey=accountManager}">
<ListBox x:Name="accountListBox" ItemsSource="{Binding LoadedAccounts}" Height="600" VerticalAlignment="Bottom" Margin="10,10" Background="Transparent" DoubleTapped="accountListBox_DoubleTapped" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10,0,0,0">
<TextBlock x:Name="AccountNameTextBox" Text="{Binding AccountName}" FontFamily="Segoe Script" FontSize="30" Foreground="White"/>
<StackPanel Orientation="Horizontal">
<StackPanel>
<!--<TextBlock Text="{Binding Username}" FontSize="25" Foreground="Lime"/>-->
<TextBlock Text="{Binding Email}" FontStyle="Italic" FontSize="25" Foreground="DarkSeaGreen"/>
<TextBlock Text="{Binding Password}" FontSize="25" Foreground="YellowGreen"/>
</StackPanel>
<Ellipse x:Name="Elipse" Height="Auto" Width="10" Margin="10,0">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="YellowGreen" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>`
Why not using Triggers or Converters?
For that you have to add a single property to your bound items (i called mine IsExpired)
Then in the DataTemplate add the DataTrigger:
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsExpired}" Value="True">
<Setter Property="Visibility" Value="Visible" TargetName="ExpiredTextBlock" />
<Setter Property="Fill" Value="Red" TargetName="Elipse" />
</DataTrigger>
</DataTemplate.Triggers>
A possibility with converter would be to add a Converter-Resource to your DataTemplate:
<DataTemplate.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</DataTemplate.Resources>
Then add your (Expired) TextBlock to the DataTemplate and bind to the property
<TextBlock Text="(Expired)" Visibility="{Binding IsExpired, Converter={StaticResource BooleanToVisibilityConverter}}"/>
For the Color you could do the same with a BooleanToColorConverter.
If you want to stick to your code approach you have to dive deeper in your visual tree:
public static T GetChildOfType<T>(this DependencyObject depObj)
where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
This helper method finds the first child of a given type.
If you want to find it by name you have to use the name as parameter instead of the generic type and replace the (child as T) check by a name-check.
My personal preferrence would be the solution with the triggers, but it's up to you..
Related
I'm having some difficulty updating a certain binding.
I have a class DeviceList that loads some devices, it inherits from ObservableCollection and is listed as a resource in my XAML:
<local:DeviceList x:Key="Devices" />
Then, I have a CollectionViewSource that uses this devicelist as source, and groups it by a property from the Device:
<CollectionViewSource x:Key="cvsDevices" Source="{StaticResource Devices}" Filter="CollectionViewSource_Filter">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="GroupId" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
A Datagrid binding to this CVS, which has a group header style:
<DataGrid x:Name="dataGrid" ItemsSource="{Binding Source={StaticResource cvsDevices}}">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
bla bla
</DataGrid.Columns>
</DataGrid>
And then finally the Group Header style in the resources:
<Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" Background="White" Foreground="Black">
<Expander.Header>
<StackPanel Orientation="Horizontal" Height="30">
<Border Margin="5" Width="20" Height="20" Background="{Binding Path=Items, Converter={StaticResource DeviceGroupToColorConverter}}" CornerRadius="10" />
<TextBlock VerticalAlignment="Center" Padding="3" Text="{Binding Name, Converter={StaticResource DeviceGroupToGroupTitleConverter}}" />
<TextBlock VerticalAlignment="Center" Padding="3" Text="{Binding ItemCount, Converter={StaticResource ItemCountToStringConverter}}"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
As you can see, there's a Border there that binds to "Items". This is a property of "CollectionViewGroup": https://learn.microsoft.com/en-us/dotnet/api/system.windows.data.collectionviewgroup?view=netcore-3.1
Basically each of my devices has a property "Connection", and when this property changes, I would like to set the color of this border in the corresponding group header.
The binding works fine the first time, but after that the DeviceGroupToColorConverter isn't called anymore when a connection changes. Device implements INotifyPropertyChanged, but I have no idea how to propagate that event to CollectionViewGroup's Items property. In fact, I have no idea where CollectionViewGroup instances live. I only have access to the CollectionViewSource.
I would like to avoid refreshing the entire DataGrid. I've read that it resets my expanders and also, why refresh the entire datagrid when only a certain group's header should change?
I have solved it by changing the binding to a MultiBinding and adding a binding with a Source set to the DeviceList:
<Border Margin="5" Width="20" Height="20" CornerRadius="10">
<Border.Background>
<MultiBinding Converter="{StaticResource DeviceGroupToColorConverter}">
<Binding Source="{StaticResource Devices}" Path="Devices" />
<Binding Path="Name" />
</MultiBinding>
</Border.Background>
</Border>
the "Devices" property of the DeviceList class is a simple getter that returns "this":
public ObservableCollection<Device> Devices
{
get
{
return this;
}
}
I let the DeviceList listen to any property changes on device, and invoke PropertyChanged on the "Devices" property of DeviceList to pass on this event to the MultiBinding.
I then use the Name binding in the MultiBinding to filter my devices based on the group that they're in. Now I don't need to refresh the whole grid and my performance is good.
I'm looking for a way to assign style with parameters(most of them just text) and assign to specified blocks
<StackPanel Orientation="Horizontal">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="field1" Text="Field1"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Default" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="field2" Text="Field2"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="RCC" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="field3" Text="Field3"/>
</StackPanel>
</StackPanel>
<Rectangle Width="1" Fill="Black" Height="42" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal">
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Custom" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<TextBox Width="90" Height="15"/>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Apply" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
</StackPanel>
</StackPanel>
There is 3 TextBlocks(field1,field2,field3), now is there any way to pass parameters(parameters are string type), to this template, and this template is generated through loop. And how to do it? Of course I could make everything in c# but thought it would be much easier just create field(stackpanel) and assign parameters
<stackpanel Style="{StaticResource mystyle}" param1="hello" param2="this" param3="world"/>
This would be perfect if its possible to make this way. Unless there is better one. Thanks for help.
You can by declaring your own Styles and Control templates with additional use of DependencyProperties.
A DependencyProperty is basically a declaration on your own custom class of your own custom property that you want to expose available during xaml entry and can also be applied to your style templates.
Once that is done, you then define your style, plenty of resources on that. Include your dependency properties as {TemplateBinding} to your custom properties.
Then add instance of your new class to your form, and specify which style to use. I have a sample showing utilization of TWO styles under the same class. I first started with a brand new WPF application. In the MainWindow.xaml.cs, I defined my own class based on a type of UserControl (which can then hold any other control(s) such as you have nested). I added 3 Dependency Properties to reflect 3 possible text values you want to implement.
public class MyControl : UserControl
{
public static readonly DependencyProperty MyText1Property =
DependencyProperty.Register("MyText1", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText1
{
get { return (string)GetValue(MyText1Property); }
set { SetValue(MyText1Property, value); }
}
public static readonly DependencyProperty MyText2Property =
DependencyProperty.Register("MyText2", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText2
{
get { return (string)GetValue(MyText2Property); }
set { SetValue(MyText2Property, value); }
}
public static readonly DependencyProperty MyText3Property =
DependencyProperty.Register("MyText3", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText3
{
get { return (string)GetValue(MyText3Property); }
set { SetValue(MyText3Property, value); }
}
}
Next, my application name is StackOverflow for sample purposes, and in the following is the entire MainWindow.xaml. Clarification of components follows code.
<Window.Resources>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding MyText1}"/>
<TextBlock Text="{TemplateBinding MyText2}"/>
<TextBlock Text="{TemplateBinding MyText3}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock Text="{TemplateBinding MyText1}"/>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Default" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{TemplateBinding MyText2}"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="RCC" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{TemplateBinding MyText3}"/>
</StackPanel>
</StackPanel>
<Rectangle Width="1" Fill="Black" Height="42" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal">
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Custom" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<TextBox Width="90" Height="15"/>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Apply" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
</StackPanel>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- NOW, we can expand the custom properties-->
<Style TargetType="{x:Type myApp:MyControl}" BasedOn="{StaticResource MyControlStyle}" />
</Window.Resources>
<Grid Height="150">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<myApp:MyControl MyText1="First String" MyText2="Second String" MyText3="Third String"
Style="{StaticResource MyControlStyle}"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="1"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="2"
Style="{StaticResource MyControlStyle1}"/>
</Grid>
At the top within the main declaration, I added
xmlns:myApp="clr-namespace:StackOverflow"
this basically states that when within this xaml file, I see a prefix of "myApp", it is similar to a "using StackOverflow;" command as if in code. So now I have access to the custom class(es) or other things within that namespace to the xaml.
Next I start to declare my own "style" for the custom MyControl class via
<Window.Resources>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
...
You might want to create a separate ResourceDictionary if you deal with many styles / templates used throughout your app. Notice the "Syle" and custom "ControlTemplate" are based on the "myApp:MyControl" class structure. Now, I can make use of my "MyText1", "MyText2", "MyText3" elements within the control template.
The x:Key="MyControlStyle1" is like creating a variable by given name so it can be used if you need to explicitly say which style to use. This first style is just to show the point that the 3 "MyText" properties are available and the Text is getting its value from the
Text="{TemplateBinding MyText1}"
Class that the control template is bound to (hence TemplateBinding).
Once you get the basics working, then you can glorify your template as you have with your nested stack panels which is the lower
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle">
declaration by a different x:Key name.
Now, so you don't have to explicitly keep adding xaml for your control and say... by the way, use this explicit style of MyControlStyle, I have the following
<Style TargetType="{x:Type myApp:MyControl}" BasedOn="{StaticResource MyControlStyle}" />
indicating whenever you see a target type of "MyControl", default the style to the "MyControlStyle" so I don't have to keep remembering to do it.
Finally implementing its use. The end of the code has a simple Grid control with 3 rows.
<myApp:MyControl MyText1="First String" MyText2="Second String" MyText3="Third String"
Style="{StaticResource MyControlStyle}"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="1"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="2"
Style="{StaticResource MyControlStyle1}"/>
Notice the first instance I CAN explicitly declare the style to be used. The second has no explicit style as per the default, but the third instance explicitly states to use the simplified "MyControlStyle1" which was just the 3 textblocks side-by-side showing that you can have one class and make it look differently as needed.
Revision per questions/comments.
If you are building these controls based on a loop and dynamically adding them, you would just set the properties respectively in the code. Performance should not be significant because the CLASS is already declared, you are just adding one more into your list.
foreach( var oneThing in YourListOfToBeAddedItems )
{
var mc = new MyControl();
mc.MyText1 = oneThing.TextFieldUsedForField1;
mc.MyText2 = oneThing.FieldForSecondText;
mc.MyText3 = oneThing.ThirdTextBasisForDisplay;
// Now, add the "mc" to whatever your control is
// can't confirm this line below as I dont know context
// of your form and dynamic adding.
YourWindowGridOrOtherControl.Controls.Add( mc );
}
Also, since the default style was defined, I would not need to explicitly declare the "Style" for the control.
Currently I am trying to add a context menu to a ListBox that uses an item template. I am able to get the context menu items added, but when I try to bind the commands, nothing happens.
The Main_Window has a data context set. Here is the XAML for the ListBox. I use a similar Binding style as part of a button in the ListView.ItemTemplate so I would assume this would work, but sadly it is not. What am I missing here? (Only important part of the code is here)
<ListBox x:Name="company_buttons_listbox"
ItemsSource="{Binding Buttons_Binding}"
SelectedIndex="{Binding Selected_Index, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Update Frazer Server Link" Foreground="Black" FontFamily="Segoe UI" FontSize="14" FontWeight="Bold"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Command="{Binding ElementName=Main_Window, Path=DataContext.Testing}"/>
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightSteelBlue" Opacity="0.5"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="LightSteelBlue" Opacity="0.5"/>
</Style.Resources>
</Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="Continue"/>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="-2,0,-2,0">
<Button CommandParameter="{Binding}"
Command="{Binding ElementName=Main_Window, Path=DataContext.Open_Link}">
</Button>
<Label VerticalContentAlignment="Top"
Margin="5,0,5,0" Height="19" Padding="0"
Foreground="White" FontFamily="Segoe UI" FontSize="12" FontWeight="Bold"
Content="{Binding ItemText}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So, I solved this by not solving this and instead used a work around.
Essentially the issue comes from this:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference
I found that Context Menus are not part of the Visual Tree (not happy about that) and hence cannot access those elements in the same fashion.
I am not a fan of using Reflection so the ElementSpy method is off the table for me along with. I tried to directly set a Click="some_function" and that also surprisingly DID not work.
I instead just wrapped my entire ListBox in a Grid and used the following. Not really MVVM, but I could care less at this point with how much wasted time I put into finding a solid and reliable solution.
XAML:
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu Item Text" Foreground="Black" FontFamily="Segoe UI" FontSize="14" FontWeight="Bold"
Click="menu_item_function"/>
<Separator/>
</Grid.ContextMenu>
Code Behind:
private void menu_item_function(object sender, RoutedEventArgs e)
{
// Get the viewmodel from the DataContext
MainWindowViewModel viewmodel = DataContext as MainWindowViewModel;
// Call command from viewmodel
if ((viewmodel != null) && (viewmodel.View_Model_Function.CanExecute(this)))
{
viewmodel.View_Model_Function.Execute(this);
}
}
Okay, this is probably something pretty simple that I'm not doing quite right. I am just now learning how to add items dynamically using an ItemsControl as shown below.
<ItemsControl ItemsSource="{Binding Buttons}">
<ItemsControl.Template>
<ControlTemplate>
<Button FontWeight="Bold" Command="{Binding SelectMaterialCommand}" CommandParameter="{Binding CommandParameter}" Width="50" Height="50" Style="{StaticResource RoundedButtonStyle}" Margin="0,0,0,0" Click="Button_Click_2" Content="{Binding .Content}"></Button>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
The ItemsControl ItemsSource Property is bound to an ObservableCollection of Buttons. In code I can create a button, set the Content and CommandParameter properties and add it to the ObservableCollection. When I run the application a button is populated, but I can't get the Content and CommandParameter properties to bind correctly.
I have tried doing several different methods such as Binding Path=., Binding Path=Content, Binding Path=.Content...etc, but nothing seems to be working. Any help would be appreciated.
Following Subramaniam B's advice I got this to work by utilizing a Data Template as shown that is located in my UserControl.Resources section.
<DataTemplate x:Key="temp" DataType="{x:Type local:ButtonModel}">
<telerik:RadButton FontWeight="Bold" FontSize="16" Command="{Binding ButtonCommand}" CommandParameter="{Binding Path=Content}" Width="100" Height="75" Margin="0,0,0,0" MouseLeftButtonUp="Button_Click_2" Content="{Binding Path=Content}">
<telerik:RadButton.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="GhostWhite" Offset="0"/>
<GradientStop Color="Gray" Offset="0.5"/>
<GradientStop Color="Gray" Offset="0.5"/>
<GradientStop Color="GhostWhite" Offset="1"/>
</LinearGradientBrush>
</telerik:RadButton.Background>
</telerik:RadButton>
</DataTemplate>
Here is where the template is used were used:
<telerik:RadCarousel Loaded="MaterialCar_Loaded" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" x:Name="MaterialCar" Height="200" Background="Blue" ItemTemplate="{StaticResource temp}" ItemsSource="{Binding Buttons}" Margin="0,0,0,0"/>
In your example you are setting the template for the whole ItemsControl (aka: LIST of buttons) to be A button.
No matter what items are in the Buttons collection, this control will render as a single button. Instead, you need to leave the template for the control itself alone, and use I template for the items that are IN the list.
<ItemsControl ItemsSource="{Binding Buttons}">
<!-- ItemsControl.Template becomes ItemsControl.ItemTemplate below -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button FontWeight="Bold" Command="{Binding SelectMaterialCommand}" CommandParameter="{Binding CommandParameter}" Width="50" Height="50" Style="{StaticResource RoundedButtonStyle}" Margin="0,0,0,0" Click="Button_Click_2" Content="{Binding .Content}"></Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have a a Grid/GridView that I have built in XAML. I have a list that is dynamically building the GridViewItems. I am trying to add elements to the GridViewItems that are being dynamically built. I have it going through a loop and building the GridViewItems fine, I just can't seem to grasp how to add the elements (TextBlocks, Symblos, etc.) to the GridViewItems. I will post what I have below:
XAML
<Grid Background="LightGray">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<controls:PageHeader BackButtonVisibility="Collapsed" Content="News" Frame="{x:Bind Frame}">
<Interactivity:Interaction.Behaviors>
<Behaviors:EllipsisBehavior Visibility="Auto" />
</Interactivity:Interaction.Behaviors>
<controls:PageHeader.SecondaryCommands>
<AppBarButton Click="{x:Bind ViewModel.GotoPrivacy}" Label="Privacy" />
<AppBarButton Click="{x:Bind ViewModel.GotoAbout}" Label="About" />
</controls:PageHeader.SecondaryCommands>
</controls:PageHeader>
<GridView x:Name="tileGridView" Margin="12,60">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="#2A2A2A"
Margin="5"
Height="200"
Width="300">
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</GridView.ItemContainerStyle>
</Grid>
C#
List<TextBlock> tList = new List<TextBlock>();
for (int j = 0; j < myList.Count; j++)
{
tList.Add(new TextBlock()
{
Text = myList[j].TitleView,
Foreground = new SolidColorBrush(Windows.UI.Colors.White)
});
tList.Add(new TextBlock()
{
Text = myList[j].BodyView,
Foreground = new SolidColorBrush(Windows.UI.Colors.White)
});
}
tileGridView.ItemsSource = myList;
I am unable to figure out a way to add the titleTextBlock to the GridViewItem. The GridViewItem is not being built until I set the itemssource to myList.
Can anyone guide me on how to add the textblock I have built to my GridViewItem?
UPDATE
I have added my update to where I am now... I have successfully built the textblock, but I have not been able to find a way to add the textblocks to a GridViewItem. My List returns 2 objects right now. That should build 2 GridViewItems, which it does, but inside of those 2 objects there are 4 pieces of information(Title, Body, Author, Date). I am trying to build 4 textblocks to place in each GridViewItem... Hope this explains better of what I am trying to accomplish.
I was able to figure the solution out... This is what I did, if anyone knows of a better way to do this, please feel free to counter my answer.
<DataTemplate x:Key="TileTemplate">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding TitleView}" FontFamily="Segoe UI" FontWeight="SemiBold" FontSize="18" Foreground="White" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10" />
<TextBlock Text="{Binding BodyView}" FontFamily="Segoe UI" FontWeight="Light" FontSize="14" Foreground="White" TextWrapping="Wrap" Margin="10,0" />
</StackPanel>
</DataTemplate>
<GridView x:Name="tileGridView" Margin="12,60" ItemTemplate="{StaticResource TileTemplate}">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView>
I then bind the data to the gridview:
tileGridView.ItemsSource = myList;