Get control inside DataTemplate - c#

So I have a FlipView defined in xaml by the following code:
<FlipView x:Name="carrousel" Height="175" Background="Transparent" Margin="0,20,0,0">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid>
<Rectangle x:Name="profile" Stroke="White" StrokeThickness="0" HorizontalAlignment="Center" VerticalAlignment="Center" Width="175" Height="175" Canvas.ZIndex="1" RadiusX="88" RadiusY="88" Tapped="profile_Tapped"/>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
When a user clicks on the rectangle, it's animated to become bigger, but I also want all the other rectangles of every other FlipViewItem to change size too. How can I achieve this? I tried:
foreach(FlipViewItem fvi in carrousel.Items)
{
Rectangle g = (fvi.Content as Grid).FindName("profile") as Rectangle;
g.Width = double;
g.Height = double;
}
But seeing as my flipview doesn't contain FlipViewItems but custom classes I've binded to it (which obviously have no .Content), it doesn't work. How can I get this to work?

foreach(var fvi in carrousel.Items)
{
FlipViewItem item=carrousel.ContainerFromItem(fvi);
var rectangle =FindElementInVisualTree<Rectangle>(item);
//Or without VisualTreeHelper you can do like what were you trying before
Rectangle g = (item.Content as Grid).FindName("profile") as Rectangle;
g.Width = double;
g.Height = double;
}
private T FindElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0) return null;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T)
return (T)child;
else
{
var result = FindElementInVisualTree<T>(child);
if (result != null)
return result;
}
}
return null;
}

This solution is a turn around solution (because I could not manage the relative binding).
<Grid Background="{ThemeResource SystemControlBackgroundListMediumBrush}">
<StackPanel Margin="100,10,10,10">
<FlipView x:Name="carrousel" Height="350" Width="350" Background="Red" Margin="0,20,0,0">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid>
<Rectangle x:Name="profile" Stroke="White" StrokeThickness="1" Fill="Aqua"
HorizontalAlignment="Center" VerticalAlignment="Center"
Width="{Binding ElementName=RefValueRect, Path=Width, Mode=OneWay}"
Height="{Binding ElementName=RefValueRect, Path=Height, Mode=OneWay}" Canvas.ZIndex="1" RadiusX="88"
RadiusY="88" Tapped="profile_Tapped"/>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</StackPanel>
<Rectangle x:Name="RefValueRect" Width="175" Height="175" Visibility="Collapsed" />
</Grid>
code behind
private void profile_Tapped(object sender, TappedRoutedEventArgs e)
{
RefValueRect.Width *= 2;
RefValueRect.Height *= 2;
}

Related

Access control inside hub control windows 8.1

I have this code:
<HubSection x:Name="MyHub">
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="200"></RowDefinition>
</Grid.RowDefinitions>
<Image x:Name="MYImage" Source="{Binding image}" Height="50" Width="60" VerticalAlignment="Center"/>
<StackPanel Orientation="Vertical">
<TextBlock TextWrapping="Wrap" Width="200" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Binding name}"/>
<Button Content="Click me">
</StackPanel>
</Grid>
</DataTemplate>
</HubSection>
But I do not know how to access the text-block, I want to change the foreground color of the text-block in code behind.
XAML:
<Hub x:Name="myHub">
<HubSection x:Name="myHubSection">
<DataTemplate>
<TextBlock x:Name="textbox1" Text="text" Width="300" Height="100">
</TextBlock>
</DataTemplate>
</HubSection>
</Hub>
Code behind:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
var hub_section = FindVisualChildByName<HubSection>(this.myHub, "myHubSection");
var text_box = FindVisualChildByName<WebView>(hub_section, "textbox1");
}
public static T FindVisualChildByName<T>(DependencyObject parent, string name)where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
string controlName = child.GetValue(Control.NameProperty) as string;
if (controlName == name)
{
return child as T;
}
else
{
T result = FindVisualChildByName<T>(child, name);
if (result != null)
return result;
}
}
return null;
}
More detailed information you could refer to How to access a Control inside the data template in C# Metro UI in the code behind

Access controls inside listbox c# (windows Phone 8)

