Can't get VisualStateGroup.Transitions to work in templated control - user-controls

I am creating a templated control. The idea is to create an expanding control. It will have a Header and a Details property each corresponding to a ContentPresenter. The user will be able to tap on the Header and the Details section will expand with an animation. When the user taps the header again the Details section will retract with another animation.
I am using Visual States and VisualTransitions to achieve that. Here is my code.
[TemplatePart(Name ="Header", Type=typeof(ContentPresenter))]
[TemplatePart(Name = "Details", Type = typeof(ContentPresenter))]
[TemplateVisualState(GroupName ="ExpandStates",Name ="Expanded")]
[TemplateVisualState(GroupName = "ExpandStates", Name = "Compact")]
public sealed class ExpandingItem : Control
{
private ContentPresenter header;
private bool isExpanded;
public ExpandingItem()
{
this.DefaultStyleKey = typeof(ExpandingItem);
}
public FrameworkElement Header
{
get { return (FrameworkElement)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(FrameworkElement), typeof(ExpandingItem), new PropertyMetadata(default(FrameworkElement)));
public FrameworkElement Details
{
get { return (FrameworkElement)GetValue(DetailsProperty); }
set { SetValue(DetailsProperty, value); }
}
// Using a DependencyProperty as the backing store for Details. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DetailsProperty =
DependencyProperty.Register("Details", typeof(FrameworkElement), typeof(ExpandingItem), new PropertyMetadata(default(FrameworkElement)));
protected override void OnApplyTemplate()
{
if (header != null)
{
header.Tapped -= HeaderTapped;
}
base.OnApplyTemplate();
header = (ContentPresenter)GetTemplateChild("Header");
header.Tapped += HeaderTapped;
}
private void HeaderTapped(object sender, TappedRoutedEventArgs e)
{
if (isExpanded)
{
Retract();
OnStateChanged(new ExpandItemEventArgs(false));
}
else
{
Expand();
OnStateChanged(new ExpandItemEventArgs(true));
}
isExpanded = !isExpanded;
}
public void Expand()
{
VisualStateManager.GoToState(this, "Expanded", true);
}
public void Retract()
{
VisualStateManager.GoToState(this, "Compact", true);
}
public EventHandler<ExpandItemEventArgs> StateChanged;
private void OnStateChanged(ExpandItemEventArgs e)
{
// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler<ExpandItemEventArgs> handler = StateChanged;
// Event will be null if there are no subscribers
if (handler != null)
{
handler(this, e);
}
}
}
And the template
<Style TargetType="controls:ExpandingItem" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ExpandingItem">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ExpandStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Compact" To="Expanded">
<VisualTransition.Storyboard>
<Storyboard>
<FadeInThemeAnimation
TargetName="Details"/>
</Storyboard>
</VisualTransition.Storyboard>
</VisualTransition>
<VisualTransition From="Expanded" To="Compact">
<VisualTransition.Storyboard>
<Storyboard>
<FadeOutThemeAnimation
TargetName="Details"/>
</Storyboard>
</VisualTransition.Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Compact"/>
<VisualState x:Name="Expanded">
<VisualState.Setters>
<Setter Target="Details.Visibility" Value="Visible"/>
</VisualState.Setters>
<Storyboard>
<FadeInThemeAnimation
TargetName="Details"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter
x:Name="Header"
Grid.Row="0"
Content="{TemplateBinding Header}"/>
<ContentPresenter
x:Name="Details"
Grid.Row="1"
Content="{TemplateBinding Details}"
Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am using the fadein/fadeout animation as it is a simple animation but ideally I would like to use something like the splitopen/splitclose animation.
The problem is that even though the transition between the states happens normally. The animations never occur. Can you help me identify the problem?
Edit: Here is the code for the ExpandItemEventArgs
public class ExpandItemEventArgs : EventArgs
{
private readonly bool isExpanded;
public ExpandItemEventArgs(bool isExpanded)
{
this.isExpanded = isExpanded;
}
public bool IsExpanded => isExpanded;
}

The problem is that even though the transition between the states happens normally. The animations never occur. Can you help me identify the problem?
This is because your VisualTransition From="Compact" To="Expanded", at first you didn't make your control enter the VisualState named Compact. And when you <VisualTransition From="Expanded" To="Compact">, since you didn't set the Visibility property for your Details, it will erase the last VisualState and go back to Collapsed state directly, the animation won't be shown.
Here I modified your code, and in order to make the animation of fade in and out more obviously, I changed the animations also:
<Style TargetType="local:ExpandingItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ExpandingItem">
<Grid Name="RootGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ExpandStates">
<VisualStateGroup.Transitions>
<VisualTransition To="Expanded" GeneratedDuration="0:0:3">
<Storyboard x:Name="FadeIn">
<DoubleAnimation From="0.1" To="1" Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="Details" Duration="0:0:3">
<DoubleAnimation.EasingFunction>
<CubicEase />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualTransition>
<VisualTransition From="Expanded" To="Compact" GeneratedDuration="0:0:2.5">
<VisualTransition.Storyboard>
<Storyboard x:Name="FadeOut">
<DoubleAnimation From="1" To="0.1" Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="Details" Duration="0:0:3">
<DoubleAnimation.EasingFunction>
<CubicEase />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualTransition.Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Target="Details.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Compact">
<VisualState.Setters>
<Setter Target="Details.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Expanded">
<VisualState.Setters>
<Setter Target="Details.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter
x:Name="Header"
Grid.Row="0"
Content="{TemplateBinding Header}" />
<ContentPresenter
x:Name="Details"
Grid.Row="1"
Content="{TemplateBinding Details}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Code I modified in behind:
protected override void OnApplyTemplate()
{
if (header != null)
{
header.Tapped -= HeaderTapped;
}
base.OnApplyTemplate();
VisualStateManager.GoToState(this, "Compact", true); //Go to compact state at first
header = (ContentPresenter)GetTemplateChild("Header");
header.Tapped += HeaderTapped;
}
public void Expand()
{
VisualStateManager.GoToState(this, "Normal", true); //Go to Normal state firstly when it expanded, in order to make it visible.
VisualStateManager.GoToState(this, "Expanded", true);
}
Rendering Image:

Related

UWP - How to format time in TimePicker_TimeChanged AND Select Time without Buttons inside in TimepickerFlyout

I am developing UWP App (Win10 VS2015). I have two problems.
1- How can I get the time in this format (4:00 PM or 9:34 AM etc..) in 12hours format, I can get the value without PM/AM via this TimePicker.Time = sender.Time.ToString(#"hh\:mm"), but I need the actual format as I mentioned.
XAML Code
<TimePicker ClockIdentifier="12HourClock" TimeChanged="TimePicker_TimeChanged" Style="{StaticResource TimePickerStyleCustom}"/>
.cs Code
private void TimePicker_TimeChanged(object sender, TimePickerValueChangedEventArgs e)
{
timeTitle.Text = (sender as TimePicker).Time.ToString(#"hh\:mm");
}
Via the above code, I can get the value without AM/PM and also it is in 24hour format i.e. 4:00PM is in 16:00, but I need it in 4:00PM or 4:00AM (this is just an example). If I put .ToString(#"hh\:mm tt"); it throws exception. How to get this please.
2- 2nd problem is, When we tap on the Timepicker, a TimePickerFlyout expands and we select time by clicking on hours/minutes and when finalize then click on the (Tick) Mark to select Time ... but I need to remove these buttons (Done (_/) & Cancel (X)) and select time by selecting the Hour/Min in Flyout panel rather than button click and assign it to a string. I can remove the buttons from TimePickerFlyoutPresenter Style but then how to make the Selection functional like button click.
See the screenshot, in first portion the 2 buttons are available and it worked, but I need the 2nd portion as shown in the right side.
For First problem
TimeSpan represents a time interval not a time of day. You have to convert it to DateTime then format it
private void TestTimePicker_TimeChanged(object sender, TimePickerValueChangedEventArgs e)
{
string Text = (sender as TimePicker).Time.ToString(#"hh\:mm");
var dateTime = new DateTime((sender as TimePicker).Time.Ticks); // Date part is 01-01-0001
var formattedTime = dateTime.ToString("h:mm tt", CultureInfo.InvariantCulture);
}
Problem 2
For this either you have to implement your own TimerPickerFlyout from PickerFlyoutBase or from Flyout. It is bit complicated and I havent worked on that. You can watch this link for that
There is a easy workaround . As you mentioned in question you have to edit TimePickerFlyoutPresenter style.
I tried adding Tapped event handler to FirstPickerHost,SecondPickerHost,ThirdPickerHost.But you cant add event handlers in app.xaml. So i used Behavioural SDK's interactions. If you have Template10 used in your project you dont have to download anything just add following namespaces in app.xaml
xmlns:interact="using:Microsoft.Xaml.Interactivity"
xmlns:interactcore="using:Microsoft.Xaml.Interactions.Core"
<Style TargetType="TimePickerFlyoutPresenter">
<Setter Property="Width" Value="242" />
<Setter Property="MinWidth" Value="242" />
<Setter Property="MaxHeight" Value="396" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
<Setter Property="AutomationProperties.AutomationId" Value="TimePickerFlyoutPresenter" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource DateTimeFlyoutBorderThickness}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TimePickerFlyoutPresenter">
<Border x:Name="Background"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
MaxHeight="396">
<Grid x:Name="ContentPanel">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" x:Name="FirstPickerHostColumn" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" x:Name="SecondPickerHostColumn" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" x:Name="ThirdPickerHostColumn" />
</Grid.ColumnDefinitions>
<Rectangle x:Name="HighlightRect" Fill="{ThemeResource SystemControlHighlightListAccentLowBrush}" Grid.Column="0" Grid.ColumnSpan="5" VerticalAlignment="Center" Height="44" >
</Rectangle>
<Border x:Name="FirstPickerHost" Grid.Column="0" >
<interact:Interaction.Behaviors>
<interactcore:EventTriggerBehavior EventName="Tapped">
<interactcore:InvokeCommandAction Command="{Binding ClosePopUp}"/>
</interactcore:EventTriggerBehavior>
</interact:Interaction.Behaviors>
</Border>
<Rectangle x:Name="FirstPickerSpacing" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" HorizontalAlignment="Center" Width="2" Grid.Column="1" >
</Rectangle>
<Border x:Name="SecondPickerHost" Grid.Column="2" >
<interact:Interaction.Behaviors>
<interactcore:EventTriggerBehavior EventName="Tapped">
<interactcore:InvokeCommandAction Command="{Binding ClosePopUp}"/>
</interactcore:EventTriggerBehavior>
</interact:Interaction.Behaviors>
</Border>
<Rectangle x:Name="SecondPickerSpacing" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" HorizontalAlignment="Center" Width="2" Grid.Column="3" >
</Rectangle>
<Border x:Name="ThirdPickerHost" Grid.Column="4" >
<interact:Interaction.Behaviors>
<interactcore:EventTriggerBehavior EventName="Tapped">
<interactcore:InvokeCommandAction Command="{Binding ClosePopUp}"/>
</interactcore:EventTriggerBehavior>
</interact:Interaction.Behaviors>
</Border>
</Grid>
<Grid Grid.Row="1" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Height="2" VerticalAlignment="Top" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" Grid.ColumnSpan="2" />
<Button x:Name="AcceptButton" Grid.Column="0" Content="" FontFamily="{ThemeResource SymbolThemeFontFamily}" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Style="{StaticResource DateTimePickerFlyoutButtonStyle}" Margin="0,2,0,0" />
<Button x:Name="DismissButton" Grid.Column="1" Content="" FontFamily="{ThemeResource SymbolThemeFontFamily}" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Style="{StaticResource DateTimePickerFlyoutButtonStyle}" Margin="0,2,0,0" />
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And you have to set datacontext of Timepicker to your viewmodel.
<TimePicker x:Name="TestTimePicker" Time="{Binding SelectedTime,Mode=TwoWay}" ClockIdentifier="12HourClock" Time="0" TimeChanged="TestTimePicker_TimeChanged" >
</TimePicker>
public MainPage()
{
this.InitializeComponent();
DataContext = new TestViewModel();
TestTimePicker.DataContext = this.DataContext;
}
public class TestViewModel:INotifyPropertyChanged
{
public DelegateCommand<TappedRoutedEventArgs> ClosePopUp { get; set; }
TimeSpan selectedTime;
public TimeSpan SelectedTime
{ get { return selectedTime; }
set
{
if (value != selectedTime)
{
selectedTime = value;
OnPropertyChanged("SelectedTime");
}
}
}
public TestViewModel()
{
ClosePopUp = new DelegateCommand<TappedRoutedEventArgs>((args) =>
{
if (args.OriginalSource is Grid)
{
Grid grid = args.OriginalSource as Grid;
if (grid != null)
{
var fly = FlyoutBase.GetAttachedFlyout(grid);
var flyoutpresenter = FindParent<TimePickerFlyoutPresenter>(grid);
if (flyoutpresenter != null)
(flyoutpresenter.Parent as Popup).IsOpen = false;
var firstPicker= FindParent(grid,"FirstPickerHost");
var secondPicker = FindParent(grid, "SecondPickerHost");
var thirdPicker = FindParent(grid, "ThirdPickerHost");
var textblock = FindElementInVisualTree<TextBlock>(grid);
if (firstPicker != null)
{
SelectedTime = new TimeSpan(int.Parse(textblock.Text), SelectedTime.Minutes, SelectedTime.Seconds);
}
if(secondPicker!=null)
{
SelectedTime = new TimeSpan(SelectedTime.Hours, int.Parse(textblock.Text), SelectedTime.Seconds);
}
if (thirdPicker != null)
{
// AM/PM
}
}
}
else if(args.OriginalSource is TextBlock)
{
TextBlock textblock = args.OriginalSource as TextBlock;
if (textblock != null)
{
var fly = FlyoutBase.GetAttachedFlyout(textblock);
var flyoutpresenter = FindParent<TimePickerFlyoutPresenter>(textblock);
if (flyoutpresenter != null)
(flyoutpresenter.Parent as Popup).IsOpen = false;
var firstPicker = FindParent(textblock, "FirstPickerHost");
var secondPicker = FindParent(textblock, "SecondPickerHost");
var thirdPicker = FindParent(textblock, "ThirdPickerHost");
if (firstPicker != null)
{
SelectedTime = new TimeSpan(int.Parse(textblock.Text), SelectedTime.Minutes, SelectedTime.Seconds);
}
if (secondPicker != null)
{
SelectedTime = new TimeSpan(SelectedTime.Hours, int.Parse(textblock.Text), SelectedTime.Seconds);
}
if (thirdPicker != null)
{
// AM/PM
}
}
}
else
{
}
});
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
// the new Null-conditional Operators are thread-safe:
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private T FindParent<T>(DependencyObject child) where T : DependencyObject
{
var parent = VisualTreeHelper.GetParent(child);
if (parent != null && parent is T)
return (T)parent;
else if (parent == null)
return null;
else
{
var result = FindParent<T>(parent);
if (result != null)
return result;
}
return null;
}
private DependencyObject FindParent(DependencyObject child,string parentName)
{
var parent = VisualTreeHelper.GetParent(child);
if (parent != null && (parent as FrameworkElement).Name.Equals(parentName))
return parent;
else if (parent == null)
return null;
else
{
var result = FindParent(parent,parentName);
if (result != null)
return result;
}
return null;
}
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;
}
}
What i'm doing above in ClosePopUp command is programmatically finding TimePickerFlyoutPresenter using VisualTreeHelper getparaent() method
TimePickerFlyoutPresenter parent is a PopUp that is actually your TimePickerFlyout. Set popup's IsOpen to false
// Updated the code to reflect selected hour and minute in timepicker. One issue left is update the selected AM or PM. I ll update if i get the solution
Here is a link to complete project which solves all issues
Source Code

Change Scrollbar color LongListSelector - WP8

Does anyone know how to change the color of LongListSelector's Scrollbar. I've tried to change the Foreground on ControlTemplate but no success.
The visible part of the ScrollBar in the LongListSelectors template is actually the background.
So, to set the scrollbar to be Fuschia.
Set the background of the scrollbar in the template like this:
<Style x:Key="LongListSelectorStyle1" TargetType="phone:LongListSelector">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="phone:LongListSelector">
<Grid Background="{TemplateBinding Background}" d:DesignWidth="480" d:DesignHeight="800">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ScrollStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="00:00:00.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Scrolling">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VerticalScrollBar"/>
</Storyboard>
</VisualState>
<VisualState x:Name="NotScrolling"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<ViewportControl x:Name="ViewportControl" HorizontalContentAlignment="Stretch" VerticalAlignment="Top" />
<ScrollBar x:Name="VerticalScrollBar" Background="Fuchsia" Grid.Column="1" Margin="4,0,4,0" Opacity="0" Orientation="Vertical"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then used:
<phone:LongListSelector Style="{StaticResource LongListSelectorStyle1" />
One of the nuances of the ScrollBar primitive is that its color is controlled by Background, and not Foreground. There are a few ways to go about this. It can be modified in code behind, or you can edit the control template, which you seem familiar with.
XAML Control Template
Template
<phone:PhoneApplicationPage.Resources>
<ControlTemplate x:Key="LongListSelectorControlTemplate1" TargetType="phone:LongListSelector">
<Grid Background="{TemplateBinding Background}" d:DesignWidth="480" d:DesignHeight="800">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ScrollStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="00:00:00.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Scrolling">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
</Storyboard>
</VisualState>
<VisualState x:Name="NotScrolling"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<ViewportControl
x:Name="ViewportControl"
VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
/>
<ScrollBar x:Name="VerticalScrollBar" Opacity="0" Margin="4,0,4,0" Orientation="Vertical" Grid.Column="1"/>
</Grid>
</Grid>
</ControlTemplate>
</phone:PhoneApplicationPage.Resources>
Usage
<phone:LongListSelector x:Name="llsMyList" Template="{StaticResource LongListSelectorControlTemplate1}" />
Code Behind
Extension
public static class Extensions
{
/// <summary>
/// Finds the first element of a given type contained by this element.
/// </summary>
/// <typeparam name="TElement">The type of the <see cref="System.Windows.FrameworkElement"/> to locate.</typeparam>
/// <param name="anElement">The parent element.</param>
/// <returns>The first descendant <see cref="System.Windows.FrameworkElement"/> or null if not found.</returns>
public static TElement FindFirstDescendant<TElement>(this FrameworkElement anElement) where TElement : FrameworkElement
{
var targetType = typeof(TElement);
var queue = new Queue<FrameworkElement>();
queue.Enqueue(anElement);
while (queue.Count > 0)
{
var thisElement = queue.Dequeue();
if (thisElement != anElement)
{
var elementType = thisElement.GetType();
if (targetType == elementType || elementType.IsSubclassOf(targetType) || targetType.IsAssignableFrom(elementType))
{
return thisElement as TElement;
}
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(thisElement as DependencyObject); i++)
{
var childElement = VisualTreeHelper.GetChild(thisElement as DependencyObject, i) as FrameworkElement;
if (childElement != null)
{
queue.Enqueue(childElement);
}
}
}
return null;
}
}
Usage
public partial class MyPhonePage : PhoneApplicationPage
{
public MyPhonePage ()
{
llsMyList.Loaded += (sender, e) =>
{
var sb = llsMyList.FindFirstDescendant<System.Windows.Controls.Primitives.ScrollBar>();
sb.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Green);
}
}
}

How bind DependencyProperty of User Control in HeaderTemplate WinRT XAML?

I have a gridView, and binding my ObservableCollection different class items for my hub page.
Binding different class items to gridView and showing different item Data Templates, Header Templates.
I using User Control in Header Template in gridview.
My headertemplate, including user control and user control include some comboboxes. I want bind in pageRoot datacontext collection to in headertemplate combobox via parameter by on pageRoot object.
I'm create a user control and create some DependencyProperty, combobox eventhandlers.
But can't bind pageRoot DataContext collection to in user control comboboxes :(
My english is poor, sorry for this situation ;)
Thanks for your answers..
My headerdatatemplate:
<DataTemplate x:Key="OrganizationFixtureHeaderTemplate">
<Grid Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextStyle}"/>
</StackPanel>
<UserControls:UcCbOrganizationFixtureSelections
Grid.Column="1"
RootElement="pageRoot"
PageOrganizationSource="{Binding PageOrganization, ElementName=pageRoot}"
/>
</Grid>
</DataTemplate>
My user control code:
<UserControl
x:Class="Modern_UI.Common.UserControls.UcCbOrganizationFixtureSelections"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Modern_UI.Common.UserControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal">
<ComboBox x:Name="cbOrgFixtureSeasons"
ItemsSource="{Binding Path=DataContext.Seasons, ElementName=RootElement}"
SelectedValuePath="Id"
DisplayMemberPath="Name"
SelectionChanged="CbOrgFixtureSeasons_OnSelectionChanged"
Width="Auto"
Height="Auto"
/>
<ComboBox x:Name="cbOrgFixtureStages"
ItemsSource="{Binding Path=DataContext.FixtureStages, ElementName=RootElement}"
SelectedValuePath="Id"
DisplayMemberPath="Name"
SelectionChanged="CbOrgFixtureStages_OnSelectionChanged"
Width="Auto"
Height="Auto"
/>
<ComboBox x:Name="cbOrgFixtureRounds"
ItemsSource="{Binding Path=DataContext.FixtureRounds, ElementName=RootElement}"
SelectedValuePath="Id"
DisplayMemberPath="Name"
SelectionChanged="CbOrgFixtureRounds_OnSelectionChanged"
Width="Auto"
Height="Auto"
/>
</StackPanel>
</UserControl>
User control code behind:
namespace Modern_UI.Common.UserControls
{
public sealed partial class UcCbOrganizationFixtureSelections : UserControl
{
public DependencyProperty RootElementProperty = DependencyProperty.Register("RootElement",
typeof(string),
typeof(
UcCbOrganizationFixtureSelections
),
null);
public DependencyProperty PageOrganizationSourceProperty = DependencyProperty.Register("PageOrganizationSource",
typeof(Organization),
typeof(
UcCbOrganizationFixtureSelections
),
null);
public string RootElement
{
get { return this.GetValue(RootElementProperty) as string; }
set { this.SetValue(RootElementProperty, value); }
}
public Organization PageOrganizationSource
{
get { return this.GetValue(PageOrganizationSourceProperty) as Organization; }
set { this.SetValue(PageOrganizationSourceProperty, value); }
}
public UcCbOrganizationFixtureSelections()
{
this.InitializeComponent();
}
async private void CbOrgFixtureSeasons_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
//loading root page parameter via "PageOrganizationSource" named DependencyProperty.
}
}
I'm resolved my code problems, and some code added.
1- Bind user control of root page DataContext. Because user control inside gridview template. If insided a control in datatemplate, binding default datacontext of datatemplate itemsources. I want don't related with itemsource datacontext, bind rootpage datacontext.
Replaced Codes, in DataTemplate:
<DataTemplate x:Key="OrganizationFixtureHeaderTemplate">
<Grid Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextStyle}"/>
</StackPanel>
<UserControls:UcCbOrganizationFixtureSelections
Grid.Column="1"
RootElement="pageRoot"
DataContext="{Binding DataContext, ElementName=pageRoot}"
PageOrganizationSource="{Binding PageOrganization, ElementName=pageRoot}"
/>
</Grid>
</DataTemplate>
2- I'm replace in user control xaml code. User Control's Datacontext is of rootPage DataContext now. I'm can be binding every collection to my comboboxes this situation.
Replaced codes:
<UserControl
x:Class="Lig_TV_Modern_UI.Common.UserControls.UcCbOrganizationFixtureSelections"
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"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal">
<ComboBox x:Name="cbOrgFixtureSeasons"
ItemsSource="{Binding Seasons}"
SelectedValuePath="Id"
DisplayMemberPath="Name"
SelectionChanged="CbOrgFixtureSeasons_OnSelectionChanged"
Width="Auto"
Height="Auto"
/>
</StackPanel>
</UserControl>
Thanks for thinking on this problem. This structure can be communicated every element, and can be binding every collection without datatemplate itemsource datacontext. If use a datatemplate and need eventhandlers of controls, can be use User control.
Good coded days ;)

