How do I use a button in Windows Phone 8 hub app - c#

I am trying to change the context of a button inside a DataTemplate, but in my code-behind I can't acses it. What am I doing wrong?
Here is the XAML I am using:
<Grid>
<Hub>
<HubSection>
<DataTemplate>
<Grid>
<Button x:Name="THEbutten" Content="Button" HorizontalAlignment="Left" Margin="186,230,0,0" VerticalAlignment="Top"/>
</Grid>
</DataTemplate>
</HubSection>
</Hub>
</Grid>

Your Button is inside a DataTemplate, and therefore it is in a different context than the page and not accessible from it's codebehind.
Consider the following options:
Modify your Buttons Properties using Data Binding.
Create a UserControl for your HubSections Content.
Sadly, the Hub Control is fairly hard to understand and use for beginners, because of this DataTemplate.
Here are some tutorials:
Mikaelkoskinen - Getting started
DotNetCurry - The Windows 8.1 Hub Control
There are also several questions around here on that topic:
How to access controls within hubsections

Related

Click handler of button in datatemplate not working

I have a resource dictionary combining a number of datatemplates. I'm including this resource dictionary as a ResourceDictionary.MergedDictionaries in my Page.Resources. One of my datatemplates is a ListView and while the item source and item click is working correctly, a separate button on the ListViewItem, set in the datatemplate, is not calling my click method. Im unsure about setting this up correctly.
This click method is defined in the code behind class the defines the pages Xaml including the resource dictionary and using my datatemplate for ListViewItems.
Dictionaries
DataTemplates.xaml <- ListView template here with a button click defined in the page cs, i.e. Click="MyPages_ClickMethod"
Pages
MyPage.xaml
MyPage.xaml.cs <- click method defined here, MyPages_ClickMethod()
Here is how I am setting up the button in the datatemplate:
<Button Tag="{Binding id}" Click="MultiShareSelectFileButton_Click" Background="Transparent" Visibility="{Binding multiShareSelected, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Inverted, Mode=OneWay}">
<Image Width="27" Source="ms-appx:///Assets/sharePlusIcon#2x.png" VerticalAlignment="Center" HorizontalAlignment="Center">
</Image>
</Button>
Is it possible to do this without using ICommand?
Something like: Click="{x:Bind Path=pages:ProductPage.MultiShareSelectFileButton_Click}", but this is complaining that MultiShareSelectFileButton_Click should be static
I'll get right to it. Here is the issue,
Your DataTemplate is in a resource dictionary. The resource dictionary is made for styles and converters if I may. Putting the DataTemplate in a resource dictionary is not recommended.
Why isn't it recommended?
The reason is straight, resource dictionaries are used to put global data. For ex: a control style that you might want to be available through out your app or your converters which are being used frequently.
This is because generally you would define the resource dictionary in your app.xaml which runs when your splashscreen appears.
Now if you have a lot of stuff (DataTemplates, Styles, Converters) all defined into resource dictionaries that are merged in <Application.ResourceDictionary> part of app.xaml, it's gonna have a significant impact on your app launch time, which will spoil your user's experience.
What's advised?
It's advised to keep your converters and styles not global unless you need them everywhere. For example: If you have a BoolToVisibilityConverter or a CustomRoundButtonStyle which you use only on one page/userControl out of 4. Then it doesn't make sense to load the style or converter for the other 3 Pages. So you should declare them in <Page.Resources> instead.
Same for your DataTemplate why declare it globally if you want to use it just once. Rather declare it to your <Page.Resources>. Your problem will be solved immediately as your Page will have a code-behind, so your xaml will know where to look for the method. That's where things are going wrong.
But in-case you have a single DataTemplate to be used on all your Views below is your solution:
Your Solution:
In-case you have to use it in a resource dictionary, use {x:Bind} and x:DataType="Models:YourDataContextModel" to bind your DataTemplate to your model. this ways your xaml will know exactly where to look for the method on click.
Below is a sample of it:
<DataTemplate x:Key="HelloTemplate" x:DataType="yourDefinedNameSpace:YourModel">
<Button Click="{x:Bind GoFetchData}"/>
</DataTemplate>
Where YourModel exists in a namespace defined as "yourDefinedNameSpace" in xaml and it contains a method of signature: internal void GoFetchData()
I hope this helps. Feel free to use the comments section if you have any doubts
I found that it was also necessary to specify ClickMode="Press" in Xaml.
<Button Content="" Focusable="True" FontFamily="Segoe UI Symbol" FontSize="16" Background="{StaticResource HeroLightGray}" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"
ClickMode="Press"
Command="{Binding DataContext.CopyMetadataSourceAsync, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" CommandParameter="{Binding .}" />
I do not recall having to do this in the past, but after spending hours troubleshooting, converting RelayCommand to IAsyncCommand, etc. this is the only thing that worked. In fact, I couldn't even get a regular code-behind "Click event" method to fire unless I included that ClickMode="Press"!

