Binding a ControlTemplate's Button's Content and Command Parameter Property - c#

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>

Related

Itemscontrol Modify control template

I want to modify itemscontrol template to modify not how each item apears but the actual itemscontrol
<ItemsControl
ItemsSource="{Binding RB}" Grid.Row="1"
ItemTemplate="{StaticResource myBTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I have this and it's works fine, I get a stackpanel behaviour of items and my custom data template for each item but I can't find a way to modify the container. Let's say to put the title into my items list without doing so outside itemscontrol.
and if i do set ControlTemplate items no longer get displayed.
(This Itemscontrol is part of an upper level DataTemplate)
After Clemens comment i searched more on Items presenter rather that ControlTemplate.
Found i just needed to add items presenter somewhere in the ControlTemplate with no special tag just respecting tree format.
<ItemsControl
ItemsSource="{Binding RB}" Grid.Row="1"
ItemTemplate="{StaticResource myBTemplate}">
<ItemsControl.Template>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<StackPanel>
<Grid Margin="5" Height="50">
<Ellipse Stroke="DarkBlue" StrokeThickness="2">
<Ellipse.Fill>
<RadialGradientBrush Center="0.3,0.2" RadiusX="0.5" RadiusY="0.5">
<GradientStop Color="Azure" Offset="0.1" />
<GradientStop Color="CornflowerBlue" Offset="1.1" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
<StackPanel >
<ItemsPresenter Margin="2,0,0,0"/>
</StackPanel>
</StackPanel>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>

Can't access listbox data template item

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..

Creating collections of arbitrarily positioned controls in WPF

I have a simple Border and Grid that is positioned within a Canvas container in WPF. The position of the control changes during runtime hence why it resides in the canvas.
The XAML for the control looks something like this:
<Border Name="PopupArea"
Width="130"
Height="150"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="5">
<Border.Background>
<SolidColorBrush Opacity="0.5" Color="Black" />
</Border.Background>
<Grid>
<StackPanel>
<Border HorizontalAlignment="Center">
<Border.Effect>
<DropShadowEffect />
</Border.Effect>
<TextBlock FontWeight="Bold" Style="{StaticResource SmallWhiteFont}">HELLO WORLD</TextBlock>
</Border>
</StackPanel>
</Grid>
</Border>
However I now need to be able to create a Collection of the above control which I create and destory as required at runtime in code.
My questions are :
A. What is the best way to compose my XAML to create multiple instances of the above control through code? Do I just declare a ContentControl in the resources?
B. Assuming I am correct and a resource template is required. How do I actually use it to create multiple instances of the control in code?
Within XAML I would use an ItemTemplate.
Then I would bind ItemsSource to some observable collection on my viewmodel.
Here's an example taken from MSDN:
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}" />
<TextBlock Text="{Binding Path=Description}"/>
<TextBlock Text="{Binding Path=Priority}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
NOTE:
It is more common to define a DataTemplate in the resources section so it can be a reusable object.
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}"
ItemTemplate="{StaticResource myTaskTemplate}"/>

Can a DataTemplate be placed inside another DataTemplate of different Template Structure?

