How to use VisualStateManager with content Dialogue control in uwp - windows

Is there any way to use visualStateManager with content Dialogue control in uwp application.

Put all your popUp controls in the control as follow:
`<Grid Background="White">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000" />
</VisualState.StateTriggers>
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="750" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="BlueRect.Visibility" Value="Visible" />
<Setter Target="RedRect.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="500" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="BlueRect.Visibility" Value="Collapsed" />
<Setter Target="RedRect.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel>
<Rectangle x:Name="BlueRect" Width="50" Height="50" Fill="Blue" />
<Rectangle x:Name="RedRect" Width="50" Height="50" Fill="Red" />
<Button Content="Change Style" Width="500" Height="30" HorizontalAlignment="Center" VerticalAlignment="Bottom" Click="Button_Click" />
</StackPanel>
</Grid>`
Transfer event of user controls to contentdialog if there is any:
`public sealed partial class MyUserControl1 : UserControl
{
public delegate void MyEventHandler(object source, EventArgs e);
public static event MyEventHandler OnNavigateParentReady;
public MyUserControl1()
{
this.InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
OnNavigateParentReady(sender,null);
}
}`
Create contentDialog control and use the created user control there as follow:
` <Grid >
<local:MyUserControl1 />
</Grid>`
Now Handle the transferred events of your user control on contentDialog code behind as follow:
`public sealed partial class ContentDialog1 : ContentDialog
{
public ContentDialog1()
{
this.InitializeComponent();
MyUserControl1.OnNavigateParentReady += test;
}
private void test(object source, EventArgs e)
{
Button bt = (Button)source;
if (bt.IsEnabled == true)
{
this.Hide();
}
}
}`
Now simply make a call to your popUp(contentDialog) from where you want to.I made a call on the button click event as shown:
` ContentDialog1 popup = new ContentDialog1() { };
public uc_test()
{
this.InitializeComponent();
}
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
await popup.ShowAsync();
}`
Works fine for me and helped me to create a responsive popUp as it applies all the triggers that you applied on your user control when the main window shrink.
Thanks.

Related

Dynamic styling in .Net Maui/Xamarin