Observable collection - CollectionChanged Binding

During programming, I ran into the following questions:
Does a observable collection implement a CollectionChanged event by itself? (Because of differentbooks refering to the fact that it does, but google shows otherwise)
I have the following code, and I want my UI to update by binding (the code is for windowsPhone 7.1) Also, the binding works for single items in my observable collection, but when I try to add a new object to my collection, the CollectionChanged event doesn't fire.
namespace Phone.lib.ViewModel
{
public class DeviceViewModel : ViewModelBase
{
DeviceModelInfo InfoList = new DeviceModelInfo();
public DeviceViewModel()
{
}
public DeviceViewModel(int index)
{
// Here I add a new item to the collection, But the ui only shows: Beckhoff, ver....
InfoList.Add(new DeviceInfo("name1", "name2", "name3"));
}
}
public class DeviceModelInfo : ObservableCollection<DeviceInfo>
{
public DeviceModelInfo() : base()
{
Add(new DeviceInfo("Beckhoff", "Ver. 1A2B3C", "Stopped"));
}
}
public class DeviceInfo : ViewModelBase
{
private string devicename;
private string deviceid;
private string devicestatus;
public DeviceInfo(string first, string second, string third)
{
devicename = first;
deviceid = second;
devicestatus = third;
}
public string DeviceName
{
get { return devicename; }
set
{
devicename = value;
RaisePropertyChanged("DeviceName");
}
}
public string DeviceID
{
get { return deviceid; }
set { deviceid = value; }
}
public string DeviceStatus
{
get { return devicestatus; }
set { devicestatus = value; }
}
}
Note: The class inherits from viewmodel base wich has the Inotify changed interface in it.
Code from my Xaml:
<phone:PhoneApplicationPage
x:Class="WindowsPhone.View.Device_Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ViewModel="clr-namespace:Phone.lib.ViewModel;assembly=Phone.lib"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
<!-- Static Resource area for binding -->
<phone:PhoneApplicationPage.Resources>
<ViewModel:DeviceModelInfo x:Key="deviceinfo"></ViewModel:DeviceModelInfo>
<ViewModel:DeviceModelSensor x:Key="devicesensors"></ViewModel:DeviceModelSensor>
<ViewModel:DeviceModelActuator x:Key="deviceactuators"></ViewModel:DeviceModelActuator>
</phone:PhoneApplicationPage.Resources>
<!-- LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="Kremer app" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Height="100" HorizontalAlignment="Left" Margin="-4,6,0,0" Name="Device_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding Source={StaticResource deviceinfo}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="100">
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=DeviceName, Mode=TwoWay}" />
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=DeviceID, Mode=TwoWay}" />
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=DeviceStatus, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Height="261" HorizontalAlignment="Left" Margin="-4,138,0,0" Name="Sensor_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding Source={StaticResource devicesensors}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="78">
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=SensorName}" />
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=SensorType}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Height="261" HorizontalAlignment="Left" Margin="-4,429,0,0" Name="Actuator_ListBox" ItemsSource="{Binding Source={StaticResource deviceactuators}}" VerticalAlignment="Top" Width="460">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Height="78" Margin="0,0,0,17" Width="432">
<TextBlock Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=ActuatorName}" TextWrapping="Wrap" />
<TextBlock Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=ActuatorType}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
I hope someone is able to help me with this problem because i have been at this for like two days now.
Also, my apologies for my "bad" english, but english is not my native language
Cheers -Bart
EDIT: done a little test
I have run a little debugtest myself to see if the add operation adds to the right collection en therefor increments the count value
public DeviceViewModel(int index)
{
// Here I add a new item to the collection, But the ui only shows: Beckhoff, ver....
Debug.WriteLine("number of added items " + InfoList.Count.ToString());
InfoList.Add(new DeviceInfo("1", "2", "3"));
Debug.WriteLine("number of added items " + InfoList.Count.ToString());
InfoList.Add(new DeviceInfo("1", "2", "3"));
InfoList.Add(new DeviceInfo("1", "2", "3"));
InfoList.Add(new DeviceInfo("1", "2", "3"));
Debug.WriteLine("number of added items " + InfoList.Count.ToString());
}
output:
number of added items 1
number of added items 2
number of added items 5
Edit 2 (19-03-2012)
Last friday I tried to get it working like you suggested. But somehow the XAML can't find InfoList, and I don't know why. Maybe I do something wrong in the XAML itself or in the code behind or in the DeviceViewModel. So here is what I have at the moment:
DeviceViewModel:
namespace Phone.lib.ViewModel
{
public class DeviceViewModel : ViewModelBase
{
public DeviceModelInfo InfoList = new DeviceModelInfo();
public DeviceViewModel()
{
//DeviceModelInfo InfoList = new DeviceModelInfo();
InfoList.Add(new DeviceInfo("1", "2", "3"));
}
public DeviceViewModel(int index)
{
}
}
public class DeviceModelInfo : ObservableCollection<DeviceInfo>
{
public DeviceModelInfo() : base()
{
Add(new DeviceInfo("Beckhoff", "Ver. 1A2B3C", "Stopped"));
//this.CollectionChanged += (e, s) => { Debug.WriteLine("event Fired " + e.ToString()); };
}
}
public class DeviceInfo : ViewModelBase
{
private string devicename;
private string deviceid;
private string devicestatus;
public DeviceInfo(string first, string second, string third)
{
devicename = first;
deviceid = second;
devicestatus = third;
}
public string DeviceName
{
get { return devicename; }
set
{
devicename = value;
RaisePropertyChanged("DeviceName");
}
}
public string DeviceID
{
get { return deviceid; }
set { deviceid = value; }
}
public string DeviceStatus
{
get { return devicestatus; }
set { devicestatus = value; }
}
}
The code behind the page:
namespace WindowsPhone.View
{
public partial class Device_Page : PhoneApplicationPage
{
private DeviceViewModel _DV;
public Device_Page()
{
InitializeComponent();
_DV = new DeviceViewModel();
DataContext = _DV;
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
string selectedIndex = "";
if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
{
int index = int.Parse(selectedIndex);
//_DV = new DeviceViewModel(index);
//DataContext = _DV;
Debug.WriteLine("index:" + index.ToString());
}
}
}
}
The XAML code:
<phone:PhoneApplicationPage
x:Class="WindowsPhone.View.Device_Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ViewModel="clr-namespace:Phone.lib.ViewModel;assembly=Phone.lib"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
<!-- Static Resource area for binding -->
<phone:PhoneApplicationPage.Resources>
<ViewModel:DeviceViewModel x:Key="deviceinfo"></ViewModel:DeviceViewModel>
<ViewModel:DeviceModelSensor x:Key="devicesensors"></ViewModel:DeviceModelSensor>
<ViewModel:DeviceModelActuator x:Key="deviceactuators"></ViewModel:DeviceModelActuator>
</phone:PhoneApplicationPage.Resources>
<!-- LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="Kremer app" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Height="100" HorizontalAlignment="Left" Margin="-4,6,0,0" Name="Device_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding InfoList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="100">
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=DeviceName, Mode=TwoWay}" />
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=DeviceID, Mode=TwoWay}" />
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=DeviceStatus, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Height="261" HorizontalAlignment="Left" Margin="-4,138,0,0" Name="Sensor_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding Source={StaticResource devicesensors}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="78">
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=SensorName}" />
<TextBlock TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=SensorType}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Height="261" HorizontalAlignment="Left" Margin="-4,429,0,0" Name="Actuator_ListBox" ItemsSource="{Binding Source={StaticResource deviceactuators}}" VerticalAlignment="Top" Width="460">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Height="78" Margin="0,0,0,17" Width="432">
<TextBlock Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}" Text="{Binding Path=ActuatorName}" TextWrapping="Wrap" />
<TextBlock Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Path=ActuatorType}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
1) ObservableCollection implements the INotifyCollectionChanged interface, which defines the CollectionChanged event.
2) When you add a new item in DeviceViewModel you do it to a new instance of DeviceModelInfo, so a different instance than the one you declared in your XAML
<ViewModel:DeviceModelInfo x:Key="deviceinfo"></ViewModel:DeviceModelInfo>
You have to either bind to the DeviceModelInfo instance in DeviceViewModel
or use the instance of DeviceViewModel, declared in your XAML
Edit
In your XAML you have
That is the same as typing 'new DeviceModelInfo()' and then registering that instance in the resources of your control PhoneApplicationPage. And you bind the the ItemsSource of your ListBox to that particular instance.
ItemsSource="{Binding Source={StaticResource deviceinfo}}"
Now in your DeviceViewModel class you declare InfoList like this
DeviceModelInfo InfoList = new DeviceModelInfo();
You create a new instance of DeviceModelInfo, so InfoList is not the same instance/object as the instance/object in your XAML.
You must either
1) Bind your ItemsSource of the ListBox to the instance you have in DeviceViewModel. To do this you must first expose InfoList, that is make it public preferably through a property (but that's just convention, not required). Then make sure the DataContext of your control is set to the instance of DeviceViewModel your're working with. And then you can set the binding like this
ItemsSource="{Binding InfoList}"
Assuming InfoList is public
2) Get the instance deviceinfo created in your XAML like this:
DeviceViewModel deviceinfo = phoneApplicationPage.FindResource("deviceinfo") as DeviceViewModel;
assuming the instance of your control is called phoneApplicationPage. If you do it in the code behind of your control then phoneApplicationPage would be this.
And now you can pass this instance (deviceinfo) to your instance of DeviceViewModel.
From the naming I assume you're attempting to use the MVVM pattern, in which case you should go with 1)
Edit
Making the field public is good enough.
Now you need to bind it to the ItemsSource property of the ListBox. Which can be as simple as
ItemsSource="{Binding InfoList}"
But this requires that the DataContext property of your page (PhoneApplicationPage) is set to an instance of DeviceViewModel.
Without knowing exactly how you currently instantiate DeviceViewModel, it's hard for me to explain exactly how you can go about doing this. But I assume you instantiate DeviceViewModel in the code-behind of your page, so it looks something like this:
public partial class PhoneApplicationPage : Page
{
private DeviceViewModel _deviceViewModel;
//...
public PhoneApplicationPage()
{
InitializeComponent();
// I assume you do something like this
_deviceViewModel = new DeviceViewModel();
// You need to set the DataContext to the DeviceViewModel instance you have created.
DataContext = _deviceViewModel;
}
//...
}
Once you've made sure the DataContext is set to your DeviceViewModel instance then you can change the binding in your XAML like stated above.
So you should change the line
<ListBox Height="100" HorizontalAlignment="Left" Margin="-4,6,0,0" Name="Device_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding Source={StaticResource deviceinfo}}">
to
<ListBox Height="100" HorizontalAlignment="Left" Margin="-4,6,0,0" Name="Device_ListBox" VerticalAlignment="Top" Width="460" ItemsSource="{Binding ListInfo}">