I want a DataTemplate for ListBox having the ItemsSource as Collection of Borders. Inside each Border i want to display another ListBox containg set of some items having its own ItemsSource.
But, when i try to acheive this structure i am not able to populate any data.
My XAML code -
<Grid x:Name="RightPanel" Grid.Column="2" Background="Beige">
<Border BorderBrush="Black" Margin="4" BorderThickness="1.5">
<ScrollViewer Margin="2" Focusable="False">
<ListBox x:Name="MainRightListBox" ItemsSource="{Binding ListBoxCollection,Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBox x:Name="ChildListBox" ItemsSource="{Binding CurrentPage.ClonedVectorImages,Mode=TwoWay}" SelectedItem="{Binding ImageVectorSelected}" BorderBrush="Transparent" Background="Transparent">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="canvas" Background="Transparent" Orientation="Horizontal" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" CommandParameter="{Binding}"
Command="{Binding PlacementTarget.Tag.DataContext.DeleteCloneCommand, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}, Mode=FindAncestor}}"/>
</ContextMenu>
</StackPanel.ContextMenu>
<Viewbox Width="35" Height="35" >
<Canvas Width="35" Height="35">
<Canvas>
<Path Fill="#ffda2526" Data="F1 M 0.000,112.500 C 0.000,50.369 50.368,0.000 112.500,0.000 C 174.632,0.000 225.000,50.369 225.000,112.500 C 225.000,174.633 174.632,225.000 112.500,225.000 C 50.368,225.000 0.000,174.633 0.000,112.500 Z" Height="30.667" Stretch="Fill" Width="31"/>
<TextBlock x:Name="tb1" Text="{Binding CountId}" Foreground="WhiteSmoke" FontSize="20" FontFamily="Arial Bold" Height="20" RenderTransformOrigin="1.588,1.224" Canvas.Left="9.322" Canvas.Top="3.335"></TextBlock>
</Canvas>
</Canvas>
</Viewbox>
<TextBox Text="Enter Text Here" Height="20" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Border>
</Grid>
"Can a DataTemplate be placed inside another DataTemplate of different Template Structure?"
The answer is yes, it can. Your XAML structure is fine.
But what possibly wrong is binding path/expression used. You need to be aware that DataContext of the inner ListBox (the one inside DataTemplate) is corresponding item in ListBoxCollection. So if that item mentioned before has property CurrentPage.ClonedVectorImages, this way of binding should work fine to populate the inner ListBox :
<ListBox x:Name="ChildListBox"
ItemsSource="{Binding CurrentPage.ClonedVectorImages,Mode=TwoWay}"
........>
You need to put DataTemplates in resources with the corresponding keys, because otherwise an exception may occur:
Markup.IStyle.Connector.Connect error
This is bug of studio, which is described as follows link:
A good way to look at this problem “Templating is like parentheses, quoting parentheses” the Template XAML is not created but saved and run later. The bug is therefore: We have a problem with nested parentheses.
In any case as I think, should be avoided nesting templates and use him via resources, it will be easier and clearer.

Changing border color when a control is selected with c# on windows 8 app store

I have a gridview control with images and text with this xaml:
<Grid Grid.Column="1" Margin="0,40,30,0" >
<GridView x:Name="celebGridView" Margin="0,0,0,0" Padding="0,0,0,0">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" MaximumRowsOrColumns="3"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.Header>
<StackPanel Width="480" Margin="0,4,14,0">
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="Most Viewed Celebs" Foreground="black" FontSize="25"/>
<Image Source="/images/Navigation-Right.png" Margin="10,0,0,0"/>
</StackPanel>
</StackPanel>
</GridView.Header>
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding ImageBitmap}" />
<TextBlock HorizontalAlignment="Center" Text="{Binding Name_}" Foreground="Black"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
and i get this purple border around the selected items in the gridview below
How can i override this behaviour, i need to change the color to a custom color (#fdeb01).
You could edit the ItemContainerStyle for the GridView. The easiest way is to use Blend and find the SelectedBorder element and change stroke brush to color you want.
Aside from using Expression Blend, note that Metro ListView selection color modification in XAML is also valid for GridViewItems so changing the following:
<SolidColorBrush x:Key="ListViewItemSelectedBackgroundThemeBrush" Color="#fdeb01"> </SolidColorBrush>
<SolidColorBrush x:Key="ListViewItemPointerOverBackgroundThemeBrush" Color="#ffffff"></SolidColorBrush>
<SolidColorBrush x:Key="ListViewItemSelectedPointerOverBackgroundThemeBrush" Color="#fdeb01"></SolidColorBrush>
<SolidColorBrush x:Key="ListViewItemSelectedPointerOverBorderThemeBrush" Color="#fdeb01"></SolidColorBrush>
will also affect the gridview.

Categories