Let's say I want to display a calendar. Each day (DayViewModel) can have such attributes that should influence styling:
is day of current month
is weekend
is day available
And based on that I'd like to style my DayContentView like follows:
if day of current month -> opacity 1
if not current month -> opacity 0.5
if weekend -> background color is red
if available -> background color is green
Moreover the last one property ("is day available") can change based on user's action (clicked button "Check availability").
In other frameworks I'd create a few styles/style classes and assign them accordingly base on those flags. But since StyleClass is not bindable I cannot. Can I? Maybe there is some workaround.
Another option could be to create a separate style (using inheritance if needed) for all the combinations. But first of all the number of combinations raises like 2^n and the second issue is that I have no idea how to dynamically change whole styl for a view changing its name. Is it possible?
Finishing my quite long question: How to do it right/in a smart way? I don't want to store values of colors, font sizes, opacities etc. in a view model and bind all the values manually.
The same thing can be achieved using DataTriggers.
Result:
MainPage.xaml
<Window
x:Class="WpfApp6.MainWindow"
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:local="clr-namespace:WpfApp6"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<ItemsControl Margin="5" ItemsSource="{Binding Days}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:DayModel}">
<Border
Padding="10"
Width="200"
Height="100"
Margin="5">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsDayOfCurrentMonth}" Value="False">
<Setter Property="Opacity" Value="0.5" />
</DataTrigger>
<DataTrigger Binding="{Binding IsAvailable}" Value="True">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding IsWeekend}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel>
<TextBlock Text="{Binding IsDayOfCurrentMonth, StringFormat='IsDayOfCurrentMonth: {0}'}" />
<TextBlock Text="{Binding IsAvailable, StringFormat='IsAvailable: {0}'}" />
<TextBlock Text="{Binding IsWeekend, StringFormat='IsWeekend: {0}'}" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
DayModel.cs
public record DayModel(bool IsDayOfCurrentMonth, bool IsWeekend, bool IsAvailable);
MainViewModel.cs
public class MainViewModel
{
public ObservableCollection<DayModel> Days { get; } = new();
public MainViewModel()
{
//Create all possible cominations of days
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
Days.Add(new DayModel(i == 0, j == 0, k == 0));
}
}
}
}
}
EDIT: sharing style by multiple controls
Here's how the same Style with Triggers might be shared by multiple controls (two of the three TextBlocks in this example):
<DataTemplate DataType="{x:Type local:DayModel}">
<Border
Width="200"
Height="100"
Margin="5"
Padding="10"
Background="#eee">
<StackPanel>
<StackPanel.Resources>
<Style x:Key="ColoredTextBlock" TargetType="TextBlock">
<Setter Property="Foreground" Value="Gray" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsDayOfCurrentMonth}" Value="False">
<Setter Property="Opacity" Value="0.5" />
</DataTrigger>
<DataTrigger Binding="{Binding IsAvailable}" Value="True">
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding IsWeekend}" Value="True">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock Style="{StaticResource ColoredTextBlock}" Text="{Binding IsDayOfCurrentMonth, StringFormat='IsDayOfCurrentMonth: {0}'}" />
<TextBlock Style="{StaticResource ColoredTextBlock}" Text="{Binding IsAvailable, StringFormat='IsAvailable: {0}'}" />
<TextBlock Text="{Binding IsWeekend, StringFormat='IsWeekend: {0}'}" />
</StackPanel>
</Border>
</DataTemplate>
The result looks like this:
I planned to add an example as #ToolmakerStave suggested but I found a solution in the meantime that seems to be very nice so I decided to share it instead. The idea is as follows:
Declare view model that implements INotifyPropertyChanged
Create a XAML file and define there all the styles
In the code behind detect change of binding context (view model) and all its dynamically changing properties (IsAvailable) in my case
When a change is detected then create a style using styles defined in the XAML file applying them in the desired order (making updates)
Assign the final style to particular elements
So starting from my view model:
public class DayViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// To style
public bool IsCurrentMonth { get; set; }
public bool IsWeekend { get; set; }
public bool IsHoliday { get; set; }
private bool _isAvailable;
public bool IsAvailable
{
get => _isAvailable;
set
{
_isAvailable = value;
PropertyChanged?.Invoke(
this,
new PropertyChangedEventArgs(nameof(IsAvailable))
);
}
}
// To display
public string DayOfWeek { get; set; }
public int DayOfMonth { get; set; }
}
Assuming that only IsAvailable property can change after some user action.
Then I have a XAML view that defines all the needed styles but they are not used directly in this file. I'll use them in the code behind. All the elements that I need to style have x:Name property set to get a reference to them from the code:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:MyProject.Calendar.ViewModels"
x:Class="MyProject.Calendar.ContentViews.DayView"
x:DataType="vm:DayViewModel">
<ContentView.Resources>
<ResourceDictionary>
<!-- By default Border has opacity 0.3 -->
<Style TargetType="Border">
<Setter Property="Opacity" Value="0.3" />
</Style>
<!-- These styles are used from the code behind -->
<Style x:Key="CurrentMonthBorder" TargetType="Border">
<Setter Property="Opacity" Value="1.0" />
</Style>
<Style x:Key="WeekendBorder" TargetType="Border">
<Setter Property="BackgroundColor" Value="LightGray" />
</Style>
<Style x:Key="AvailableBorder" TargetType="Border">
<Setter Property="BackgroundColor" Value="Green" />
</Style>
<Style x:Key="HolidayLabel" TargetType="Label">
<Setter Property="TextColor" Value="DarkRed" />
</Style>
<!-- // These styles are used from the code behind -->
</ResourceDictionary>
</ContentView.Resources>
<Border x:Name="DayBorder">
<VerticalStackLayout HorizontalOptions="FillAndExpand">
<Label x:Name="DayOfWeekLabel" Text="{Binding DayOfWeek}" />
<Label x:Name="DayOfMonthLabel" Text="{Binding DayOfMonth}" />
</VerticalStackLayout>
</Border>
</ContentView>
Now a helper class that allows to update a style with another style:
public static class StyleExtension
{
public static Style Update(this Style style, Style otherStyle)
{
var result = new Style(style.TargetType);
var allSetters = style.Setters.Concat(otherStyle.Setters);
foreach (var setter in allSetters)
{
result.Setters.Add(setter);
}
return result;
}
public static Style UpdateIf(this Style style, bool condition, Style otherStyle)
{
return style.Update(condition ? otherStyle : new Style(style.TargetType));
}
}
Final part, the code behind:
public partial class DayView : ContentView
{
private DayViewModel _viewModel;
public DayView()
{
InitializeComponent();
BindingContextChanged += OnBindingContextChanged;
}
private void OnBindingContextChanged(object sender, EventArgs e)
{
_viewModel = BindingContext as DayViewModel;
_viewModel.PropertyChanged += OnAvailabilityChanged;
StyleDayBorder();
StyleDayOfWeekLabel();
StyleDayOfMonthLabel();
}
private void OnAvailabilityChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(DayViewModel.IsAvailable))
{
StyleDayBorder();
}
}
private void StyleDayBorder()
{
DayBorder.Style = new Style(typeof(Border))
.UpdateIf(_viewModel.IsCurrentMonth, GetStyle("CurrentMonthBorder"))
.UpdateIf(_viewModel.IsWeekend, GetStyle("WeekendBorder"))
.UpdateIf(_viewModel.IsAvailable, GetStyle("AvailableBorder"));
}
private void StyleDayOfWeekLabel()
{
DayOfWeekLabel.Style = new Style(typeof(Label))
.UpdateIf(_viewModel.IsHoliday, GetStyle("HolidayLabel"));
}
private void StyleDayOfMonthLabel()
{
DayOfMonthLabel.Style = new Style(typeof(Label))
.UpdateIf(_viewModel.IsHoliday, GetStyle("HolidayLabel"));
}
private Style GetStyle(string name)
{
return Resources[name] as Style;
}
}
And final thought after the final code:) If there is no simpler solution then it would be nice to be able to do it in the XAML like this (pseudocode):
<Label Text="{Binding Message}">
<Label.Styles>
<Style ShouldApply="{Binding IsError}" Style="{StaticResource ErrorMessage}" />
<Style ShouldApply="{Binding IsWarning}" Style="{StaticResource WarningMessage}" />
...
</Label.Styles>
</Label>
And then all the styles would be created applying one after another in the defined order based on the defined conditions.

