I'm trying to make an animated splash screen for my app. I have my MainPage where I show a Popup which has an animation and a textblock. I'd like to change the text of my textblock to show the status of the loading, but I can't change it. Any ideas?
Mainpage code
namespace animatedsplash
{
public partial class MainPage : PhoneApplicationPage
{
BackgroundWorker preloader;
Popup splashPop;
public MainPage()
{
InitializeComponent();
splashPop = new Popup(){IsOpen = true, Child = new Splash() };
preloader = new BackgroundWorker();
RunPreloader();
}
private void RunPreloader()
{
preloader.DoWork += ((s, args) => {
Thread.Sleep(10000);
});
preloader.RunWorkerCompleted += ((s,args) =>
{
this.Dispatcher.BeginInvoke(()=> { this.splashPop.IsOpen = false; });
});
preloader.RunWorkerAsync();
}
}
}
Splash xaml
<phone:PhoneApplicationPage
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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:ec="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions" xmlns:eim="clr-namespace:Microsoft.Expression.Interactivity.Media;assembly=Microsoft.Expression.Interactions"
xmlns:local="clr-namespace:animatedsplash"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
x:Class="animatedsplash.Splash"
Orientation="Portrait"
shell:SystemTray.IsVisible="False">
<phone:PhoneApplicationPage.Resources>
<Storyboard x:Name="load">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" Storyboard.TargetName="image">
<EasingDoubleKeyFrame KeyTime="0" Value="-180"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="180"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</phone:PhoneApplicationPage.Resources>
<phone:PhoneApplicationPage.FontFamily>
<StaticResource ResourceKey="PhoneFontFamilyNormal"/>
</phone:PhoneApplicationPage.FontFamily>
<phone:PhoneApplicationPage.FontSize>
<StaticResource ResourceKey="PhoneFontSizeNormal"/>
</phone:PhoneApplicationPage.FontSize>
<phone:PhoneApplicationPage.Foreground>
<StaticResource ResourceKey="PhoneForegroundBrush"/>
</phone:PhoneApplicationPage.Foreground>
<i:Interaction.Triggers>
<eim:StoryboardCompletedTrigger Storyboard="{StaticResource load}">
<eim:ControlStoryboardAction Storyboard="{StaticResource load}"/>
</eim:StoryboardCompletedTrigger>
<i:EventTrigger>
<eim:ControlStoryboardAction Storyboard="{StaticResource load}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--TitlePanel contains the name of the application and page title--><!--ContentPanel - place additional content here-->
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Margin="0" Grid.Row="1" Source="/media/splashbg.jpg" Stretch="Fill" d:IsLocked="True"/>
<Image x:Name="rotator" Margin="96,288,184,312" Grid.Row="1" Source="media/splashpin.png" Stretch="Fill" d:IsLocked="True"/>
<Image x:Name="image" Margin="142,305,0,370" Grid.Row="1" Source="media/pinload.png" Stretch="Fill" HorizontalAlignment="Left" Width="75" RenderTransformOrigin="0.838,0.504">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<TextBlock x:Name="preloader_percentage" Margin="178,354,0,0" Grid.Row="1" TextWrapping="Wrap" Text="100" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.593" TextAlignment="Right" HorizontalAlignment="Left" Width="35" FontFamily="Segoe WP Semibold" Height="27"/>
<TextBlock Margin="213,354,0,0" Grid.Row="1" TextWrapping="Wrap" Text="%" VerticalAlignment="Top" HorizontalAlignment="Left" Width="16" FontFamily="Segoe WP Semibold" d:IsLocked="True"/>
</Grid>
</phone:PhoneApplicationPage>
How about something like this:
In Splash.xaml.cs you would have the following:
public string Progress
{
get { return preloader_percentage.Text; }
set { preloader_percentage.Text = value; }
}
And in MainWindow.xaml.cs you change your code to look something like this:
preloader.WorkerReportsProgress = true;
preloader.ProgressChanged += (sender, e) =>
{
this.Dispatcher.BeginInvoke(() =>
(this.splashPop.Child as Splash).Progress = e.ProgressPercentage.ToString());
};
Then in your worker method you need to call preloader.ReportProgress() method several times. As far as I know, that should do it.
Note: There are a lot of design landmines here. I'd suggest getting this code to work, and you can refactor later to make it cleaner and easier to maintain.
Related
Is there a standard message box in WPF, like WinForms' System.Windows.Forms.MessageBox.Show(), or should I use the WinForms message box?
The WPF equivalent would be the System.Windows.MessageBox. It has a quite similar interface, but uses other enumerations for parameters and return value.
You can use this:
MessageBoxResult result = MessageBox.Show("Do you want to close this window?",
"Confirmation",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
Application.Current.Shutdown();
}
For more information, visit MessageBox in WPF.
WPF contains the following MessageBox:
if (MessageBox.Show("Do you want to Save?", "Confirm",
MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
}
The equivalent to WinForms' MessageBox in WPF is called System.Windows.MessageBox.
In WPF it seems this code,
System.Windows.Forms.MessageBox.Show("Test");
is replaced with:
System.Windows.MessageBox.Show("Test");
The MessageBox in the Extended WPF Toolkit is very nice. It's at Microsoft.Windows.Controls.MessageBox after referencing the toolkit DLL. Of course this was released Aug 9 2011 so it would not have been an option for you originally. It can be found at Github for everyone out there looking around.
If you want to have your own nice looking wpf MessageBox:
Create new Wpf Windows
here is xaml :
<Window x:Class="popup.MessageboxNew"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:popup"
mc:Ignorable="d"
Title="" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" WindowStyle="None" ResizeMode="NoResize" AllowsTransparency="True" Background="Transparent" Opacity="1"
>
<Window.Resources>
</Window.Resources>
<Border x:Name="MainBorder" Margin="10" CornerRadius="8" BorderThickness="0" BorderBrush="Black" Padding="0" >
<Border.Effect>
<DropShadowEffect x:Name="DSE" Color="Black" Direction="270" BlurRadius="20" ShadowDepth="3" Opacity="0.6" />
</Border.Effect>
<Border.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="DSE" Storyboard.TargetProperty="ShadowDepth" From="0" To="3" Duration="0:0:1" AutoReverse="False" />
<DoubleAnimation Storyboard.TargetName="DSE" Storyboard.TargetProperty="BlurRadius" From="0" To="20" Duration="0:0:1" AutoReverse="False" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<Grid Loaded="FrameworkElement_OnLoaded">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Name="Mask" CornerRadius="8" Background="White" />
<Grid x:Name="Grid" Background="White">
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Mask}"/>
</Grid.OpacityMask>
<StackPanel Name="StackPanel" >
<TextBox Style="{DynamicResource MaterialDesignTextBox}" Name="TitleBar" IsReadOnly="True" IsHitTestVisible="False" Padding="10" FontFamily="Segui" FontSize="14"
Foreground="Black" FontWeight="Normal"
Background="Yellow" HorizontalAlignment="Stretch" VerticalAlignment="Center" Width="Auto" HorizontalContentAlignment="Center" BorderThickness="0"/>
<DockPanel Name="ContentHost" Margin="0,10,0,10" >
<TextBlock Margin="10" Name="Textbar"></TextBlock>
</DockPanel>
<DockPanel Name="ButtonHost" LastChildFill="False" HorizontalAlignment="Center" >
<Button Margin="10" Click="ButtonBase_OnClick" Width="70">Yes</Button>
<Button Name="noBtn" Margin="10" Click="cancel_Click" Width="70">No</Button>
</DockPanel>
</StackPanel>
</Grid>
</Grid>
</Border>
</Window>
for cs of this file :
public partial class MessageboxNew : Window
{
public MessageboxNew()
{
InitializeComponent();
//second time show error solved
if (Application.Current == null) new Application();
Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
DialogResult = true;
}
private void cancel_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
}
private void FrameworkElement_OnLoaded(object sender, RoutedEventArgs e)
{
this.MouseDown += delegate { DragMove(); };
}
}
then create a class to use this :
public class Mk_MessageBox
{
public static bool? Show(string title, string text)
{
MessageboxNew msg = new MessageboxNew
{
TitleBar = {Text = title},
Textbar = {Text = text}
};
msg.noBtn.Focus();
return msg.ShowDialog();
}
}
now you can create your message box like this:
var result = Mk_MessageBox.Show("Remove Alert", "This is gonna remove directory from host! Are you sure?");
if (result == true)
{
// whatever
}
copy this to App.xaml inside
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<!-- Accent and AppTheme setting -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
<!--two new guys-->
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.LightBlue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Green.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
-------------------------------
My Refrence :
https://www.red-gate.com/simple-talk/dotnet/net-development/using-c-to-create-powershell-cmdlets-the-basics/
for logic how can i make my own messagebox
As the others say, there is a MessageBox in the WPF namespace (System.Windows).
The problem is that it is the same old messagebox with OK, Cancel, etc. Windows Vista and Windows 7 have moved on to use Task Dialogs instead.
Unfortunately there is no easy standard interface for task dialogs. I use an implementation from CodeProject KB.
Maybe the code here below helps:
using Windows.UI.Popups;
namespace something.MyViewModels
{
public class TestViewModel
{
public void aRandonMethode()
{
MyMessageBox("aRandomMessage");
}
public async void MyMessageBox(string mytext)
{
var dialog = new MessageDialog(mytext);
await dialog.ShowAsync();
}
}
}
I want to know how to display current date and time on a WPF statusbar.
I know this is too basic a question, but I am new to .net WPF,
and I know this can be done in a Form application easily.
Thanks in advance.
Ting
Create a wpf project. In your MainWindow.xaml add the StatusBar and handle Loaded event of window.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApp1.MainWindow"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StatusBar Grid.Row="1">
<TextBlock x:FieldModifier="private" x:Name="myDateTime"/>
</StatusBar>
</Grid>
</Window>
In the MainWindow.xaml.cs add the following namespaces (if they are not exist):
using System;
using System.Windows;
using System.Windows.Threading;
And in the Loaded enevt handler you can use DispatcherTimer for update textblock text property every second:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DispatcherTimer timer = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Normal, (object s, EventArgs ev) =>
{
this.myDateTime.Text = DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss");
}, this.Dispatcher);
timer.Start();
}
Also there are a lot of examples for customize wpf controls using Template and Style properties. just search for it.
Styles and templates in WPF
The WPF StatusBar control
and many more.
Also you can implement your custom WPFTimer. This simple implementation get you an idea for do this.
public class WPFTimer : TextBlock
{
#region static
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register("Interval", typeof(TimeSpan), typeof(WPFTimer), new PropertyMetadata(TimeSpan.FromSeconds(1), IntervalChangedCallback));
public static readonly DependencyProperty IsRunningProperty = DependencyProperty.Register("IsRunning", typeof(bool), typeof(WPFTimer), new PropertyMetadata(false, IsRunningChangedCallback));
private static void IntervalChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
WPFTimer wpfTimer = (WPFTimer)d;
wpfTimer.timer.Interval = (TimeSpan)e.NewValue;
}
private static void IsRunningChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
WPFTimer wpfTimer = (WPFTimer)d;
wpfTimer.timer.IsEnabled = (bool)e.NewValue;
}
#endregion
private readonly DispatcherTimer timer;
[Category("Common")]
public TimeSpan Interval
{
get
{
return (TimeSpan)this.GetValue(IntervalProperty);
}
set
{
this.SetValue(IntervalProperty, value);
}
}
[Category("Common")]
public bool IsRunning
{
get
{
return (bool)this.GetValue(IsRunningProperty);
}
set
{
this.SetValue(IsRunningProperty, value);
}
}
public WPFTimer()
{
this.timer = new DispatcherTimer(this.Interval, DispatcherPriority.Normal,this.Timer_Tick ,this.Dispatcher);
this.timer.IsEnabled = false;
}
private void Timer_Tick(object sender, EventArgs e)
{
this.SetValue(TextProperty, DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss"));
}
}
And now you have a control that can use it in the designer.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
x:Class="WpfApp1.MainWindow"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StatusBar Grid.Row="1">
<local:WPFTimer IsRunning="True"/>
</StatusBar>
</Grid>
</Window>
You can do it this way, using wpf animation and binding, and no background code :)
<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
<Grid.Resources>
<!--Set x: share to get the latest every time-->
<system:DateTime x:Key="DateTime"
x:Shared="False" />
<Storyboard x:Key="Storyboard">
<!--Use keyframe animation to update datetime -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="DataContext"
Duration="0:0:1"
RepeatBehavior="Forever"
AutoReverse="False">
<DiscreteObjectKeyFrame KeyTime="50%"
Value="{StaticResource DateTime}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
<!--Get datetime from DataContext-->
<TextBlock Text="{Binding RelativeSource={RelativeSource Self},Path=DataContext.Now}"
DataContext="{StaticResource DateTime}">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard Storyboard="{StaticResource Storyboard}" />
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</Grid>
</Window>
or like this,a real clock
<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Window.Resources>
<FrameworkElement x:Key="time" Tag="{x:Static system:DateTime.Now}" />
<TransformGroup x:Key="transformHour">
<TranslateTransform X="{Binding Source={StaticResource time},Path=Tag.Hour}"
Y="{Binding Source={StaticResource time},Path=Tag.Minute}" />
<MatrixTransform Matrix="30 0 0.5 0 0 0" />
</TransformGroup>
<TransformGroup x:Key="transformMinute">
<TranslateTransform X="{Binding Source={StaticResource time},Path=Tag.Minute}"
Y="{Binding Source={StaticResource time},Path=Tag.Second}" />
<MatrixTransform Matrix="6 0 0.1 0 0 0" />
</TransformGroup>
<TransformGroup x:Key="transformSecond">
<TranslateTransform X="{Binding Source={StaticResource time},Path=Tag.Second}" />
<MatrixTransform Matrix="6 0 0 0 0 0" />
</TransformGroup>
<Style TargetType="{x:Type Path}">
<Setter Property="Stroke"
Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
<Setter Property="StrokeThickness" Value="3" />
<Setter Property="StrokeDashCap" Value="Triangle" />
</Style>
</Window.Resources>
<Viewbox>
<Canvas Width="200" Height="200">
<Canvas.RenderTransform>
<TranslateTransform X="100" Y="100" />
</Canvas.RenderTransform>
<Path Data="M 0 -90 A 90 90 0 1 1 -0.01 -90"
StrokeDashArray="0 3.14157" />
<Path Data="M 0 -90 A 90 90 0 1 1 -0.01 -90"
StrokeDashArray="0 7.854"
StrokeThickness="6" />
<Border Background="LightBlue" Width="10" Height="80" RenderTransformOrigin="0.5 0">
<Border.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="bor_Second"
Angle="{Binding Source={StaticResource transformSecond},Path=Value.OffsetX}" />
<RotateTransform Angle="180" />
</TransformGroup>
</Border.RenderTransform>
</Border>
<Border Background="LightGreen" Width="10" Height="60" RenderTransformOrigin="0.5 0">
<Border.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="bor_Minute"
Angle="{Binding Source={StaticResource transformMinute},Path=Value.OffsetX}" />
<RotateTransform Angle="180" />
</TransformGroup>
</Border.RenderTransform>
</Border>
<Border Background="LightGray" Width="10" Height="40" RenderTransformOrigin="0.5 0">
<Border.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="bor_Hour"
Angle="{Binding Source={StaticResource transformHour},Path=Value.OffsetX}" />
<RotateTransform Angle="180" />
</TransformGroup>
</Border.RenderTransform>
</Border>
</Canvas>
</Viewbox>
<Window.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="bor_Hour"
Storyboard.TargetProperty="Angle"
IsAdditive="True"
Duration="12:0:0"
From="0" To="360"
RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="bor_Minute"
Storyboard.TargetProperty="Angle"
IsAdditive="True"
Duration="1:0:0"
From="0" To="360"
RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="bor_Second"
Storyboard.TargetProperty="Angle"
IsAdditive="True"
Duration="0:1:0"
From="0"
To="360"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
</Window>
Create a clock using only xaml code in wpf
I'm developing a UWP app and trying to apply a style per control in code that would set the Grid.Column property, effectively to move the elements around the grid. However, my elements stay where they are, even though the animations run. Any setter besides Grid.* works, and I can see the styles being applied both through my code and through the live property window.
I know there are other ways to accomplish what I'm going for and I'll probably do one of those, but I want to know what's going on here. I'll post a sample of my page and the command that applies the styling:
MainPage.xaml
<Page
x:Class="UWPApp.Scorekeeper.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UWPApp.Scorekeeper"
xmlns:viewmodels="using:UWPApp.Scorekeeper.Models.ViewModels"
xmlns:converters="using:UWPApp.Scorekeeper.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mo="using:UWPApp.Scorekeeper.Models"
mc:Ignorable="d"
x:Name="MainPageElement"
d:DesignHeight="600"
d:DesignWidth="1024">
<Page.Resources>
<DataTemplate x:Key="GridHorizontalTemplate" x:DataType="local:MainPage">
<Grid MinWidth="768" MinHeight="500" Background="{ThemeResource SystemControlBackgroundAccentBrush}" ManipulationMode="All">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="69*"/>
<ColumnDefinition Width="76*"/>
<ColumnDefinition Width="76*"/>
<ColumnDefinition Width="69*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="73*"/>
<RowDefinition Height="135*"/>
<RowDefinition Height="69*"/>
<RowDefinition Height="43*"/>
</Grid.RowDefinitions>
<Button Foreground="{ThemeResource SystemControlForegroundChromeMediumBrush}" Command="{Binding ElementName=MainPageElement, Path=EnterGoalCommand}" CommandParameter="{Binding ElementName=MainPageElement,Path=StateModel.HomeID}" x:Name="HomeGoalBtn" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1" Grid.Column="1" Margin="0,0.4,0,0" d:LayoutOverrides="LeftMargin, RightMargin" >
<Button.Resources>
<Style x:Key="FlippedStyle" TargetType="Button">
<Setter Property="Grid.Column" Value="2"/>
</Style>
<Storyboard x:Key="ToFlipAnimation">
<RepositionThemeAnimation FromHorizontalOffset="-487"/>
</Storyboard>
<Storyboard x:Key="FromFlipAnimation">
<RepositionThemeAnimation FromHorizontalOffset="487"/>
</Storyboard>
</Button.Resources>
<Viewbox Margin="40" Stretch="Uniform">
<TextBlock Text="Goal" FontSize="48" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Bottom" />
</Viewbox>
</Button>
<Button Foreground="{ThemeResource SystemControlForegroundChromeMediumBrush}" Command="{Binding ElementName=MainPageElement, Path=EnterGoalCommand}" CommandParameter="{Binding ElementName=MainPageElement,Path=StateModel.AwayID}" x:Name="AwayGoalBtn" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1" Grid.Column="2" Margin="0,0.4,-0.2,0" d:LayoutOverrides="LeftMargin, RightMargin" >
<Button.Resources>
<Style x:Key="FlippedStyle" TargetType="Button">
<Setter Property="Grid.Column" Value="1"/>
</Style>
<Storyboard x:Key="ToFlipAnimation">
<RepositionThemeAnimation FromHorizontalOffset="487"/>
</Storyboard>
<Storyboard x:Key="FromFlipAnimation">
<RepositionThemeAnimation FromHorizontalOffset="-487"/>
</Storyboard>
</Button.Resources>
<Viewbox Margin="40" Stretch="Uniform">
<TextBlock Text="Goal" FontSize="48" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Bottom" />
</Viewbox>
</Button>
</Grid>
</DataTemplate>
</Page.Resources>
<ContentPresenter x:Name="MainContent" Margin="0,0,0,0" HorizontalAlignment="Stretch" d:LayoutOverrides="Width, Height" VerticalAlignment="Stretch">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000"></AdaptiveTrigger>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainContent.ContentTemplate" Value="{StaticResource GridHorizontalTemplate}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</Page>
MainPage.xaml.cs
public ICommand FlipScreen => new CommandHandler(() =>
{
if (!flipped)
{
flipped = true;
foreach (var item in this.FindChildren<FrameworkElement>())
{
object styleObject;
if (item.Resources.TryGetValue("FlippedStyle", out styleObject))
{
item.Style = (Style)styleObject;
}
object animationObject;
if (item.Resources.TryGetValue("ToFlipAnimation", out animationObject))
{
Storyboard board = animationObject as Storyboard;
if (board.GetCurrentState() != ClockState.Stopped)
{
board.Stop();
}
foreach (var subitem in board.Children)
{
Storyboard.SetTarget(subitem, item);
}
board.Begin();
}
}
}
else
{
flipped = false;
foreach (var item in this.FindChildren<FrameworkElement>())
{
item.Style = null;
object animationObject;
if (item.Resources.TryGetValue("FromFlipAnimation", out animationObject))
{
Storyboard board = animationObject as Storyboard;
if (board.GetCurrentState() != ClockState.Stopped)
{
board.Stop();
}
foreach (var subitem in board.Children)
{
Storyboard.SetTarget(subitem, item);
}
board.Begin();
}
}
}
});
FindChildren:
public static List<T> FindChildren<T>(this FrameworkElement element) where T : FrameworkElement
{
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
var children = new FrameworkElement[childrenCount];
List<T> list = new List<T>();
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;
children[i] = child;
if (child is T)
list.Add(child as T);
}
for (int i = 0; i < childrenCount; i++)
if (children[i] != null)
{
var subChild = FindChildren<T>(children[i]);
if (subChild != null)
list.AddRange(subChild);
}
return list;
}
Not sure if a default Button Style in the Resources of a Button would actually apply to that Button.
Better set the Style explicitly:
<Button ... >
<Button.Style>
<Style TargetType="Button">
<Setter Property="Grid.Column" Value="2"/>
</Style>
</Button.Style>
<Button.Resources>
...
</Button.Resources>
<Viewbox ...>
...
</Viewbox>
</Button>
I'm developing a C# WPF application that is intended to run on full Windows 10 tablets using exclusively touch. So far, the app works great, except for one of my dialog windows has buttons that don't like to be touched.
Dialog Window XAML:
<Window x:Class="Commencement_Organizer.ConfirmStudentWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Commencement_Organizer"
mc:Ignorable="d"
Title="Confirmation" Topmost="True" Height="372.677" Width="578.225" ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
WindowStyle="None" Background="White" AllowsTransparency="True" Stylus.IsTapFeedbackEnabled="False" Stylus.IsTouchFeedbackEnabled="False">
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="00:00:0.2" Storyboard.TargetProperty="Opacity" From="0" To="1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid Background="#FF171717">
<Grid Margin="1" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="YesButton" Content="Yes" Margin="25" Grid.Row="2" Click="YesButton_Click"/>
<Button x:Name="NoButton" Content="No" Margin="25" Grid.Row="2" Grid.Column="1" Click="NoButton_Click"/>
<Label x:Name="label" Content="Confirm your name" Margin="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
<Label x:Name="nameLabel" Content="Label" HorizontalAlignment="Center" Margin="0" Grid.Row="1" VerticalAlignment="Center" Grid.ColumnSpan="2" FontSize="24" FontWeight="Bold"/>
</Grid>
</Grid>
Implementation (C#):
ConfirmStudentWindow confirmWindow = new ConfirmStudentWindow(student);
confirmWindow.Confirm += OnConfirm;
// This window makes everything behind the dialog window a grey tint, which makes the dialog more prominent
var darkwindow = new Window()
{
Background = Brushes.Black,
Opacity = 0.4,
AllowsTransparency = true,
WindowStyle = WindowStyle.None,
WindowState = WindowState.Maximized,
Topmost = true,
Effect = new BlurEffect()
};
darkwindow.Show(); // Show grey background tint
confirmWindow.ShowDialog(); // Stops main UI thread
darkwindow.Close();
Everything about this works as intended, except when I try to use a touchscreen to use those buttons, they just stay highlighted, but don't actually click. Works perfect with a mouse.
Tested on 2 different Windows 10 Devices (Surface Pro 2 and Surface Book).
To put it in the form of a question:
Why does launching this window as a Dialog make it resistant to touch, but not if it's launched as a regular window?
Edit - New Question:
Is there any way to simulate a Dialog window other than launching a regular window that always stays on top and then put a tinted overlay behind it while giving the window an eventhandler that provides the result of the user input?
I tried your example and it is running without any problem at my end. I am using DELL notebook with touch display with W10 and .NET 4.5.2. One thing that I can suggest you is to try to hook up StylusUp (or StylusDown that depends on your logic) event on buttons in dialog. I did encounter similar problems in the past when only click event was managed.
This worked for me, confirm method was called and dialog closed.
ConfirmStudentWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Input;
namespace DialogTouchTest
{
/// <summary>
/// Interaction logic for ConfirmStudentWindow.xaml
/// </summary>
public partial class ConfirmStudentWindow : Window
{
public Action Confirm;
public ConfirmStudentWindow()
{
InitializeComponent();
}
private void YesButton_Click(object sender, RoutedEventArgs e)
{
e.Handled = true;
Yes();
}
private void NoButton_Click(object sender, RoutedEventArgs e)
{
e.Handled = true;
No();
}
private void YesButton_StylusUp(object sender, StylusEventArgs e)
{
e.Handled = true;
Yes();
}
private void NoButton_StylusUp(object sender, StylusEventArgs e)
{
e.Handled = true;
No();
}
private void Yes()
{
DialogResult = true;
Confirm();
}
private void No()
{
DialogResult = false;
}
}
}
ConfirmStudentWindow.xaml
<Window x:Class="DialogTouchTest.ConfirmStudentWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Confirmation" Topmost="True" Height="372.677" Width="578.225" ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
WindowStyle="None" Background="White" AllowsTransparency="True" Stylus.IsTapFeedbackEnabled="False" Stylus.IsTouchFeedbackEnabled="False">
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="00:00:0.2" Storyboard.TargetProperty="Opacity" From="0" To="1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid Background="#FF171717">
<Grid Margin="1" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="YesButton" Content="Yes" Margin="25" Grid.Row="2" StylusUp="YesButton_StylusUp" Click="YesButton_Click"/>
<Button x:Name="NoButton" Content="No" Margin="25" Grid.Row="2" Grid.Column="1" StylusUp="NoButton_StylusUp" Click="NoButton_Click"/>
<Label x:Name="label" Content="Confirm your name" Margin="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
<Label x:Name="nameLabel" Content="Label" HorizontalAlignment="Center" Margin="0" Grid.Row="1" VerticalAlignment="Center" Grid.ColumnSpan="2" FontSize="24" FontWeight="Bold"/>
</Grid>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Effects;
namespace DialogTouchTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
ConfirmStudentWindow confirmWindow = new ConfirmStudentWindow();
confirmWindow.Confirm += OnConfirm;
// This window makes everything behind the dialog window a grey tint, which makes the dialog more prominent
var darkwindow = new Window()
{
Background = Brushes.Black,
Opacity = 0.4,
AllowsTransparency = true,
WindowStyle = WindowStyle.None,
WindowState = WindowState.Maximized,
Topmost = true,
Effect = new BlurEffect()
};
darkwindow.Show(); // Show grey background tint
confirmWindow.ShowDialog(); // Stops main UI thread
darkwindow.Close();
}
private void OnConfirm()
{
}
}
}
Comparing two identical .Show() methods, one being executed from a ViewModel and the other executed in code-behind, I found that the code-behind instance did not detect touches.
My solution was to invoke the method on the main UI thread from code-behind:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
{
window.Show()
}));
Beware that if you expect a result from the dialog then you will need to include it within the `Dispatched.BeginInvoke' method, otherwise it will not work correctly.
Ideally, grouping all relevant logics within would be the best approach.
hey I create a usercontrol in my project. I want when its Visibility property is changed, run a line of code
VisualStateManager.GoToState(this, "Normal", true);
this property is binding to a data source.
<usercontrol:CorrectAnswerMessage Grid.Column="1" x:Name="correct"
Visibility="{Binding IsTrueAnswer,Mode=TwoWay}" VerticalAlignment="Center"
HorizontalAlignment="Left"></usercontrol:CorrectAnswerMessage>
I looking for a way to create a event for Visibility property. when this property is changed , the event is fired.
here is my user control
<UserControl
x:Class="Lifener.UserControls.CorrectAnswerMessage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Lifener.UserControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="500">
<Grid x:Name="CorrectResult" Width="400" Height="350" Visibility="Visible" HorizontalAlignment="Center" Margin="0">
<TextBlock Text="" FontSize="120" FontFamily="Segoe UI Symbol" Padding="0" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Center" />
<TextBlock TextAlignment="Center" Text="" FontSize="60" FontFamily="Segoe UI Symbol" Margin="130,30,55,215" />
<TextBlock x:Name="Like" TextAlignment="Center" Text="" FontSize="60" FontFamily="Segoe UI Symbol" Margin="165,30,20,0" Foreground="Green" RenderTransformOrigin="0.5,0.5" Height="104" VerticalAlignment="Top"/>
<TextBlock x:Uid="AnswerIsRight" HorizontalAlignment="Left" Margin="185,140,0,0" TextWrapping="Wrap" Text="Hooora, Right. You are awsome." VerticalAlignment="Top" Width="185" Height="140" TextAlignment="Center" FontSize="28" FontWeight="Bold"/>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonGroups">
<VisualState x:Name="Normal" >
<VisualState.Storyboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Like"
Storyboard.TargetProperty="Foreground"
Duration="0:0:2.5"
AutoReverse="True"
RepeatBehavior="Forever">
<DiscreteObjectKeyFrame Value="Red" KeyTime="0"></DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState.Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
If you're not using MVVM, then you could call GoToState in the setter for IsTrueAnswer.
With MVVM, I'm not sure what the best way is. Maybe raise an event VisibilityChanged from the user control's model:
public partial class MyModel
{
public event EventArgs VisibilityChanged;
private bool _isTrueAnswer;
public bool IsTrueAnswer
{
get { return _isTrueAnswer; }
set
{
_isTrueAnswer = value;
VisibilityChanged(this, EventArgs.Empty);
}
}
// etc...
}
And add a listener from the code-behind of your page:
public MyPage()
{
((MyModel)MyUserControl.DataContext).VisibilityChanged += (sender, args) => {
VisualStateManager.GoToState(this, "Normal", true);
};
}