Pop Up: a problem with margin Top

I'm developing a Windows Phone app.
I use a user control to show a pop up:
<UserControl x:Class="XXXXXXX.Views.Lists.GameDescriptionControl"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}" Height="290" Width="460">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}" Margin="0,0,0,0" Width="460">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="133"/>
<RowDefinition Height="86"/>
</Grid.RowDefinitions>
<TextBlock HorizontalAlignment="Center" Margin="10" Name="gameDescription" Text="" VerticalAlignment="Top" TextWrapping="Wrap" Grid.Row="1" Style="{StaticResource PhoneTextTitle3Style}" />
<Button Content="{Binding Path=AppResources.Yes, Source={StaticResource LocalizedStrings}}" Height="72" HorizontalAlignment="Left" Margin="50,5,0,0" Name="okButton" VerticalAlignment="Top" Width="160" Click="okButton_Click" Grid.Row="2" />
<Button Content="{Binding Path=AppResources.No, Source={StaticResource LocalizedStrings}}" Height="72" HorizontalAlignment="Left" Margin="244,5,0,0" Name="cancelButton" VerticalAlignment="Top" Width="160" Click="cancelButton_Click" Grid.Row="2" />
<TextBlock Grid.Row="0" x:Name="caption" HorizontalAlignment="Left" Margin="10" TextWrapping="Wrap" Text="{Binding Path=AppResources.Description, Source={StaticResource LocalizedStrings}}" Style="{StaticResource PhoneTextLargeStyle}"/>
</Grid>
</UserControl>
And this is the code to show the Pop Up:
private void showInfo(int gameId)
{
string gameDesc = getGameInfo(gameId);
p = new Popup();
GameDescriptionControl gd = new GameDescriptionControl();
gd.Description = gameDesc;
gd.OkClicked += new EventHandler(gd_OkClicked);
gd.CancelClicked += new EventHandler(gd_CancelClicked);
p.Child = gd;
// Set where the popup will show up on the screen.
p.VerticalOffset = 10;
p.HorizontalOffset = 10;
// Open the popup.
p.IsOpen = true;
}
But I get this:
As you can see, caption TextBlock hasn't got a margin top.
Any advice?
Margin will refer to the area outside of your textblock. If you want to move your text away from the edge of the textblock you will need to use the Padding attribute.
Not to act like the word paperclip, but it looks like you're trying to make a custom MessageBox.
Check this implementation out: http://cloudstore.blogspot.com/2011/01/customizing-messagebox-on-windows-phone.html . It's a great implementation of a messagebox that is very easy to use, looks/behaves very closely to the real MessageBox, and is lightweight.
Adding the few files that come with the solution, all you have to do is:
private MessageBoxService mbs = new MessageBoxService();
...
mbs.Closed +=new System.EventHandler(mbs_Closed);
mbs.Show("Confirm?","Are you sure you wish to do that?",MessageBoxServiceButton.YesNo,null);
void mbs_Closed(object sender, System.EventArgs e)
{
mbs.Closed -= mbs_Closed;
if (mbs.Result == MessageBoxResult.Yes)
{
...
}
}

Resources