my xaml code..
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="DataTemplate1" >
<Border BorderBrush="LightGray" BorderThickness="1" Height="150" Width="500" >
<Grid Width="500" Height="150" Background="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.9*"/>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="1.5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Name="imgitem" Grid.Column="0" Height="Auto" Width="Auto" Source="{Binding ImgSource}" Margin="0,5,4,4" HorizontalAlignment="Left" />
<TextBlock x:Name="txtbindprice" Text="{Binding _PRICE,ConverterCulture=en-IN,StringFormat=C}" TextWrapping="Wrap" Grid.Column="1" Width="350" Foreground="Black" Height="60" Margin="40,70,20,-10"/>
<TextBlock x:Name="txtFinalTotal" Text="{Binding _FinalTotal}" TextWrapping="Wrap" Grid.Column="1" Width="350" Foreground="Red" Height="60" Margin="40,115,20,-10"/>
<TextBlock x:Name="txtITMNAME" Text="{Binding _ITMNAME }" Padding="1" Tap="ItmName_Tapped" TextDecorations="Underline" FontSize="24" TextWrapping="Wrap" Grid.Column="1" FontWeight="Normal" TextTrimming="WordEllipsis" Foreground="OrangeRed" Width="Auto" Height="150" Margin="30,25,10,-10"/>
<CheckBox Grid.Column="2" Grid.Row="0" Background="Black" Foreground="Black" BorderThickness="4" BorderBrush="Red" Margin="10,20,-15,10" Checked="CheckBox_Checked" Unchecked="CheckBox_UnChecked" />
</Grid>
</Border>
</DataTemplate>
<ListBox Height="Auto" Name="lstbxmanual" SelectionMode="Extended" ItemTemplate="{StaticResource DataTemplate1 }" Width="475" Margin="2,192,0,-39" Background="White" HorizontalAlignment="Left" Grid.RowSpan="2">
</ListBox>
I want to access textblocks inside listbox based on selected index
accessing textblock
string a =txtbindprice.text
wont work as they are inside data template of listbox..
I came across visual child tree methods and some other examples..i cant find much info..
please help me regarding this...
The following method finds currently selected list-box item:
private ListBoxItem FindSelectedListBoxItem(DependencyObject control)
{
int childNumber = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < childNumber; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(control, i);
FrameworkElement fe = child as FrameworkElement;
// Not a framework element or is null
if (fe == null) return null;
if (child is ListBoxItem && ((ListBoxItem)child).IsSelected)
{
// Found the control so return
return (ListBoxItem)child;
}
else
{
// Not found it - search children
ListBoxItem nextLevel = FindSelectedListBoxItem(child);
if (nextLevel != null)
return nextLevel;
}
}
return null;
}
Below method finds any child control with a certain name from a given root control:
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);
FrameworkElement 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;
}
else
{
// Not found it - search children
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
}
return null;
}
Now you can use the first method to get currently selected ListBoxItemand then pass it to the second method to retrieve any control inside this ListBoxItem (e.g. txtbindprice):
ListBoxItem item = FindSelectedListBoxItem(this);
TextBlock txtPrice = FindChildControl<TextBlock>(item , "txtbindprice") as TextBlock;
string a = txtPrice.Text;
Update
You can add SelectionChanged event to your ListBox like this:
<ListBox Height="Auto" Name="lstbxmanual" SelectionChanged="OnSelectionChanged">
</ListBox>
And then retrieve a certain TextBlock.Text (e.g. txtbindprice) this way:
public void OnSelectionChanged(object sender, SelectionChangedEventArgs args)
{
ListBoxItem item = FindSelectedListBoxItem((ListBox(sender)));
TextBlock txtPrice = FindChildControl<TextBlock>(item , "txtbindprice") as TextBlock;
string a = txtPrice.Text;
}

Cant Find Control Windows Phone 8.1 UAP

