Reuse of element in xaml (win store app) - wpf

In my xy.xaml file which is representing LayoutAwarePage I have this two elements
<StackPanel x:Name="LeftCommands" Orientation="Horizontal" Grid.Column="2" Margin="0,0,100,0" HorizontalAlignment="Right">
<Button x:Name="BragButton" HorizontalAlignment="Left"/>
</StackPanel>
and
<Page.TopAppBar>
<AppBar x:Name="PageAppBar" Padding="10,0,10,0" Height="120" Opacity="0.98">
<ItemsControl x:Name="groupTopMenuBar" Margin="116,0,40,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,0">
<Button Click="UpperMenu_Click"
Style="{StaticResource TextPrimaryButtonStyle}"
Height="Auto" Margin="20,0,20,0"
CommandParameter="{Binding Group.MenuItemID}">
<StackPanel>
<Image Source="{Binding Group.IconURL}" Width="40"
Height="40" VerticalAlignment="Top" Stretch="UniformToFill" />
<TextBlock Text="{Binding Group.Name}" HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}"
Style="{StaticResource TitleTextStyle}" FontSize="16" />
</StackPanel>
</Button>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</AppBar>
</Page.TopAppBar>
I need to use these elements in every page of my application and I do not want to write this pieces of code in every .xaml file of application, so I want to ask if there is any way how to do this.
Thank you.

You want to share your AppBar across multiple pages. Unfortunately, in Windows Store apps it is not possible using referencing AppBar defined in App.xaml using StaticResource as is the case of Windows Phone.
There are 2 ways how to do it:
Create another Frame inside your main page and do all navigation in this frame. Check this MSDN article.
Create UserControl with contents (buttons) of your AppBar, add TopAppBar on every page and set its content to that UserControl. This approach is advised in this StackOverflow answer.
I might see little problem with page navigation. If you want to navigate the hosting frame from the UserControl, store the Frame instance which is created in the App.xaml.cs OnActivated method to some static property of App class. For example public static Frame RootFrame { get; private set; } and set it by App.RootFrame = new Frame(). To navigate from the code behind your UserControl just call something like this: App.RootFrame.Navigate().
This approach was advised by Filip Skakun here on StackOverflow.

Related

TextBlock1 is not declared. It may be inaccessible due to its protection level