Remove borders on custom renderer SearchBar for Xamarin Forms UWP

I am currently working with a UWP project in Xamarin Forms.
When i use the default SearchBar, it comes with a border that i wish to remove as well as add a rounded background.
I have setup the renderer and some code, but the border is still intact.
public class SearchBar_UWP : SearchBarRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
Control.Background = null;
Control.BorderBrush = null;
}
}
What am I missing in my UWP custom renderer code in order to remove the border and add a rounded background?
Remove border
You could copy the default style and modify BorderThickness property (in test i found we need to change the property on TextBox inside AutoSuggestBox ), then place the new style into Application.Resources , at last apply the style in custom renderer .
custom style in App
<Application.Resources>
<Style TargetType="AutoSuggestBox" x:Key="myStyle">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="TextBoxStyle" Value="{StaticResource AutoSuggestBoxTextBoxStyle}" />
<Setter Property="UseSystemFocusVisuals" Value="{ThemeResource IsApplicationFocusVisualKindReveal}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="AutoSuggestBox">
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Orientation">
<VisualState x:Name="Landscape" />
<VisualState x:Name="Portrait" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox x:Name="TextBox"
Style="{TemplateBinding TextBoxStyle}"
PlaceholderText="{TemplateBinding PlaceholderText}"
Header="{TemplateBinding Header}"
Width="{TemplateBinding Width}"
BorderThickness="0"
ScrollViewer.BringIntoViewOnFocusChange="False"
Canvas.ZIndex="0"
Margin="0"
DesiredCandidateWindowAlignment="BottomEdge"
UseSystemFocusVisuals="{TemplateBinding UseSystemFocusVisuals}" />
<Popup x:Name="SuggestionsPopup">
<Border x:Name="SuggestionsContainer">
<ListView x:Name="SuggestionsList"
Background="{ThemeResource AutoSuggestBoxSuggestionsListBackground}"
BorderThickness="{ThemeResource AutoSuggestListBorderThemeThickness}"
BorderBrush="{ThemeResource AutoSuggestBoxSuggestionsListBorderBrush}"
DisplayMemberPath="{TemplateBinding DisplayMemberPath}"
IsItemClickEnabled="True"
ItemTemplate="{TemplateBinding ItemTemplate}"
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
MaxHeight="{ThemeResource AutoSuggestListMaxHeight}"
Margin="{ThemeResource AutoSuggestListMargin}"
Padding="{ThemeResource AutoSuggestListPadding}" />
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
custom renderer
[assembly: ExportRenderer(typeof(Xamarin.Forms.SearchBar), typeof(MyRenderer))]
namespace App1.UWP
{
class MyRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if(Control != null)
{
Control.Style = App.Current.Resources["myStyle"] as Windows.UI.Xaml.Style;
}
}
}
}
Add Rounded background
Warp SearchBar into Frame , and set CornerRadius on Frame .
<Frame HeightRequest="100" WidthRequest="100" VerticalOptions="Center" HorizontalOptions="Center" BorderColor="Red" CornerRadius="50">
<SearchBar />
</Frame>