Can't get custom fonts to display at runtime - Windows Phone 8.1 MVVM - FontAwesome

I am having trouble with custom fonts in my Windows Phone 8.1 MVVM app.
I am using FontAwesome icons. I have included the FontAwesome font file in my project. When I set a static control such as this, it works perfectly;
<TextBlock x:Name="txtTest" Grid.Row="3" Text="" Foreground="Black" FontSize="20" FontFamily="/Assets/Fonts/FontAwesome.ttf#FontAwesome"/>
However, what I need is for this to work dynamically. I have a Hub control on the main page of the app, with ListViews in each Hub section. These are bound to a collection of custom objects, populated from an API response. When creating the collection of objects, the code looks for a marker in the response and dynamically sets the FontAwesome icon depending on the marker.
Hub Section code:
<HubSection x:Uid="hubApproved" Header="Approved"
DataContext="{Binding MyObjects.Approved}"
d:DataContext="{Binding MyObjects.Approved}"
HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}" >
<DataTemplate>
<ListView
ItemsSource="{Binding}"
ItemTemplate="{ThemeResource ApprovedTemplate}"
IsItemClickEnabled="True"
ItemClick="ListView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
</ListView>
</DataTemplate>
</HubSection>
And here is the Approved Template which binds to this:
<DataTemplate x:Key="ApprovedTemplate">
<StackPanel Margin="0,0,0,19" Background="{x:Null}" >
<TextBlock FontFamily="/Assets/Fonts/FontAwesome.ttf#FontAwesome" Text="{Binding Icon}" Foreground="Black" />
<TextBlock Text="{Binding SupplierName}" Style="{ThemeResource ListViewItemTripNameTextBlockStyle}" />
<TextBlock Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" Text="{Binding StartDate}"></TextBlock>
</StackPanel>
</DataTemplate>
The Template contains a TextBlock which binds to the Icon property of my object. This is supposed to then display the appropriate FontAwesome icon, but instead just displays the unicode of the icon:
I have tried defining the font family of the Hub control from the code behind in the view, but it has no effect:
Hub.FontFamily = new FontFamily("ms-appx:///Assets/Fonts/FontAwesome.otf#FontAwesome");
Any ideas on how to dynamically get these icons to display...? Thanks
You should be able to do it like this:
FontFamily fontFam = new FontFamily("ms-appx:///Assets/Fonts/FontAwesome.otf#FontAwesome");
and set FontFamily like this:
Hub.FontFamily = fontFam
I solved this with a workaround. The icons in my ListView will only ever be 1 of 5 possible icons. So instead of setting the unicode, I created 5 different textbox objects in the template definition, one for each icon. The unicode is static, so the dynamic aspect is instead the Visibility of each object. I created corresponding XAML Visibility properties on the custom object. After this, the style object is bound to its Visibility property, like so:
<!--Generic (shopping cart icon)-->
<TextBlock FontFamily="/Assets/Fonts/FontAwesome.otf#FontAwesome" Grid.Column="0" Text="" Style="{ThemeResource ListViewItemTripNameTextBlockStyle}"
VerticalAlignment="Center" Visibility="{Binding VisGeneric}" />
Then when I create the object collection from the API response, I set the appropriate visibility property to be Visible, according the the marker in the response.
I'd like a slightly more elegant solution than this, but essentially it works...

Open WPF Window in StackPanel [duplicate]