As silly as this sounds I'm a little stumped at this one. Here's my XAML in a Win Phone 8 App:
<!--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 Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="Page" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="MainLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock x:Name="TextBlock1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
</Grid>
I've searched around but I don't know why I can't write code against the TextBlock1 control in code behind. When I type TextBlock1.Text= .... I get the error TextBlock1 is not declared. It may be inaccessible due to its protection level. But I can't see how it is private?
All I'm trying to do is add a textblock, assign some content to it, and then that selected value is passed across another page to perform relevant action.
In addition as soon as I remove it outside of the PhoneListSelector I can access it.
TextBlock1 is defined inside an ItemTemplate, anything defined a Template cannot be access directly as it will be created on runtime by the control.
You probably need to do binding on the TextBlock if you want to manipulate anything that the LongListSelector's DataContext has.
<phone:LongListSelector x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="MainLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock x:Name="TextBlock1" Text="{Binding Content"} HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
MainLongListSelector.DataContext = new List<TestViewModel>();
public class TestViewModel : INotifyPropertyChanged
{
//Assuming you've implemented the interface
private string _content;
public string Content { get { return _content; } { set { _content = value; NotifyOfPropertyChanged("Content"); } }
}
From here, you can try to access the selected value content and pass that to the next page.
var selectedItem = MainLongListSelector.SelectedItem as TestViewModel;
GoToNextPage(selectedItem.Content);
I strongly suggest to read MVVM design pattern and everything should be easy for you to implement, always remember UI is not DATA it's responsibility is only to show something that is passed through the ViewModel.

Proper usage of Viewbox for WPF kiosk touch screen applications

Is there some kind of "best practices" manual for creating proper GUI for kiosk touch screens? These applications need to have consistent look and feel across different screen resolutions and more importantly screen ratios (since everything is rendered as vectors so screen resolution and DPI shouldn't be an issue with WPF).
Take for example this screenshot where I tried to create simple keyboard for touch screens. I've used UniformGrid so that each button gets cell of equal size:
Here is the code for this:
<TabItem Header="Test 1">
<ItemsControl ItemsSource="{Binding KeyboardItems}" SnapsToDevicePixels="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Viewbox Margin="5">
<Button Content="{Binding}"></Button>
</Viewbox>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</TabItem>
Notice that all buttons are sized to content which makes them non-stretchable so each button has its own size... This is how Viewbox scales its content and of course this kind of GUI is out of question. This is not the keyboard I want to use on some kiosk application, so the next better version is following:
<TabItem Header="Test 2">
<ItemsControl ItemsSource="{Binding KeyboardItems}" SnapsToDevicePixels="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="5">
<Viewbox>
<TextBlock Text="{Binding}" />
</Viewbox>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</TabItem>
Now this is a bit better as Viewbox is now wrapping the content rather than the whole button. Notice however that because we are now wrapping the button's content rather the whole button the button's border is now not scaled. I want this to be scaled too, not just the content. In the first example we had this but the overall look of the GUI was horrible.
Also notice that in this version I've set Margin to the Button and in the first version on the Viewbox. This means that in the first version margin will scale too (I want that!) while in the second version it will be constant for any screen size. So for really big screens the white space between buttons will become relatively smaller though they are absolutely of constant size (not what I want!).
Here is the code for generating keyboard buttons:
public partial class MainWindow : Window
{
public List<string> KeyboardItems { get; set; }
public MainWindow()
{
KeyboardItems = new List<string>();
for (char c = 'A'; c <= 'Z'; c++)
{
KeyboardItems.Add(c.ToString());
}
KeyboardItems.Add("Space");
DataContext = this;
InitializeComponent();
}
}
Problems like this are all around development of WPF touch screen kiosks so I'd like to hear some ideas and solutions you came about while dealing with scaling issues.
You didn't show us Test 3, which I thought might be this:
<TabItem Header="Test 3">
<Viewbox>
<ItemsControl ItemsSource="{Binding KeyboardItems}" SnapsToDevicePixels="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="5">
<TextBlock Text="{Binding}" />
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Viewbox>
</TabItem>
Does that have the desired effect?

WP7 An Image over the full display

I am developing an application where i want to browse images like native WindowsPhone form.
I have used Pivot control. Everything works, but there is one unwanted thing. The image does not fill all display area. There is a gap on the top of page. I have set margin and padding everywhere where it is possible. And the result is still the same. :(
Here is my XAML code:
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid
x:Name="LayoutRoot"
Background="Transparent"
Margin="0">
<toolkit:PerformanceProgressBar
VerticalAlignment="Top"
HorizontalAlignment="Left"
IsIndeterminate="{Binding IsBusy}"
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVisibilityConverter}}"
/>
<controls:Pivot
x:Name="PhotoPivot"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
IsHitTestVisible="True"
ItemsSource="{Binding Photos}"
Margin="0"
Padding="0"
>
<controls:Pivot.HeaderTemplate>
<DataTemplate/>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate >
<controls:PivotItem
x:Name="PhotoPivotItem"
Margin="0"
>
<Image
x:Name="PhotoPicture"
Source="{Binding}"
Stretch="Uniform"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Margin="0"
/>
</controls:PivotItem>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
</Grid>
Are you talking about the system tray?
To remove the system tray use the following code:
shell:SystemTray.IsVisible="False"
Update:
I'm not real sure why that extra space is there.
I created a simplified version of your example and the only thing I could think of is to use negative margins. There is probably a better solution that I am just overlooking, but for now you can just use the following:
<controls:PivotItem x:Name="PhotoPivotItem" Margin="0,-10,0,0">
Although, from your posted image, it looks as if you have a bigger gap than I did, so you might need to decrease the margin.

How to change HirerachicalDataTemplate associated with the WPF TreeView programatically at run time?

I have a TreeView control on my WPF window. I am giving only relevant XAML from my window.
<Window.Resources>
<HierarchicalDataTemplate x:Key="HierarchicalTemplate" ItemsSource="{Binding SubOrgUnitItems}">
<StackPanel Orientation="Horizontal">
<Image Height="16" Source="{Binding ImagePath}" Stretch="Fill" Width="16"/>
<TextBlock Text="{Binding OrgUnitName}" Name="treeText" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView Margin="10,35,10,10" BorderThickness="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Auto"
IsTabStop="True" Name="orgTreeView" ItemsSource="{Binding}" ItemTemplate="{DynamicResource HierarchicalTemplate}" TabIndex="700" SelectedItemChanged="orgTreeView_SelectedItemChanged" />
When the Collection of Organisations is bound to DataContext of the TreeView, items are displayed with the OrgUnitName's value as a text at every node.
Now at run time I want to see some other property's value as a text at every node. e.g. OrgUnitCode instead of OrgUnitName. Both are properties declared in the view model class associated with the treeview.
How can i do it programatically at run time?
You should use HierarchicalDataTemplateSelector.
Define two different HierarchicalDataTemplate (as you did).
Inherite your custom selector class from DataTemplateSelector, override its SelectTemplate method and put there the logic of the selection. This method will return the correct template in each case.
Create a Resource(Custom Selector class) in the xaml file.
Set the TreeViews ItemTemplateSelector to the static selector resource.
See a simple example here: Link
I have achieved what I wanted to do, but unfortunately by some work around. Following thing worked for me but it may not be the correct answer to the problem.
I added one more HirerachicalDataTemplate and TreeView. The new template uses the OrgUnitCode property. The new tree view uses the new template.
<HierarchicalDataTemplate x:Key="HierarchicalTemplateUsingCode" ItemsSource="{Binding SubOrgUnitItems}">
<StackPanel Orientation="Horizontal">
<Image Height="16" Source="{Binding ImagePath}" Stretch="Fill" Width="16"/>
<TextBlock Text="{Binding OrgUnitCode}" Name="treeText" />
</StackPanel>
</HierarchicalDataTemplate>
<TreeView Margin="10,35,10,10" BorderThickness="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Auto"
IsTabStop="True" Name="orgTreeViewCode" ItemsSource="{Binding}" ItemTemplate="{DynamicResource HierarchicalTemplateUsingCode}" TabIndex="700" SelectedItemChanged="orgTreeViewCode_SelectedItemChanged" Visibility="Hidden"/>
At run time, when I want to see OrgUnitCode property value as a text at the node, I simply make new tree visible and hide the first one (mentioned in question). So making tree views visible/invisible help me to achieve what I wanted to do.

WPF ListBox DataTemplate and Image Question

I have a ListBox with a StackPanel that contains an image and label.
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding Image}" Cursor="Hand" Tag="{Binding Link}" MouseLeftButtonDown="Image_MouseLeftButtonDown" ToolTip="Click to see this product on adidas.com" VerticalAlignment="Top" HorizontalAlignment="Left" />
<Label Content="{Binding Name}" Cursor="Hand" Tag="{Binding Link}" MouseLeftButtonDown="Label_MouseLeftButtonDown" VerticalAlignment="Bottom" Foreground="White" Style="{StaticResource Gotham-Medium}" FontSize="8pt" HorizontalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
I want to show a third image (glow.png) behind the currently moused over image. I can't seem to add a second image to the stack panel, and set it's visibility to hidden. I haven't even tackled the mouseover part yet.
Is adding another image inside the stack panel, and then setting it's visibility to visible the right approach on mouseenter, and then swapping back on mouseleave?
Thanks.
You certainly can have one image behind another. Instead of directly adding the image to your StackPanel, add a Grid and then add both images, like this:
<StackPanel Orientation="Vertical">
<Grid>
<Image Source="..." />
<Image Source="{Binding Image}" ... />
</Grid>
<Label Content="{Binding Name}" ... />
</StackPanel>
You might also like to look into Bitmap Effects, using which you can introduce a "glow" effect onto any WPF element.
Edit: Another way to achieve the effect you want (I believe) is to swap out the image's Source property in a trigger. I'm not going to try to write the XAML from memory here, but you could catch the IsMouseOver property for the image itself, and when it switches to True you could set its Source to the "glowing" version of the image.
Another possibility is to add a border to your image, set the color of the borderbrush to whatever you want and the opacity to 0. In your MouseEnter event handler set the opacity to 1.

Resources