I am trying to find a control under my xaml in the hub control of windows phone 8.1. It may be the case my method works fine on desktop as I have testest it in wpf before but I am porting it to windows phone and may not work the same.
<Grid>
<Hub Header="Lists" Name="mainHub" >
<HubSection MinWidth="600" Name="lattestLists" Header="New Lists">
<DataTemplate>
<Grid>
<ListBox Background="Transparent" Margin="6" Height="auto" BorderThickness="2" MaxHeight="580" Grid.Row="1" x:Name="listBoxobj" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="350" >
<Border Margin="5" BorderBrush="White" BorderThickness="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Margin="5,0,0,0" Grid.Row="0" x:Name="NameTxt" TextWrapping="Wrap" Text="{Binding Name}" FontSize="28" Foreground="White"/>
<TextBlock Grid.Row="0" Text=">" FontSize="28" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="White"/>
<TextBlock Margin="5,0,0,0" Grid.Row="1" x:Name="PhoneTxt" TextWrapping="Wrap" Foreground="White" FontSize="18" Text="{Binding PhoneNumber}" />
<TextBlock HorizontalAlignment="Right" Margin="0,0,35,0" Grid.Row="3" x:Name="CreateddateTxt" Foreground="White" FontSize="18" TextWrapping="Wrap" Text="{Binding CreationDate}" />
</Grid>
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</HubSection>
<HubSection Header="Tech" IsHeaderInteractive="True"
Background="#222222" MinWidth="250">
<DataTemplate>
<StackPanel>
<TextBlock Text="Tech news goes here."
Style="{ThemeResource BodyTextBlockStyle}" />
<TextBlock Text="Click the header to go to the Tech page."
Style="{ThemeResource BodyTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</HubSection>
<HubSection Header="Sports" IsHeaderInteractive="True"
Background="#444444" MinWidth="250">
<DataTemplate>
<StackPanel>
<TextBlock Text="Sports news goes here."
Style="{ThemeResource BodyTextBlockStyle}" />
<TextBlock Text="Click the header to go to the Sports page."
Style="{ThemeResource BodyTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</HubSection>
</Hub>
</Grid>
I am trying to use the following method to find the lsitbox but its not working
ListBox listBoxobjc = FindChildControl<ListBox>(this, "listBoxobj") as ListBox;
listBoxobjc.ItemsSource = DB_ContactList.OrderByDescending(i => i.id).ToList();//Binding DB data to LISTBOX and Latest contact ID can Display first.
This is the method FindChildControl
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);
FrameworkElement 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;
}
else
{
// Not found it - search children
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
}
return null;
}
Edit
I debuged the code and its showing the control as null even though I have done the same way as i would
I have replace my method to find children a couple of times during the different versions of Windows Phone / Windows Runtime with this one being the most reliable. Just in case you're not able to spot the mistake you could also try this one and see if it yields better results:
public T FindElementByName<T>(DependencyObject element, string sChildName) where T : FrameworkElement
{
T childElement = null;
var nChildCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < nChildCount; i++)
{
FrameworkElement child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;
if (child == null)
continue;
if (child is T && child.Name.Equals(sChildName))
{
childElement = (T)child;
break;
}
childElement = FindElementByName<T>(child, sChildName);
if (childElement != null)
break;
}
return childElement;
}
Also when using this method shortly after creating / loading content I call UpdateLayout beforehand:
this.UpdateLayout();
But be careful - this is not one of the performance-friendliest methods (see also: https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.uielement.updatelayout).

A Simple Photo Album with Pinch and Zoom using FlipView