Xamarin: Visual State Manager and custom properties

I am trying to set a custom property on a custom control using the Visual State Manager but I'm not having any luck so far. My custom control is just a label with an additional bindable property on it.
public class SelectableLabel : Label
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableLabel), false);
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
SetValue(IsSelectedProperty, value);
}
}
I use this control inside a CollectionView to toggle the IsSelected property when the control enters the Selected visual state.
<CollectionView
x:Name="cv"
ItemsSource="{Binding Names}"
SelectionMode="Multiple"
SelectedItems="{Binding SelectedNames, Mode=TwoWay}"
VerticalOptions="Fill">
<CollectionView.ItemTemplate>
<DataTemplate>
<local:SelectableLabel
x:Name="lblName"
Text="{Binding First}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Selected">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableLabel>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
When I run this on an iOS simulator, I'm not seeing the setter being fired when the visual state changes to Selected. If I change the property in the setter to BackgroundColor or Text, I'm seeing the expected behavior. The problem seems specific to the custom property. I looked at the documentation for the Setter.Property and it states that the Setter can be applied to a BindableProperty which IsSelected is. Am I doing something wrong or does the VSM not support this functionality?
Edit: The CollectionView part of this example is irrelevant. The same issue happens with this code.
public class SelectableEntry : Entry
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false);
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
var color = value ? Color.LightBlue : Color.LightPink;
SetValue(IsSelectedProperty, value);
SetValue(BackgroundColorProperty, color);
}
}
}
Here is the corresponding XAML. The background color changes when the first custom Entry control receives focus while the second does not. I also don't see my WriteLine statement in the console.
<local:SelectableEntry Text="First">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="BackgroundColor"
Value="LightBlue" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Focused">
<VisualState.Setters>
<Setter
Property="BackgroundColor"
Value="LightPink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
<local:SelectableEntry Text="Second">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Focused">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
I have tried with Bindable Property to check whether property be invoked in VisualStateManager . That's regrettable, it can not be invoked even in propertyChanged method . I think maybe bindable property can not work in VisualStateManager.
Custom Entry Code as follow :
public class SelectableEntry : Entry
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false ,propertyChanged:changedMethod);
private static void changedMethod(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine($"MDO: {oldValue}.IsSelected_set={newValue}");
}
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
var color = value ? Color.LightBlue : Color.LightPink;
SetValue(IsSelectedProperty, value);
SetValue(BackgroundColorProperty, color);
}
}
}
Solution:
However , there is a Attached Properties that can be used in Style.Setters. Then you can also have a try with it in VisualState.Setters .It also will work .
Attached property class Code as follow :
public class SelectableEntryStyle
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.CreateAttached("IsSelected", typeof(bool), typeof(SelectableEntryStyle), false,propertyChanged:onChangedMethod);
private static void onChangedMethod(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine($"MDO:IsSelected_set={newValue}");
var color = (bool)newValue ? Color.LightBlue : Color.LightPink;
var entry = bindable as Entry;
entry.SetValue(Entry.BackgroundColorProperty, color);
}
public static bool GetIsSelected(BindableObject view)
{
return (bool)view.GetValue(IsSelectedProperty);
}
public static void SetIsSelected(BindableObject view, bool value)
{
view.SetValue(IsSelectedProperty, value);
}
}
The code of Xaml as follow :
<local:SelectableEntry FontSize="18" Placeholder="Bindable Property">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
<Entry Placeholder="Attached Property">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="local:SelectableEntryStyle.IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="local:SelectableEntryStyle.IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Then console can print log when Entry is Normal or Focused .
02-18 14:26:27.360 I/mono-stdout(26014): MDO:IsSelected_set=True
02-18 14:26:28.675 I/mono-stdout(26014): MDO:IsSelected_set=False
The effects :

