I want to override the Xamarin Forms Control Picker so it display "No entries" if the binded collection is empty.
I tried:
<Picker
x:Class="v.App.Styling.Controls.vPicker"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:v.App.Styling.Controls;assembly=v.App"
x:Name="CustomPicker"
mc:Ignorable="d" >
<Picker.Style>
<Style TargetType="controls:vPicker">
<Setter Property="ControlTemplate">
<Setter.Value>
<ControlTemplate>
<controls:vStackLayout >
<ContentPresenter
IsVisible="{Binding ItemsSource.Count, Converter={StaticResource HasItemsToBoolConverter}, ConverterParameter=0}"
Content="{TemplateBinding Content}" />
<controls:vEntry
IsVisible="{Binding ItemsSource, Converter={StaticResource HasNoItemsToBoolConverter}"
IsEnabled="False"
TextColor="{StaticResource ColorTextSecondary}"
Text="No entries" />
</controls:vStackLayout>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Picker.Style>
</Picker>
But I get
Error XFC0001: Cannot resolve property "ControlTemplate" on type "vPicker (property missing or missing accessors)". (13, 21)
I'm not sure what I'm doing wrong...
Another solution that I offered someone trying to create their own style, but for a button. The underlying premise is the same. You have something special you want to do based on a default class (or derived).
I would take the picker control, subclass it and add your own dependency property boolean or visibility so it can be used within your own custom style template. A dependency property is instance specific, so if you had one picker that HAD entries, its flag would be different than another that had NO entries.
Now, that said,
Here is one source to start about your own templates / styles
But this one goes into an elaborate control template for a picker. You could build your own simplified and have your visible vs not context defined once as a style. Then when you define your combobox picker control, just have it reference the given style you declare. Having this style in a ResourceDictionary and available system wide can help all instances have the same look and feel without duplicating all over.
Update here
You could use a ContentView to write a custom control, as the picker doesn't have a ControlTemplate property. You could create your own custom picker view using ContentView, such like this:
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PickerControlTemplate74952715.PickerView"
x:Name="PickerView">
<ContentView.Content>
...
<controls:vStackLayout >
<ContentPresenter
IsVisible="{Binding ItemsSource.Count, Converter={StaticResource HasItemsToBoolConverter}, ConverterParameter=0}"
Content="{TemplateBinding Content}" />
<controls:vEntry
IsVisible="{Binding ItemsSource, Converter={StaticResource HasNoItemsToBoolConverter}"
IsEnabled="False"
TextColor="{StaticResource ColorTextSecondary}"
Text="No entries" />
</controls:vStackLayout>
</ContentView.Content>
For more info, you could refer to Xamarin.Forms control templates and Create a custom control
===============
you could use data bindings to make it.
In the .xaml for Picker:
<Picker x:Name="picker"
ItemsSource="{Binding ItemCollection}"
IsVisible="{Binding IsVisible}"
Title="Select a monkey"
TitleColor="Red">
</Picker>
And in ViewModel just add some logic like this:
public Command ClickedCommand // i define a button to add item to ItemCollection as a demo
{
get
{
return new Command(() =>
{
ItemCollection.Add(count);
count++;
if(ItemCollection.Count > 0)
{
IsVisible = true;
}
});
}
}
Hope it works for you.
Related
So I'm trying to make a simple navigation using MVVM in Xamarin forms, and people suggested that I used the control template with a content presenter.
So far so good.
I made the control template, but I'm not sure how to bind content presenter to my buttons so it changes when I click them.
App.Xaml
<Application.Resources>
<!-- Application resource dictionary -->
<ResourceDictionary>
<ControlTemplate x:Key="ThemeMaster">
<StackLayout>
<Label Text="App name" BackgroundColor="Blue"></Label>
<ContentPresenter x:Name="ContentPresenter"
Content="{Binding changeContentCommand}">
</ContentPresenter>
<Button Text="Click me" Command="{Binding changeContentButtonCommand}"></Button>
</StackLayout>
</ControlTemplate>
When I open the program contentpresenter starts showing the mainPage as it should, but what should I write in MainViewModel.cs too change contentpresenter too lets say LeaderBoardPage?
I think you should create different ControlTemplate for your different content.
I am writing a WPF control that is meant to be a container in the same way Border and ScrollViewer are containers. It is called EllipsisButtonControl, and it is supposed to place an ellipsis button to the right of its content. Here's an example of how I intend for it to be used:
<local:EllipsisButtonControl>
<TextBlock Text="Testing" />
</local:EllipsisButtonControl>
Here is the XAML for EllipsisButtonControl:
<ContentControl
x:Class="WpfApplication1.EllipsisButtonControl"
x:Name="ContentControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" Content="{Binding ElementName=ContentControl, Path=Content}" />
<Button Grid.Column="1" Command="{Binding ElementName=ContentControl, Path=Command}" Margin="3,0" Width="30" Height="24" MaxHeight="24" VerticalAlignment="Stretch" Content="..." />
</Grid>
</ContentControl>
And here is the code behind:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class EllipsisButtonControl
{
public EllipsisButtonControl()
{
InitializeComponent();
}
public static string GetCommand(DependencyObject obj)
{
return (string)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, string value)
{
obj.SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached(
name: "Command",
propertyType: typeof(ICommand),
ownerType: typeof(EllipsisButtonControl),
defaultMetadata: new UIPropertyMetadata());
}
}
This doesn't work. It crashes the Designer with a System.Runtime.Remoting.RemotingException.
I believe the binding on the ContentPresenter of the EllipsisButtonControl XAML is wrong, but I don't know how to make it right. What is the appropriate syntax to make that line reference the control's content? (e.g. The TextBlock defined in the usage example)
Edit:
poke provided a comprehensive answer below (including working code), but for the benefit of others who might share my initial misunderstanding, let me summarize the key concept here: A container control cannot "place content", per se. It achieves the desired effect by defining a template that modifies the way the calling XAML presents the content. The rest of the solution follows from that premise.
<local:EllipsisButtonControl>
<TextBlock Text="Testing" />
</local:EllipsisButtonControl>
This does set the Content of your user control. But so does the following in the user control’s XAML:
<ContentControl …>
<Grid>
…
</Grid>
</ContentControl>
The calling XAML has precendence here, so whatever you do inside that user control’s XAML is actually ignored.
The solution here is to set the template of the user control. The template, in this case the control’s control template, determines how the control itself is rendered. The simplest template for a user control (and also its default) is just using a ContentPresenter there, but of course, you want to add some stuff around that, so we have to overwrite the template. This generally looks like this:
<ContentControl …>
<!-- We are setting the `Template` property -->
<ContentControl.Template>
<!-- The template value is of type `ControlTemplate` and we should
also set the target type properly so binding paths can be resolved -->
<ControlTemplate>
<!-- This is where your control code actually goes -->
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Now this is the frame you need to make this work. However, once you’re inside the control template, you need to use the proper binding type. Since we are writing a template and want to bind to properties of the parent control, we need to specify the parent control as the relative source in bindings. But the easiest way to do that is to just use the TemplateBinding markup extension. Using that, a ContentPresenter can be placed like this inside the ControlTemplate above:
<ContentPresenter Content="{TemplateBinding Content}" />
And that should be all you need here in order to get the content presenter working.
However, now that you use a control template, of course you need to adjust your other bindings too. In particular the binding to your custom dependency property Command. This would generally look just the same as the template binding to Content but since our control template is targetting the type ContentControl and a ContentControl does not have your custom property, we need to explicitly reference your custom dependency property here:
<Button Command="{TemplateBinding local:EllipsisButtonControl.Command}" … />
Once we have that, all the bindings should work fine. (In case you are wondering now: Yes, the binding always targets the static dependency property on the type)
So, to sum this all up, your custom content control should look something like this:
<ContentControl
x:Class="WpfApplication1.EllipsisButtonControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1"
d:DesignHeight="30" d:DesignWidth="300" mc:Ignorable="d">
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Grid>
<ContentPresenter Grid.Column="0"
Content="{TemplateBinding Content}" />
<Button Grid.Column="1" Content="…"
Command="{TemplateBinding local:EllipsisButtonControl.Command}" />
</Grid>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Try replacing this line:
<ContentPresenter Grid.Column="0" Content="{Binding ElementName=ContentControl, Path=Content}" />
With this
<ContentPresenter Grid.Column="0" Content={Binding Content} />
In your existing code you are making this ContentPresenter display the generated content of EllipsesButtonControl, which includes the ContentPresenter which must render the generated content of ElipsesButtonControl which includes the ContentPresenter..... Unlimited recursion.
The XAML of your EllipsisButtonControl already sets its Content to the top-level Grid. What you probably wanted is to create a ControlTemplate, e.g. like this:
<ContentControl x:Class="WpfApplication1.EllipsisButtonControl"
x:Name="ContentControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="300">
<ContentControl.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0"
Content="{Binding ElementName=ContentControl, Path=Content}"/>
<Button Grid.Column="1"
Command="{Binding ElementName=ContentControl, Path=Command}"
Margin="3,0" Width="30" Height="24" MaxHeight="24"
VerticalAlignment="Stretch" Content="..." />
</Grid>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
I was trying to follow this instruction on how to do it, but I'm just starting out with WPF.
How do I do this using a UserControl that i can reuse in different TabControls?
Also which one is the "Header" ContentPresenter in the TabControl Style?
Below is the instruction found at
https://github.com/MahApps/MahApps.Metro/issues/281
The other way is to modify/create a style - the issue then is hooking
it up to an actual 'close' event in a generic fashion.
If you look at the TabControl style, you'll see the "Header"
ContentPresenter. If you wrap that in a stackpanel and add a button
like so:
<StackPanel Orientation="Horizontal">
<Label x:Name="root" FontSize="26.67">
<ContentPresenter ContentSource="Header" RecognizesAccessKey="True" />
</Label>
<Button Content="X" />
</StackPanel>
You get :
If you have that in your Window or UserControl (rather than a resource
dictionary), you can wire that up so Click can fire and you can then
remove the item from the databound collection or directly from the
TabControl.
The easiest way is to use the MetroTabItem. It comes with the property CloseButtonEnabled to enable/disable the close button. You can also bind a command to the CloseTabCommand and CloseTabCommandParameter.
<TabControl xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls">
<Controls:MetroTabItem Header="The Header of the TabItem"
CloseButtonEnabled="True"
CloseTabCommand="{Binding CloseTabCommand}"
CloseTabCommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Header}">
<!-- your content of the TabItem -->
</Controls:MetroTabItem>
</TabControl>
Hope this helps.
What is the difference between
ControlTemplate
DataTemplate
HierarchalDataTemplate
ItemTemplate
Control Template
A ControlTemplate specifies the visual structure and visual behavior of a control. You can customize the appearance of a control by giving it a new ControlTemplate. When you create a ControlTemplate, you replace the appearance of an existing control without changing its functionality. For example, you can make the buttons in your application round rather than the default square shape, but the button will still raise the Click event.
An Example of ControlTemplate would be
Creating a Button
<Button Style="{StaticResource newTemplate}"
Background="Navy"
Foreground="White"
FontSize="14"
Content="Button1"/>
ControlTemplate for Button
<Style TargetType="Button" x:Key="newTemplate">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="RootElement">
<!--Create the SolidColorBrush for the Background
as an object elemment and give it a name so
it can be referred to elsewhere in the control template.-->
<Border.Background>
<SolidColorBrush x:Name="BorderBrush" Color="Black"/>
</Border.Background>
<!--Create a border that has a different color by adding smaller grid.
The background of this grid is specificied by the button's Background
property.-->
<Grid Margin="4" Background="{TemplateBinding Background}">
<!--Use a ContentPresenter to display the Content of
the Button.-->
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="4,5,4,4" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
More about ControlTemplate
Data Templates
Data Template are a similar concept as Control Templates. They give you a very flexible and powerful solution to replace the visual appearance of a data item in a control like ListBox, ComboBox or ListView. WPF controls have built-in functionality to support the customization of data presentation.
An Example for the DataTemplate would be
<!-- Without DataTemplate -->
<ListBox ItemsSource="{Binding}" />
<!-- With DataTemplate -->
<ListBox ItemsSource="{Binding}" BorderBrush="Transparent"
Grid.IsSharedSizeScope="True"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Key" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
<TextBox Grid.Column="1" Text="{Binding Value }" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
More about DataTemplates and Triggers
Item Templates
You use the ItemTemplate to specify the visualization of the data objects. If your ItemsControl is bound to a collection object and you do not provide specific display instructions using a DataTemplate, the resulting UI of each item is a string representation of each object in the underlying collection.
An Example for Item Template would be
<ListBox Margin="10" Name="lvDataBinding">
<ListBox.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="Name: " />
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
<TextBlock Text=", " />
<TextBlock Text="Age: " />
<TextBlock Text="{Binding Age}" FontWeight="Bold" />
<TextBlock Text=" (" />
<TextBlock Text="{Binding Mail}" TextDecorations="Underline" Foreground="Blue" Cursor="Hand" />
<TextBlock Text=")" />
</WrapPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When you set an ItemTemplate on an ItemsControl, the UI is generated as follows (using the ListBox as an example):
During content generation, the ItemsPanel initiates a request for the ItemContainerGenerator to create a container for each data item. For ListBox, the container is a ListBoxItem. The generator calls back into the ItemsControl to prepare the container.
Part of the preparation involves the copying of the ItemTemplate of the ListBox to be the ContentTemplate of the ListBoxItem.
Similar to all ContentControl types, the ControlTemplate of a ListBoxItem contains a ContentPresenter. When the template is applied, it creates a ContentPresenter whose ContentTemplate is bound to the ContentTemplate of the ListBoxItem.
Finally, the ContentPresenter applies that ContentTemplate to itself, and that creates the UI.
If you have more than one DataTemplate defined and you want to supply logic to programmatically choose and apply a DataTemplate, use the ItemTemplateSelector property.
The ItemsControl provides great flexibility for visual customization and provides many styling and templating properties. Use the ItemContainerStyle property or the ItemContainerStyleSelector property to set a style to affect the appearance of the elements that contain the data items. For example, for ListBox, the generated containers are ListBoxItem controls; for ComboBox, they are ComboBoxItem controls. To affect the layout of the items, use the ItemsPanel property. If you are using grouping on your control, you can use the GroupStyle or GroupStyleSelector property.
For more information, see Data Templating Overview.
ControlTemplaes defines the "look" and the "behavour" of a control. A button is rectangular by default. A ListBox has a white background by default. These are all defineed by Control's ControlTemple.
A DataTemplae helps a Control with Layout of Data that it holds. If a list of Users are added to listbox and you would like UserName to show up before UserPassword then you will define this inside a DataTemples. DataTemples is assigned to the ItemTemplate (4) Property of the ListBox.
HierarchalDataTemplte is same as DataTemples except that it deal with Hierarchal Data Source. It is commonlly used with TreeView Control.
I am attempting to convert a bing map implementation that uses standard PushPins in order to populate the map, but I need to add a tooltip to each pin. I found some options of how to do this on the website but the issue is I need the pushpins to be different from each other in a way that is dynamic. Based on the properties of each pin it must have a different background color.
The code already on this site all has the programmer use an image of the pushpin when they customize it.
So right now I need a way to either create a templated pushpin that is able to maintain the look and properties of a pushpin (so I can set background), while allowing a tooltip. Or instead having a regular pushpin have a tooltip or popup with it.
Any help would be appreciated!
Edited:
Control Template I am using
<ControlTemplate x:Key="NewPins" >
<Grid x:Name="pushPin" >
<Popup IsOpen="False" behaviors:RolloverPopup.HideDelay="0" behaviors:RolloverPopup.Target="{Binding ElementName=pushPin}" Margin="30,-20,0,0" >
<Border Background="White" BorderBrush="Black" CornerRadius="10" BorderThickness="1">
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding Title}" Foreground="Black" FontWeight="Bold" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" />
<TextBlock Text="{Binding Content}" Foreground="Black" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" />
</StackPanel>
</Border>
</Popup>
</Grid>
</ControlTemplate>
This is setting up the pin in C#
Pushpin pin = new Pushpin()
{
Location = new Location( Double.Parse(item.PinLat), Double.Parse(item.PinLong)),
Content=String.Concat( GetNewlineString(item.LocationName), GetNewlineString(item.CallerName), GetNewlineString(item.PhoneNumber)),
Template=(ControlTemplate)Application.Current.Resources["NewPins"],
Width = 50,
Height = 65,
};
And this is creating the Bing Map
<c:BingMapAdSmart
AnimationLevel="UserInput"
Pins="{Binding DashboardViewModel.MapPins}"
NavigationVisibility="Visible"
SetViewZoomFactor="0"
MaxZoomLevel="7"
Visibility="{Binding NavViewModel.IsViewTransitioning, Converter={StaticResource TrueToCollapsedConverter}}" />
I may not really understand your question correctly, but i assume you need pushpins that are being created dynamically based on a template right? And you want to be able to change the tooltip (content property i assume) independently.
If thats the case, first you need to put a template resource to your resources in xaml;
<phone:PhoneApplicationPage.Resources>
<ControlTemplate x:Key="template_name" TargetType="m:Pushpin">
...this is your design part you can compile this xaml via Expression
</ControlTemplate>
</phone:PhoneApplicationPage.Resources>
then you'll need pass this value to every pushpin you've created dynamically codebehind. On this stage you can also set their content property, since they don't have a notification property, i don't know if you mean this but content property is the similar one. You can edit them like you edit other stuff;
myPushPin.template = (ControlTemplate)This.Resources["template_name"];
myPushPin.Content = "Hello World!";
This stage may differ according where you put your resources if its in phone:PhoneApplicationPage.Resources
if you put in Application.Resources
use this;
myPushPin.template = (ControlTemplate)Application.Current.Resources["template_name"];
myPushPin.Content = "Hello World!";
This should work, i don't have bing maps API or WP7 tools installed on this computer so i can't test it but this should be ok.
Happy coding!
Edit:
So if you want to change the background of a pushpin you don't have to hold back, it doesn't matter whether it has a control template or not. Actually every control has one as default. You can change the background as you always do
myPushpin.Background = new SolidColorBrush(Colors.Blue);
I have done exactly what you describe. The way i did this makes the most sense to me. Here is what I did:
I created a custom Pushpin (i.e. UserControl). This Xaml defines my custom pushpin. It assumes this pushpin is to be data-bound to. One of the binded properties is background Color. This will easily satisfy your dynamic color issue.
In the bing map control i defined the following:
The MyPushpinTemplate is defined in the UserControl.Resources like this:
MyPushpinControl is the UserControl.
I also have a data model class (that implements INotifyPropertyChanged). This class is bound to an instance of MyPushpinControl. this data model class has all the properties and is data-binded to the UserControl.
This is technically all you need to know.
To satisfy your tooltip issue, I simply added a tooltip to one of the panels within my custom pushpin. Simple as that.
Until I have a better solution I have decided the only thing I can think to do is to create a number of different pins to use. I don't need an infinite color solution so about 15 different pins should do the trick. Messy but it will work.
I just solved this issue to my complete satisfaction. To accomplish this, you need to have to create a Pushpin style with a key. Then inside this pushpin you create a standard pushpin (you can use another style on that but don't let it look back to this style, I used default), and a popup to go along with it. An example is below, I am using a local tool to do easy rollover popups, otherwise its standard stuff + bind maps.
<Style TargetType="bingMaps:Pushpin" x:Key="NewPins2">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="bingMaps:Pushpin" >
<Grid x:Name="pushPin" >
<Border Width="50" Height="65" >
<bingMaps:Pushpin Background="{TemplateBinding Background}" />
</Border>
<Popup IsOpen="False" behaviors:RolloverPopup.HideDelay="0" behaviors:RolloverPopup.Target="{Binding ElementName=pushPin}" Margin="30,-20,0,0" >
<Border Background="White" BorderBrush="Black" CornerRadius="10" BorderThickness="1">
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding Title}" Foreground="Black" FontWeight="Bold" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" />
<TextBlock Text="{Binding Content}" Foreground="Black" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" />
</StackPanel>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>