I'm trying to create a simple photo album (Windows Store App) using Flip View.
I have the Image element embedded within a ScrollViewer. I'm able to browse through the photos, but I'm looking to do the following things.
The image should fill the height of the screen uniformly [when the image is not zoomed]. I get vertical scrollbars for few items. I dont have this problem when the height of all the images are the same.
When I change the orientation of the screen, a part of the image is clipped on the right side.
The scrollviewer should forget the zoom level (reset zoom factor to 1) when I move between pages.
This is the code I have right now. What Am I doing wrong? And what should I add in my EventHandler to reset my ScrollViewer's zoom factor.
<FlipView
Name="MainFlipView"
Margin="0"
Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
Background="Black">
<FlipView.ItemTemplate>
<DataTemplate>
<ScrollViewer Name="myScrollViewer" ZoomMode="Enabled"
Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
MinZoomFactor="0.5"
MaxZoomFactor="2.5"
Margin="0" >
<Image Source="{Binding Path=Image}"
Name="MainImage" Stretch="Uniform" />
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
What user2199147 said should solve your first bullet point, the other two I had to fix programmatically, though it should be noted that I also had to use the VisualTreeHelper class which you'll have to import, and an extension method to help me use the helper class.
First of all, I had to a method from the VisualTreeHelper extension, which finds the first element in the FlipView that is of any type:
private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
if (parentElement != null)
{
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0)
return null;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T)
return (T)child;
else
{
var result = FindFirstElementInVisualTree<T>(child);
if (result != null)
{
return result;
}
}
}
}
return null;
}
For going into portrait mode, I added a callback handler for WindowSizeChanged, and simply reset all the ScrollViewers in the flip view back to their default
private void WindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
//Reset scroll view size
int count = MainFlipView.Items.Count;
for(int i = 0; i < count; i++)
{
var flipViewItem = MainFlipView.ItemContainerGenerator.ContainerFromIndex((i));
var scrollViewItem = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
if (scrollViewItem is ScrollViewer)
{
ScrollViewer scroll = (ScrollViewer)scrollViewItem;
scroll.Height = e.Size.Height; //Reset width and height to match the new size
scroll.Width = e.Size.Width;
scroll.ZoomToFactor(1.0f);//Zoom to default factor
}
}
}
And then in your constructor you need Window.Current.SizeChanged += WindowSizeChanged; in order for the callback to ever be called.
Now, for setting each ScrollViewer back to their default positions, we do a similar process, only whenever the FlipView selection is changed, we reset the ScrollViewer back to its default zoom factor
private void FlipViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is FlipView)
{
FlipView item = (FlipView)sender;
var flipViewItem = ((FlipView)sender).ItemContainerGenerator.ContainerFromIndex(((FlipView)sender).SelectedIndex);
var scrollViewItem = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
if (scrollViewItem is ScrollViewer)
{
ScrollViewer scroll = (ScrollViewer)scrollViewItem;
scroll.ScrollToHorizontalOffset(0);
scroll.ScrollToVerticalOffset(0);
scroll.ZoomToFactor(1.0f);
}
}
}
And again, we have to have a call in the constructor that looks like MainFlipView.SelectionChanged += FlipViewSelectionChanged;
I know these methods seem really hackish and roundabout, because they are, but it's what worked for me, and I hope this helps.
try changing the height and width bindings from the scrollviewer to the image.
<FlipView
Name="MainFlipView"
Margin="0"
Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
Background="Black">
<FlipView.ItemTemplate>
<DataTemplate>
<ScrollViewer Name="myScrollViewer" ZoomMode="Enabled"
HorizontalAlignment="Center"
VerticalAlignment="Center"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
MinZoomFactor="0.5"
MaxZoomFactor="2.5"
Margin="0" >
<Image Source="{Binding Path=Image}"
Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
Name="MainImage" Stretch="Uniform" />
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
Good practice for WinRT is:
1) Make Attached Property for ScrollViewer, which will change ZoomFactor
public class ScrollViewerExtension : DependencyObject
{
public static readonly DependencyProperty ScrollViewerZoomFactorProperty = DependencyProperty.RegisterAttached(
"ScrollViewerZoomFactor", typeof(double), typeof(ScrollViewerExtension), new PropertyMetadata(default(double), OnZoomFactorChanged));
public static void SetScrollViewerZoomFactor(DependencyObject element, double value)
{
element.SetValue(ScrollViewerZoomFactorProperty, value);
}
public static double GetScrollViewerZoomFactor(DependencyObject element)
{
return (double)element.GetValue(ScrollViewerZoomFactorProperty);
}
private static void OnZoomFactorChanged(DependencyObject depObject, DependencyPropertyChangedEventArgs args)
{
if (depObject is ScrollViewer)
{
var scrollViewer = (ScrollViewer)depObject;
var zoomValue = (double)args.NewValue;
if (!Double.IsNaN(zoomValue))
scrollViewer.ZoomToFactor((float)zoomValue);
}
else
{
throw new Exception("ARE YOU KIDDING ME ? ITS NOT SCROLLVIEWER");
}
}
}
2) Changer FlipViewItem Template
<Style TargetType="FlipViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Width="1040">
<ScrollViewer HorizontalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
MaxZoomFactor="4"
MinZoomFactor="1"
Tag="{Binding IsSelected}"
VerticalScrollBarVisibility="Auto"
VerticalScrollMode="Auto"
ZoomMode="Enabled"
extension:ScrollViewerExtension.ScrollViewerZoomFactor="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Converter={StaticResource IsSelectedToZoom}}">
<ContentPresenter />
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
3) Create converter, which will change ScrollViewerZoomFactor to default value if item isnt selected.
public class IsSelectedToZoomConverter :DependencyObject, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var val = (bool) value;
return val ? Double.NaN : 1.0;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
4) FlipView code will look like this:
<FlipView x:Name="FlipView"
Grid.Row="5"
Width="1040"
MinHeight="392"
MaxHeight="600"
ItemsSource="{Binding Path=CurrentSession.Photos}"
Visibility="{Binding CurrentSession.HasContent,
Converter={StaticResource BoolToVisibility}}">
<FlipView.ItemContainerStyle>
<Style TargetType="FlipViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Width="1040">
<ScrollViewer HorizontalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
MaxZoomFactor="4"
MinZoomFactor="1"
Tag="{Binding IsSelected}"
VerticalScrollBarVisibility="Auto"
VerticalScrollMode="Auto"
ZoomMode="Enabled"
extension:ScrollViewerExtension.ScrollViewerZoomFactor="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=IsSelected,
Converter={StaticResource IsSelectedToZoom}}">
<ContentPresenter />
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</FlipView.ItemContainerStyle>
<FlipView.ItemTemplate>
<DataTemplate>
<Image HorizontalAlignment="Stretch" Source="{Binding Path=Path}" />
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
why do you have a ScrollViewer within you FlipViewItemTemplate?
Thie template will be used for each Item, so for each Image you add to your ItemList.
that said it shoud be enough to have the Image element within your Template.
this should at least avoid the scrollbars for images that are bigger than your screen, cause then the Stretch="Uniform" should handle the resizing...