WP7 UI controls like button and listbox events are not fired, in a user control class

I have a user control and in that user control there are ui controls like button and listbox, I have attached click and selection changed events of these controls from xaml and also tried by attaching them programmatically, but the events are not being fired.
any kind of help will be appreciated ,
Many thanks
here is the code .cs and xaml
<UserControl
x:Class="VisioLink.Views.MagazineListPage"
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:views="clr-namespace:VisioLink.Views"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True"
Loaded="PhoneApplicationPage_Loaded"
xmlns:local="clr-namespace:VisioLink.Views">
<UserControl.Resources>
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="LayoutRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="LayoutRoot">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ContentContainer"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="ContentContainer"
Storyboard.TargetProperty="Foreground"
Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="White"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="border"
Storyboard.TargetProperty="Background"
Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="LightBlue"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel x:Name="border" Orientation="Horizontal">
<!--<CheckBox x:Name="checkBox" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=IsSelected, Mode=TwoWay}" DataContext="{TemplateBinding IsSelected}" Visibility="{Binding Converter={StaticResource BooleanToVisibilityConverter}}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>-->
<ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="White">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Flick="GestureListener_Flick" />
</toolkit:GestureService.GestureListener>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="firstCol" Width="40"></ColumnDefinition>
<ColumnDefinition x:Name="secondCol" Width="10"></ColumnDefinition>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<views:LeftMenuControl Visibility="Collapsed" x:Name="leftMenuControl" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="1" ></views:LeftMenuControl>
<Button x:Name="flipBtn" Click="flip_click" Grid.Column="0" Height="70" Grid.Row="1" VerticalAlignment="Center">
<Button.Background>
<ImageBrush ImageSource="file:///C:/VisioLink/Resources/Images/next.png" />
</Button.Background>
</Button>
<Rectangle Fill="Black" Width="1" Grid.Column="1" Grid.Row="1" VerticalAlignment="Stretch" />
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Grid.Column="2" Margin="0,0,0,0">
<TextBlock x:Name="ApplicationTitle" Foreground="Black" Text="Nyhet" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<StackPanel x:Name="ContentPanel" Grid.Row="1" Grid.Column="2" Margin="5,12,12,0">
<ListBox x:FieldModifier="public" x:Name="databoundListBoxMag" SelectionChanged="listBox1_SelectionChanged" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" SelectionMode="Single">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Margin="7"
BorderThickness="1"
BorderBrush="SteelBlue"
CornerRadius="3" x:Name="border1">
<StackPanel Width="450" x:Name="listItemPanel" Orientation="Vertical" Height="100" Margin="10,10,10,10">
<StackPanel x:Name="firstStack" Orientation="Horizontal">
<Image x:Name="magImage" Height="40" Width="40" Visibility="Collapsed" Source="Example4.PNG"></Image>
<TextBlock x:Name="itemone" FontWeight="Bold" TextAlignment="Left" Foreground="Black" Margin="0,0,0,0" HorizontalAlignment="Left" FontSize="22" Text="{Binding name}" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<TextBlock x:Name="itemtwo" TextAlignment="Left" Foreground="Black" HorizontalAlignment="Left" Margin="0,0,0,0" FontSize="16" Text="{Binding content}" Style="{StaticResource PhoneTextNormalStyle}"/>
<!--<phone:WebBrowser Name="webBrowserContent" ScriptNotify="wb1_ScriptNotify" IsScriptEnabled="True" Source="http://www.bing.com" >
</phone:WebBrowser>-->
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<!--<ListBoxItem Style="{StaticResource ListBoxItemStyle1}">
<StackPanel x:Name="itemPanel" Grid.Row="0" Margin="0,0,0,28">
<TextBlock Height="72" HorizontalAlignment="Left" Name="nameBlock" Text="{Binding name}" VerticalAlignment="Top" Width="379" />
<TextBlock Height="72" HorizontalAlignment="Left" Name="detailBlock" Text="{Binding detail}" VerticalAlignment="Top" Width="379" />
</StackPanel>
</ListBoxItem>-->
</ListBox>
</StackPanel>
</Grid>
<!--Sample code showing usage of ApplicationBar-->
<!--<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="MenuItem 1"/>
<shell:ApplicationBarMenuItem Text="MenuItem 2"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>-->
and here is its .cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Data;
using System.Globalization;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Resources;
using System.Text.RegularExpressions;
using VisioLink.DTO;
namespace VisioLink.Views
{
public partial class MagazineListPage : UserControl
{
public MagazineListPage()
{
InitializeComponent();
}
List<Article> articles = new List<Article>();
public int CatalogId { get; set; }
public string ContentToSee = string.Empty;
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
databoundListBoxMag.SelectionChanged += new SelectionChangedEventHandler(listBox1_SelectionChanged);
// List<Magazine> listMag = new List<Magazine>();
// listMag.Clear();
if(IsolatedStorageSettings.ApplicationSettings.Contains("magazineListPage"))
{
IsolatedStorageSettings.ApplicationSettings.TryGetValue("magazineListPage", out ContentToSee);
DoProcessingOnData();
}
else
{
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("http://device01.e-pages.dk/content/default4.php?customer=kaleva&catalog=" + CatalogId, UriKind.RelativeOrAbsolute));
}
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
ContentToSee = e.Result;
IsolatedStorageSettings.ApplicationSettings.Add("magazineListPage", e.Result);
DoProcessingOnData();
}
private void DoProcessingOnData()
{
leftMenuControl.parent = this;
leftMenuControl.contentToSee = ContentToSee != "" ? ContentToSee : "";
XDocument doc = XDocument.Parse(ContentToSee);
XElement content = null;
foreach (XElement element in doc.Descendants("article"))
{
XElement refId = element.Element("refid");
XElement page = element.Element("page");
XElement title = element.Element("title");
XElement images = element.Element("images");
XElement image = null;
if (images != null)
{
foreach (XElement img in images.Descendants("image"))
{
image = img.Element("medium");
}
}
content = element.Element("content");
String detail = Regex.Replace(content.Value, #"<[^>]*>", String.Empty);
String cont = "";
if (detail.Length > 300)
{
cont = detail.Substring(0, 300) + ".....";
}
else
{
cont = detail;
}
Article art = new Article(title.Value, cont);
art.detail = detail;
art.page = Convert.ToInt32(page.Value);
art.refId = refId.Value;
if (image != null)
{
art.imageSrc = image.Value;
}
articles.Add(art);
}
this.databoundListBoxMag.ItemsSource = articles;
}
private void wb1_ScriptNotify(object sender, NotifyEventArgs e)
{
// The browser is zooming the text so we need to
// reduce the pixel size by the zoom level...
// Which is about 0.50
}
private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Article art = databoundListBoxMag.SelectedItem as Article;
string id = art.refId;
MagazinePage page = new MagazinePage();
page._id = id;
page._content = art.detail;
page._title = art.name;
this.Content = page;
}
private void GestureListener_Flick(object sender, FlickGestureEventArgs e)
{
if (e.Angle > 90 && e.Angle < 270)
{
// MessageBox.Show("right");
GridLength len = new GridLength(50);
firstCol.Width = len;
flipBtn.Visibility = Visibility.Visible;
leftMenuControl.Visibility = Visibility.Collapsed;
}
else
{
// MessageBox.Show("left");
}
}
private void flip_click(object sender, RoutedEventArgs e)
{
GridLength len = new GridLength(200);
firstCol.Width = len;
flipBtn.Visibility = Visibility.Collapsed;
leftMenuControl.Visibility = Visibility.Visible;
}
private void SaveHTMLFile2()
{
string fileName = "TextFile2.htm";
IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication();
if (isolatedStorageFile.FileExists(fileName) == true)
{
isolatedStorageFile.DeleteFile(fileName);
}
StreamResourceInfo streamResourceInfo = Application.GetResourceStream(new Uri(fileName, UriKind.Relative));
using (BinaryReader binaryReader = new BinaryReader(streamResourceInfo.Stream))
{
byte[] data = binaryReader.ReadBytes((int)streamResourceInfo.Stream.Length);
using (BinaryWriter bw = new BinaryWriter(isolatedStorageFile.CreateFile(fileName)))
{
bw.Write(data);
bw.Close();
}
}
}
}
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return System.Convert.ToBoolean(value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.Equals(Visibility.Visible);
}
}
}
You need to bubble click events through UserControl. See my answer on this topic: Custom events in XAML on my UserControl