I am currently writing a desktop application, but I cannot seem to get my head around what to use when redirecting someone to a new section of the application.
My options appear to be
Window
Page
UserControl
but I don't understand what the difference between them is, and when I should use each one.
Could someone explain the differences for me, and give an example of what situations/applications you may use each one for?
A Window object is just what it sounds like: its a new Window for your application. You should use it when you want to pop up an entirely new window. I don't often use more than one Window in WPF because I prefer to put dynamic content in my main Window that changes based on user action.
A Page is a page inside your Window. It is mostly used for web-based systems like an XBAP, where you have a single browser window and different pages can be hosted in that window. It can also be used in Navigation Applications like sellmeadog said.
A UserControl is a reusable user-created control that you can add to your UI the same way you would add any other control. Usually I create a UserControl when I want to build in some custom functionality (for example, a CalendarControl), or when I have a large amount of related XAML code, such as a View when using the MVVM design pattern.
When navigating between windows, you could simply create a new Window object and show it
var NewWindow = new MyWindow();
newWindow.Show();
but like I said at the beginning of this answer, I prefer not to manage multiple windows if possible.
My preferred method of navigation is to create some dynamic content area using a ContentControl, and populate that with a UserControl containing whatever the current view is.
<Window x:Class="MyNamespace.MainWindow" ...>
<DockPanel>
<ContentControl x:Name="ContentArea" />
</DockPanel>
</Window>
and in your navigate event you can simply set it using
ContentArea.Content = new MyUserControl();
But if you're working with WPF, I'd highly recommend the MVVM design pattern. I have a very basic example on my blog that illustrates how you'd navigate using MVVM, using this pattern:
<Window x:Class="SimpleMVVMExample.ApplicationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SimpleMVVMExample"
Title="Simple MVVM Example" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:HomeViewModel}">
<local:HomeView /> <!-- This is a UserControl -->
</DataTemplate>
<DataTemplate DataType="{x:Type local:ProductsViewModel}">
<local:ProductsView /> <!-- This is a UserControl -->
</DataTemplate>
</Window.Resources>
<DockPanel>
<!-- Navigation Buttons -->
<Border DockPanel.Dock="Left" BorderBrush="Black"
BorderThickness="0,0,1,0">
<ItemsControl ItemsSource="{Binding PageViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"
Margin="2,5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<!-- Content Area -->
<ContentControl Content="{Binding CurrentPageViewModel}" />
</DockPanel>
</Window>
Window is like Windows.Forms.Form, so just a new window
Page is, according to online documentation:
Encapsulates a page of content that can be navigated to
and hosted by Windows Internet Explorer, NavigationWindow, and Frame.
So you basically use this if going you visualize some HTML content
UserControl is for cases when you want to create some reusable component (but not standalone one) to use it in multiple different Windows
All depends on the app you're trying to build. Use Windows if you're building a dialog based app. Use Pages if you're building a navigation based app. UserControls will be useful regardless of the direction you go as you can use them in both Windows and Pages.
A good place to start exploring is here: http://windowsclient.net/learn
We usually use One Main Window for the application and other windows can be used in situations like when you need popups because instead of using popup controls in XAML which are not visible we can use a Window that is visible at design time so that'll be easy to work with
on the other hand we use many pages to navigate from one screen to another like User management screen to Order Screen etc In the main Window we can use Frame control for navigation like below
XAML
<Frame Name="mainWinFrame" NavigationUIVisibility="Hidden" ButtonBase.Click="mainWinFrame_Click">
</Frame>
C#
private void mainWinFrame_Click(object sender, RoutedEventArgs e)
{
try
{
if (e.OriginalSource is Button)
{
Button btn = (Button)e.OriginalSource;
if ((btn.CommandParameter != null) && (btn.CommandParameter.Equals("Order")))
{
mainWinFrame.Navigate(OrderPage);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
That's one way of doing it We can also use a Tab Control instead of Fram and Add pages to it using a Dictionary while adding new page check if the control already exists then only navigate otherwise add and navigate. I hope that'll help someone
Most of all has posted correct answer. I would like to add few links, so that you can refer to them and have clear and better ideas about the same:
UserControl:
http://msdn.microsoft.com/en-IN/library/a6h7e207(v=vs.71).aspx
The difference between page and window with respect to WPF:
Page vs Window in WPF?

Focus on Canvas overlapping the listbox in WP7

I have a situation here. I have a page containing a ListBox. The ListBox is populated with Items if it is able to fetch the data from a web service. Now when the user doesn't have network connectivity on his phone or the webservice doesn't respond back with Ok status, I want to show the user a pop-up with an option to Retry or select Ok to stay on the same page (though it sounds dumb). Now for this I used a Canvas:
<Canvas Name="Nonetwork" Height="150" Width="280" HorizontalAlignment="Center" VerticalAlignment="Center" Background="DodgerBlue" Visibility="Collapsed" Margin="111,160,92,160" >
<TextBlock VerticalAlignment="Top" Height="120" Width="280" Text="No Network is currently availabe" TextAlignment="Center" TextWrapping="Wrap" Foreground="White" FontSize="28" />
<Button Margin="30, 80" Height="60" Width="100" Content="OK" FontSize="18" Click="Ok_Click"/>
<Button Margin="150, 80" Height="60" Width="100" Content="Retry" FontSize="18" Click="Retry_Click"/>
</Canvas>
Well as most of you experienced guys would have guessed, the canvas is buried inside the listbox and is not accessible when there is no network connectivity. So I have a blank page with the canvas but the user is not able to click on Ok or Retry. Please help
Please do let me know if there is any other approach to solve this problem. I tried Popup but I cant Navigate to the main page from a pop-up since that is a user control page. Any help is higly appreciated
Well, I placed my Canvas below the ListBox and the problem was solved. I didn't know that positioning of the controls in the XAML would have so much effect ...
The order in which elements are rendered in Silverlight is determined firstly by where they appear in the visual object hierarchy and secondly by their ZIndex property.
The Canvas has a third attached property named ZIndex that you can use to override the default layering of elements. Although this Canvas.ZIndex attached property is defined by the Canvas class, it actually works with any type of panel.
You can also try Canvas.ZIndex property:
Canvas.ZIndex Attached Property
What you do is a wrong practice and not at all recommended.
ChildWindow is the class you should use to display such kind of dialog.
Using a Popup is also another approach you can use.
NOTE: I know the simplest approach would be to use MessageBox.Show(), but it would create a popup out of silverlight frame and does not allow theming/styling and other customizations.

WPF Design question

Lets say i am developing a chat, first you come to a login window and when your logged in i want to use the same window but chaning the control :P how would be the best way to desight this?
is there any good way to implement this what root element should i use?
Thanks a lot!!
Take a look at Josh Smith's article in MSDN magazine (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx). He describes an interesting method where you have a content presenter on your main window use data templates to switch out what the window is showing.
If you want to do this all within the same window, you could use a Grid as the root element and host a login element (possibly another grid for layout) and the chat window. These elements would stack on top of one another, depending upon the order in which you declare them. To hide the chat element initially, set its Visibility to Collapsed
You could then have the login element's Visibility set to Collapsed when the user submits their login details, and have the chat element's Visibility set to Visible.
I did something similar once and it worked well for me.
Hope that helps.
EDIT I knocked this together in Kaxaml for you to play with (and because I like playing with XAML):
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Border x:Name="_loginForm" BorderBrush="#888" BorderThickness="3" CornerRadius="5"
HorizontalAlignment="Center" VerticalAlignment="Center" Padding="10" Visibility="Visible">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Height="30">Welcome to chat</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0">User Name</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="_userName" />
<TextBlock Grid.Row="2" Grid.Column="0">Password</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="_password"></TextBox>
<Button Grid.Row="3" Grid.Column="1">Log In</Button>
</Grid>
</Border>
<DockPanel x:Name="_chatForm" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" LastChildFill="True" Visibility="Collapsed">
<DockPanel DockPanel.Dock="Bottom" LastChildFill="True" Height="70">
<Button DockPanel.Dock="Right" Width="70">_Send</Button>
<TextBox x:Name="_input" HorizontalAlignment="Stretch">Hello world</TextBox>
</DockPanel>
<ListBox x:Name="_messageHistory" />
</DockPanel>
</Grid>
</Page>
Initially the element _loginForm is visible. You'd attach a handler for the Log In button's Click event that would hide it, and show the _chatForm instead.
This example shows usage of several layout controls -- the Grid, DockPanel and StackPanel.
Alternatively, you can use a StackPanel for your layout. As a simple example, you can have 2 elements in your panel; a custom login control as well as the chat 'display' control. After successfully logging in, remove the custom login control from your stack so only the chat is visible.
It's WPF! Animate them in and out of view...you can do that now. There's a collaborative project on Google Code called Witty (a desktop Twitter client written in WPF), and they do something really cool that you might want to borrow from. Come to think of it, there's another WPF Twitter client (blu) that does similar animations that you might want to look at.
In Witty, the Settings dialog is a normal window, but when you switch between the tabs, a storyboard slides the part of the window you requested into view. I haven't debugged the app at this level, but I'm assuming that they have a horizontal StackPanel populated with containers that are fixed to the height and width of the dialog, and they slide them in and out with a storyboard.
Take a look at both of these apps for ideas. You may want to do something similar, but being that this is a WPF app, the sky is really the limit.
Witty
blu
There are already some answers here on, how to swap two elements at the view level. This post offers a way to more fundamentally create a modular application design with interchangeable views.
You could take a look at the Composite Application Library. It is a small library (developed by Microsoft) that among other things aid in making your application more modular. With this you can define regions of your GUI, that can have interchangeable views.
In your containing xaml import the CAL namespace and use RegionManager to define a region:
<Window ...
xmlns:cal="http://www.codeplex.com/CompositeWPF"
...>
...
<ItemsControl cal:RegionManager.RegionName="MyRegion" />
...
Then you can swap views in this region, preferably in a module:
_regionManager.Regions["MyRegion"].Add(new LoginView());
...swap...
_regionManager.Regions["MyRegion"].Add(new ChatView());
This is of course just an outline of what you can do. In order to implement this solution, you will have to look further in to CAL. It has great documentation and lots of examples to learn from.
I think a more intuitive solution is to use a Frame control as the base control of your window - and to use the NavigateService to change the source of the Frame to different Page controls (which could be defined in separate assemblies, or in your same project as different XAML files).
Your Window:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Frame Source="LogonPage.xaml" NavigationUIVisibility="Hidden" />
</Window>
And your separate LogonPage:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Logon">
<!-- Your content of the page goes here... -->
</Page>

Categories