On item selection, changing the color of a rectangle which is part of a ListBoxItem in Windows Phone

I have a ListBox with the following XAML:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Name="listItemGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="20" MinWidth="20" Width="20" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Name="listItemSideBar" Height="85" HorizontalAlignment="Left"
Margin="0, 0, 0, 0" Stroke="{StaticResource PhoneAccentBrush}"
StrokeThickness="1" VerticalAlignment="Top" Fill="{StaticResource
PhoneAccentBrush}" MinHeight="85" Width="25"/>
<StackPanel Margin="0,0,0,17" Grid.Column="1" Grid.ColumnSpan="2">
<TextBlock Name="listItemMainData" Text="{Binding LineTwo}"
TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource
PhoneTextExtraLargeStyle}"/>
<TextBlock Name="listItemSubData" Text="{Binding LineOne}"
TextWrapping="NoWrap" Margin="12,-6,0,0"
Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
When a ListBoxItem is selected I would like to change that ListBoxItem's Rectangle fill color to a different color; when the ListBoxItem is deselected I would like the fill color to change back to PhoneAccentBrush.
Is there a way to accomplish this task?
I finally worked out a solution which I have copied below. The ColorHelper class simply gets the PhoneAccentColor from the PhoneAccentBrush resource. The DarkPhoneAccentColor is produced via the method found here. PropertyValue<string>(child, "Name") is a syntactic sugar extension method to get a value from a property of a type; it returns default(T) if the property does not exist.
Full error checking has not yet been applied to this code.
private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Color accent = ColorHelper.PhoneAccentColor;
Color accentDark = ColorHelper.DarkPhoneAccentColor;
foreach (object item in e.RemovedItems)
SetListBoxItemColor(item, accentDark);
foreach (object item in e.AddedItems)
SetListBoxItemColor(item, accent);
}
private void SetListBoxItemColor(object item, Color color)
{
ListBoxItem listBoxItem = listBox.ItemContainerGenerator
.ContainerFromItem(item) as ListBoxItem;
if (listBoxItem != null)
{
Rectangle rectangle = GetItemsRecursive<Rectangle>(
listBoxItem, "listItemSideBar");
SolidColorBrush fillBrush = new SolidColorBrush();
fillBrush.Color = color;
rectangle.Fill = fillBrush;
}
}
private T GetItemsRecursive<T>(DependencyObject lb, string name)
where T : DependencyObject
{
int childrenCount = VisualTreeHelper.GetChildrenCount(lb);
for (int i = 0; i < childrenCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(lb, i);
if (child is T)
{
string childName = child.GetType().PropertyValue<string>(child, "Name");
if (String.Compare(childName, name) == 0)
return (T)child;
}
return GetItemsRecursive<T>(child, name);
}
return default(T);
}

Categories