wp7: how to create image button and bind template to ImageSource dependency property

I am trying to create a silverlight imagebutton control. the xaml and code-behind will follow, but my problem is that I get an 'unspecified error' when i try a TemplateBinding to the image's source property. I'm hoping that someone can help me preserve my last shreds of sanity and last few scraps of hair on my head.
XAML:
<Grid x:Name="LayoutRoot">
<Button x:Name="btn" Click="Cancel_Click" Margin="0,0,10,10"
Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" >
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background"
Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush"
Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush"
Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background"
Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="33"
Margin="{StaticResource PhoneTouchTargetOverhang}">
<Image x:Name="image" Source="{TemplateBinding IconSource}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}" />
</Border>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</UserControl>
Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace sltest.controls
{
public partial class ImageButtonControl : UserControl
{
public ImageButtonControl()
{
InitializeComponent();
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
}
public double ImageWidth { get; set; }
public double ImageHeight { get; set; }
public static readonly DependencyProperty IconSourceProperty =
DependencyProperty.Register("IconSource", typeof(ImageSource), typeof(ImageButtonControl), null);
public ImageSource IconSource
{
get { return base.GetValue(IconSourceProperty) as ImageSource; }
set { base.SetValue(IconSourceProperty, value); }
}
}
}
I'm using the following implementation which contains additional functionality to display text, but you can exclude it:
ImageTextButtonControl class
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SecureBox.Controls
{
public class ImageTextButtonControl: Button
{
///
///
///
public static readonly DependencyProperty ImageHeightProperty =
DependencyProperty.Register("ImageHeight", typeof(double), typeof(ImageTextButtonControl), null);
public double ImageHeight
{
get { return (double)GetValue(ImageHeightProperty); }
set { SetValue(ImageHeightProperty, value); }
}
///
///
///
public static readonly DependencyProperty ImageWidthProperty =
DependencyProperty.Register("ImageWidth", typeof(double), typeof(ImageTextButtonControl), null);
public double ImageWidth
{
get { return (double)GetValue(ImageWidthProperty); }
set { SetValue(ImageWidthProperty, value); }
}
///
///
///
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(BitmapImage), typeof(ImageTextButtonControl), null);
public BitmapImage ImageSource
{
get { return (BitmapImage)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
///
///
///
public static readonly DependencyProperty TextMarginProperty =
DependencyProperty.Register("TextMargin", typeof(Thickness), typeof(ImageTextButtonControl), null);
public Thickness TextMargin
{
get { return (Thickness)GetValue(TextMarginProperty); }
set { SetValue(TextMarginProperty, value); }
}
///
///
///
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ImageTextButtonControl), null);
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public ImageTextButtonControl()
{
DefaultStyleKey = typeof(ImageTextButtonControl);
}
}
}
Themes\generic.xaml contains:
<Style TargetType="local:ImageTextButtonControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ImageTextButtonControl">
<Grid Margin="{StaticResource PhoneTouchTargetOverhang}" toolkit:TiltEffect.IsTiltEnabled="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border BorderBrush="White" BorderThickness="0" Opacity="0.9" >
<Image Grid.Column="0" Width="{TemplateBinding ImageWidth}" Height="{TemplateBinding ImageHeight}" Source="{TemplateBinding ImageSource}" VerticalAlignment="Top" />
</Border>
<TextBlock Grid.Column="1" Margin="{TemplateBinding TextMargin}" Text="{TemplateBinding Text}" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="{TemplateBinding FontSize}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Example of usage:
<local:ImageTextButtonControl ImageSource="/ImagePath/YourImage.png" Text="YourText" FontSize="50" ImageHeight="128" ImageWidth="128" TextMargin="20,0,0,0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Command:EventToCommand
Command="{Binding GoTo}" CommandParameterValue="YourCommandParameter" />
</i:EventTrigger>
</i:Interaction.Triggers>
Note:
I've inherited the control from Button control. This allows me to
subscribe to Click event using MVVMLight framework
Xaml code is located in special place: Themes\generic.xaml file
I guess you can try to check whether these notes can fix your the issue in your code or use my one instead.

Resources