DispatcherTimer does not showing UI manipulation in tick event - UWP - windows-10

I have a DispatcherTimer in my UWP app for updating database from a web services.
public DispatcherTimer SessionTimer { get; set; }
Before updating the DB in the tick event of this timer, I collapse main grid and show updating message and after update completed I do reverse.
private void SessionTimer_Tick(object sender, object e)
{
rpWait.Visibility = Visibility.Visible;
LayoutRoot.Visibility = Visibility.Collapsed;
Update();
rpWait.Visibility = Visibility.Collapsed;
LayoutRoot.Visibility = Visibility.Visible;
}
My XAML codes:
<Grid x:Name="LayoutRoot" Style="{StaticResource backGrid}">
<RelativePanel Style="{StaticResource rpTop}">
...
</RelativePanel>
<Frame x:Name="frameBody" Loaded="frameBody_Loaded" Margin="0,100,0,0"/>
</Grid>
<RelativePanel x:Name="rpWait" Visibility="Collapsed">
<StackPanel RelativePanel.AlignHorizontalCenterWithPanel="True" RelativePanel.AlignVerticalCenterWithPanel="True">
<TextBlock x:Name="lbMessage" FontSize="30" HorizontalAlignment="Center">Updating</TextBlock>
<TextBlock x:Name="lbWaiting" FontSize="30" Margin="0 50 0 0">Please Wait</TextBlock>
</StackPanel>
</RelativePanel>
But the timer does not show anything (DB updated properly).
Help me please?

I believe your problem is that you dont run Update() Asynchronous and await for the update. Also if if you do UI updates better to do them in the UI thread.
DispatcherTimer ds = new DispatcherTimer();
// In Constuctor of the page
ds.Interval = new TimeSpan(0, 1, 0);
ds.Tick += ds_Tick;
ds.Start();
void ds_Tick(object sender, object e)
{
ShowHide(true);
await Update();
ShowHide(false);
}
private async void ShowHide(bool state)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
if(state)
{
rpWait.Visibility = Visibility.Visible;
LayoutRoot.Visibility = Visibility.Collapsed;
}
else
{
rpWait.Visibility = Visibility.Collapsed;
LayoutRoot.Visibility = Visibility.Visible;
}
});
}
private Task Update()
{
//run your update
//if your update doesnt have await use
//return Task.Run(() => {
// //doto
// });
//If it does just write your code
}

Related

How to send messages between threads using CommunityToolkit.Mvvm.Messaging and WinUI 3?

The following simple multi-threaded program was meant to try out the CommunityToolkit Messenger package for which the documentation says (see: Messenger)
Both WeakReferenceMessenger and StrongReferenceMessenger also expose a Default property that offers a thread-safe implementation built-in into the package.
I had hoped this would mean I could send messages on one thread and receive them on other threads but a problem arose with what seems to be the IMessenger Interface. Details follow below.
This project starts with a vanilla TemplateStudio WinUI 3 (v1.1.5) desktop template that uses the CommunityToolkit Mvvm package (with Messenger) and a single page, MainPage. When the App launches, it starts a RandomMessageGenerator thread that periodically issues a TraceMessage using the WeakReferenceMessenger.Default channel from the Toolkit. The UI thread receives these messages and stores them in a List.
App.xaml.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml;
using Multi_Window.Activation;
using Multi_Window.Contracts.Services;
using Multi_Window.Core.Contracts.Services;
using Multi_Window.Core.Services;
using Multi_Window.Services;
using Multi_Window.ViewModels;
using Multi_Window.Views;
using Microsoft.UI;
using Microsoft.UI.Windowing;
using CommunityToolkit.Mvvm.Messaging.Messages;
using System.Diagnostics;
namespace Multi_Window;
// To learn more about WinUI 3, see https://docs.microsoft.com/windows/apps/winui/winui3/.
public partial class App : Application
{
// The .NET Generic Host provides dependency injection, configuration, logging, and other services.
// https://docs.microsoft.com/dotnet/core/extensions/generic-host
// https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
// https://docs.microsoft.com/dotnet/core/extensions/configuration
// https://docs.microsoft.com/dotnet/core/extensions/logging
public IHost Host { get; }
public static T GetService<T>()
where T : class
{
if ((App.Current as App)!.Host.Services.GetService(typeof(T)) is not T service)
{
throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs.");
}
return service;
}
public static WindowEx MainWindow { get; } = new MainWindow();
public static ShellPage? ShellPage { get; set; }
private static readonly List<string> _traceMessages = new();
private Task? messageGenerator;
public App()
{
InitializeComponent();
Host = Microsoft.Extensions.Hosting.Host.
CreateDefaultBuilder().
UseContentRoot(AppContext.BaseDirectory).
ConfigureServices((context, services) =>
{
// Default Activation Handler
services.AddTransient<ActivationHandler<LaunchActivatedEventArgs>, DefaultActivationHandler>();
// Other Activation Handlers
// Services
services.AddTransient<INavigationViewService, NavigationViewService>();
services.AddSingleton<IActivationService, ActivationService>();
services.AddSingleton<IPageService, PageService>();
services.AddSingleton<INavigationService, NavigationService>();
// Core Services
services.AddSingleton<IFileService, FileService>();
// Views and ViewModels
services.AddTransient<MainViewModel>();
services.AddTransient<MainPage>();
// ** NOTE ** changed to Singleton so we can refer to THE ShellPage/ShellViewModel
services.AddSingleton<ShellPage>();
services.AddSingleton<ShellViewModel>();
// Configuration
}).
Build();
UnhandledException += App_UnhandledException;
System.AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Microsoft.UI.Xaml.Application.Current.UnhandledException += Current_UnhandledException;
}
private void RandomMessageGenerator()
{
var shutdown = false;
WeakReferenceMessenger.Default.Register<ShutDownMessage>(this, (r, m) => shutdown = true);
Debug.WriteLine($"RandomMessageGenerator started on thread {Environment.CurrentManagedThreadId}");
Random rnd = new();
// not a good way to control thread shutdown in general but will do for a quick test
while (shutdown == false)
{
Thread.Sleep(rnd.Next(5000));
var tm = new TraceMessage($"{DateTime.Now:hh:mm:ss.ffff} Timer event. (Th: {Environment.CurrentManagedThreadId})");
try
{
WeakReferenceMessenger.Default.Send(tm);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
break;
}
}
Debug.WriteLine($"RandomMessageGenerator closed at {DateTime.Now:hh:mm:ss.ffff} (Th: {Environment.CurrentManagedThreadId})");
}
private void Current_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) => throw new NotImplementedException();
private void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e) => throw new NotImplementedException();
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{
// TODO: Log and handle exceptions as appropriate.
// https://docs.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.unhandledexception.
throw new NotImplementedException();
}
protected async override void OnLaunched(LaunchActivatedEventArgs args)
{
base.OnLaunched(args);
await App.GetService<IActivationService>().ActivateAsync(args);
MainWindow.AppWindow.Closing += OnAppWindowClosing;
WeakReferenceMessenger.Default.Register<TraceMessage>(this, (r, m) =>
{
_traceMessages.Add(m.Value);
Debug.WriteLine(m.Value);
});
WeakReferenceMessenger.Default.Register<WindowClosedMessage>(this, (r, m) => OnStatusWindowClosed()); // StatusWindow closed events
WeakReferenceMessenger.Default.Register<App, TraceMessagesRequest>(this, (r, m) => m.Reply(_traceMessages)); // StatusWindow requests previous messages
messageGenerator = Task.Run(RandomMessageGenerator);
}
private void OnStatusWindowClosed()
{
if (ShellPage is not null && ShellPage.SettingsStatusWindow)
{
ShellPage.SettingsStatusWindow = false; // turn off toggle
if (ShellPage.NavigationFrame.Content is MainPage settingsPage) settingsPage.StatusWindowToggle.IsOn = false;
}
}
private async void OnAppWindowClosing(object sender, AppWindowClosingEventArgs e)
{
WeakReferenceMessenger.Default.UnregisterAll(this); // stop messages and avoid memory leaks
WeakReferenceMessenger.Default.Send(new ShutDownMessage(true)); // close all windows
MainWindow.AppWindow.Closing -= OnAppWindowClosing;
if (messageGenerator is not null) await messageGenerator;
}
}
The user may create a StatusWindow (a secondary Window on the UI thread) by toggling a switch on MainPage. The StatusWindow should open, request and load previous messages from the App, then register for new TraceMessages. All TraceMessages (including new ones) are displayed in a ListView on the StatusWindow.
MainPage.xaml.cs
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Multi_Window.ViewModels;
namespace Multi_Window.Views;
public sealed partial class MainPage : Page
{
public MainViewModel ViewModel { get; } = App.GetService<MainViewModel>();
public ShellPage ShellPage { get; } = App.GetService<ShellPage>();
public ShellViewModel ShellViewModel { get; } = App.GetService<ShellViewModel>();
public MainPage()
{
DataContext = ViewModel;
InitializeComponent();
}
private void StatusWindow_Toggled(object sender, RoutedEventArgs e)
{
if (StatusWindowToggle.IsOn && ShellPage.SettingsStatusWindow == false)
{
StatusWindow window = new() { Title = "Prosper Status" };
window.Activate();
ShellPage.SettingsStatusWindow = true;
}
else if (StatusWindowToggle.IsOn == false && ShellPage.SettingsStatusWindow == true)
WeakReferenceMessenger.Default.Send(new CloseWindowMessage(true));
}
}
MainPage.xaml
<Page
x:Class="Multi_Window.Views.MainPage"
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">
<Grid x:Name="ContentArea">
<ToggleSwitch x:Name="StatusWindowToggle" x:FieldModifier="public" Grid.Row="2" Grid.Column="1" Header="Show Status Window"
Toggled="StatusWindow_Toggled" IsOn="{x:Bind ShellPage.SettingsStatusWindow, Mode=OneTime}" />
</Grid>
</Page>
StatusWindow.xaml.cs
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace Multi_Window.Views;
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class StatusWindow : Window
{
private ObservableCollection<string> _traceMessages { get; } = new();
public StatusWindow()
{
InitializeComponent();
var sw = new WindowPrimitives(this);
sw.AppWindow.SetIcon("Assets/wip.ico");
WeakReferenceMessenger.Default.Register<CloseWindowMessage>(this, (r, m) => Close());
WeakReferenceMessenger.Default.Register<ShutDownMessage>(this, (r, m) => Close());
}
private void StatusWindow_Closed(object sender, WindowEventArgs args)
{
WeakReferenceMessenger.Default.UnregisterAll(this); // stop getting messages and avoid memory leaks
WeakReferenceMessenger.Default.Send(new WindowClosedMessage(true)); // acknowledge closure
}
private void StatusMessages_Loaded(object sender, RoutedEventArgs e)
{
// get current Trace messages
var messages = WeakReferenceMessenger.Default.Send<TraceMessagesRequest>();
if (messages != null && messages.Responses.Count > 0)
foreach (var response in messages.Responses)
foreach (var trace in response)
_traceMessages.Add(trace);
// register for Trace messages and, when they arrive, add them to list
WeakReferenceMessenger.Default.Register<TraceMessage>(this, (r, m) => _traceMessages.Add(m.Value));
}
}
StatusPage.xaml
<Window
x:Class="Multi_Window.Views.StatusWindow"
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"
Closed="StatusWindow_Closed"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView x:Name="StatusMessages" x:FieldModifier="public" VerticalAlignment="Top" Margin="20" SelectionMode="None" BorderBrush="Black" BorderThickness="1"
ItemsSource="{x:Bind _traceMessages, Mode=OneWay}"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.IsHorizontalRailEnabled="True"
ScrollViewer.IsDeferredScrollingEnabled="False"
Loaded="StatusMessages_Loaded">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel VerticalAlignment="Bottom" ItemsUpdatingScrollMode="KeepLastItemInView"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Grid>
</Window>
Other Sundry Classes
// Allows Win32 access to a Window through WinAPI
public class WindowPrimitives
{
public IntPtr HWnd { get; }
private WindowId WindowId { get; }
public AppWindow AppWindow { get; }
public Window Window { get; }
public WindowPrimitives(Window window)
{
HWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
WindowId = Win32Interop.GetWindowIdFromWindow(HWnd);
AppWindow = AppWindow.GetFromWindowId(WindowId);
Window = window;
}
}
// Message Definitions
public class CloseWindowMessage : ValueChangedMessage<bool>
{
public CloseWindowMessage(bool value) : base(value) { }
}
public class WindowClosedMessage : ValueChangedMessage<bool>
{
public WindowClosedMessage(bool value) : base(value) { }
}
public class ShutDownMessage : ValueChangedMessage<bool>
{
public ShutDownMessage(bool value) : base(value) { }
}
public class TraceMessage : ValueChangedMessage<string>
{
public TraceMessage(string value) : base(value) { }
}
public class TraceMessagesRequest : CollectionRequestMessage<List<string>>
{
}
The problem is that, on the first new TraceMessage sent after the StatusWindow has been opened, the same WeakReferenceMessenger.Default.Send() method that has been happily sending messages between the RandomMessageGenerator thread and the UI thread throws a "The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))" exception and the RandomMessageGenerator thread dies.
The exception is thrown by the WeakReferenceMessenger.Default.Send(tm); statement in the RandomMessageGenerator() method. I assume the issue is in the IMessenger interface (the only interface involved here). Briefly, as I understand it, this interface builds a table of subscribed receivers for each message type. Each receiver is then signaled on each Send().
One possibility is that references in the receiver list are all assumed to marshal to the same thread. If that were so, none of the messages between threads would work but they do before the StatusWindow is opened so that's unlikely. Changing the list of receivers is an obvious place where threading issues might occur. As WeakReferenceMessenger.Default is thread-safe, I thought adding (and deleting) registered receivers would be thread-safe but doesn't seem to be the case here. Finally, it could be the message itself (a string in this case) that is at fault. I don't know for sure but assumed that the Send method took a private copy of the message to deliver to the marshaled thread.
Could any of you please help me understand the mistake I've made here?
I did find a solution for this particular issue. As expected, it's because an object is accessed from a thread other than the thread on which it was created.
To fix the error, add
public static DispatcherQueue UIDispatcherQueue = DispatcherQueue.GetForCurrentThread();
to the App class which will allow any thread access to the UI thread DispatcherQueue. Then, change the message registration in StatusWindow.xaml.cs to
// register for Trace messages and, when they arrive, add them to list
WeakReferenceMessenger.Default.Register<TraceMessage>(this, (r, m) => App.UIDispatcherQueue.TryEnqueue(() => _traceMessages.Add(m.Value)));
This will now marshal the _traceMessages.Add call in the message handler to the UI thread, which is where
private ObservableCollection<string> _traceMessages { get; } = new();
was constructed.
This was easy enough to figure out once I realized that the point where the exception was thrown and the exception message were both rather deceptive. Although the sending of the message is the cause of the message being received, it's the attempt to handle the message on the wrong thread that really throws the exception.
At any rate, this appears to show that the message receiver handler executes on the same thread as the sender. I was hoping that "thread-safe" in the documentation meant messages were automatically marshalled to the receiver's thread.

UWP AutoSuggestionBox Search Utility using my Model

I'm Currently Working on a Project Designing a Media Player with a Library Ill post the Code for that Method, What i'm trying to Achieve is using the AutoSuggestionBox To Search through my library GridView items then Querying one of the Songs and highlighting it in the GridView
Here's my Code for the Library
private ObservableCollection<MusicLib> MusicList = new ObservableCollection<MusicLib>();
private StackPanel CurrentTarget;
private string content;
public Browsing()
{
this.InitializeComponent();
}
private async void btn_Add_Click(object sender, RoutedEventArgs e)
{
//Create a new picker
var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
//Add filetype filters.
filePicker.FileTypeFilter.Add(".mp3");
filePicker.FileTypeFilter.Add(".wav");
//Set picker start location to the video library
filePicker.SuggestedStartLocation = PickerLocationId.MusicLibrary;
var files = await filePicker.PickMultipleFilesAsync();
foreach (var file in files)
{
StorageItemThumbnail currentThumb = await file.GetThumbnailAsync(ThumbnailMode.MusicView, 200, ThumbnailOptions.UseCurrentScale);
var albumCover = new BitmapImage();
albumCover.SetSource(currentThumb);
var musicProperties = await file.Properties.GetMusicPropertiesAsync();
var musicname = musicProperties.Title;
var musicdur = musicProperties.Duration;
var artist = musicProperties.Artist;
if (artist == "")
{
artist = "Unkown";
}
var album = musicProperties.Album;
if (album == "")
{
album = "Unkown";
}
MusicList.Add(new MusicLib
{
FileName = musicname,
Artist = artist,
Album = album,
Duration = musicdur,
AlbumCover = albumCover,
MusicPath = file.Path
});
}
}
Here's my Context Menu for Deleting Tracks(It's a Work in Progress i'm Probaly missing something stupid)
private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
GridView listView = (GridView)sender;
allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView));
var a = ((FrameworkElement)e.OriginalSource).DataContext as MusicList;
content = a.text;
}
private void Remove_Click(object sender, RoutedEventArgs e)
{
foreach (var item in MusicList.ToList())
{
if (item.text == content)
{
MusicList.Remove(item);
}
}
content = "";
}
Xaml
<Grid Background="White" Name="MyGrid">
<AutoSuggestBox Name="Search" />
<GridView RightTapped="ListView_RightTapped" Name="mylist" ItemsSource="{x:Bind MusicList}" Margin="0,37,0,0">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Name="Stacky" PointerEntered="myList_PointerEntered" Orientation="Horizontal">
<Image MaxWidth="100" MaxHeight="100" Source="{Binding AlbumCover}"/>
</StackPanel>
<StackPanel >
<TextBlock Text="{Binding FileName}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Artist}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Album}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Duration}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FileName}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.Resources>
<MenuFlyout x:Name="allContactsMenuFlyout">
<MenuFlyout.Items>
<MenuFlyoutItem x:Name="Edit" Text="Edit" />
<MenuFlyoutItem x:Name="Remove" Text="Remove" Click="Remove_Click" />
</MenuFlyout.Items>
</MenuFlyout>
</GridView.Resources>
</GridView>
Model
namespace Mp3Player
{
class MusicLib
{
public string FileName { get; set; }
public string Artist { get; set; }
public string Album { get; set; }
public TimeSpan Duration { get; set; }
public string MusicPath { get; set; }
public BitmapImage AlbumCover { get; set; }
}
}
To be more specific on my Question im trying to Query one the object's from my Model to "find" that specific track so like FileName For example
I know with the Auto Suggestion box there are 3 Methods you need to use one of which is a Query Method I'm just at a loss as to what to do so if someone could provide a Example possibly, I Will appreciate it, And Post my Project on GitHub for future Ref for anyone who's new to this like i am .
AutoSuggestBox has been documented with detail of its design and how to use it along with its code examples here.
This is a typical AutoSuggestBox
<AutoSuggestBox PlaceholderText="Search" QueryIcon="Find" Width="200"
TextChanged="AutoSuggestBox_TextChanged"
QuerySubmitted="AutoSuggestBox_QuerySubmitted"
SuggestionChosen="AutoSuggestBox_SuggestionChosen"/>
Backend
private void AutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
// Only get results when it was a user typing,
// otherwise assume the value got filled in by TextMemberPath
// or the handler for SuggestionChosen.
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
//Set the ItemsSource to be your filtered dataset
//sender.ItemsSource = dataset;// Here you will filter your music list and only send back the data which matches with the text in your autosuggest box.
}
}
private void AutoSuggestBox_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args)
{
// Set sender.Text. You can use args.SelectedItem to build your text string.
}
private void AutoSuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
if (args.ChosenSuggestion != null)
{
// User selected an item from the suggestion list, take an action on it here.
}
else
{
// Use args.QueryText to determine what to do.
}
}
In your case you have the collection of MusicLib objects and you need to filter with FileName so the DataSet you send back as filtered data will be from your collection. for that you can use LINQ or just a simple foreach loop if you prefer that.
Note that when you keep filtering your collection but if you change the collection for filtering then you need to keep a second collection as well which will always have all the music tracks,and once you are comfortable with basic concepts, dont hesitate to explore : AdvancedCollectionView by WindowsCommunityToolkit which makes filtering much simpler and powerful for you.
GoodLuck

Starting camera on resume in windows store app

We are developing normal bar code scanner app for windows surface tablets. In onNavigatedTo method of page we are invoking camera..
var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
await App.camera.InitializeAsync(new MediaCaptureInitializationSettings
{
VideoDeviceId = devices[1].Id
});
cap.Source = App.camera;
cap.Visibility = Visibility.Visible;
await App.camera.StartPreviewAsync();
It is working fine.
Now App goes to background and comes back to foreground. But we are unable to invoke camera
again on resume using same code
await App.camera.StartPreviewAsync();
How to do it?
You need to use events such as Activated and VisibilityChanged :
private MediaCapture m_mediaCaptureMgr;
public MainPage()
{
this.InitializeComponent();
Window.Current.Activated+=Current_Activated;
Window.Current.VisibilityChanged+= Current_VisibilityChanged;
}
And then Initialize and StartPreview your camera on Current_Activated :
private async void Current_Activated(object sender, WindowActivatedEventArgs e)
{
try
{
m_mediaCaptureMgr = new Windows.Media.Capture.MediaCapture();
await m_mediaCaptureMgr.InitializeAsync();
cap.Source = m_mediaCaptureMgr;
await m_mediaCaptureMgr.StartPreviewAsync();
}
catch (Exception exception)
{
new MessageDialog("Unable to start the video capture.").ShowAsync();
}
}
And Stop Camera on Current_VisibilityChanged :
private async void Current_VisibilityChanged(object sender, VisibilityChangedEventArgs e)
{
try
{
await m_mediaCaptureMgr.StopPreviewAsync();
}
catch (Exception exception)
{
}
}

with a winrt user control how do i dynamically create controls based on dependency property

I'm trying to create a user control that will display a collection of images. I have the user control created with a dependency property for the collection of images. I can databind to that property and display the images fine.
However, I have hard-coded in the size of the collection and I want it to take in an arbitrary number of images and display them.
I am not sure how to dynamically create the images based on the collection of images. I'm sure there is some event that I want to respond to and create my images based on the contents of the dependency property.
public sealed partial class ImageView : UserControl
{
public ImageView()
{
this.InitializeComponent();
scrollViewer.ZoomSnapPoints.Clear();
scrollViewer.ZoomSnapPoints.Add(0.2f);
scrollViewer.ZoomSnapPoints.Add(0.6f);
scrollViewer.ZoomSnapPoints.Add(1.0f);
scrollViewer.ZoomSnapPoints.Add(1.4f);
scrollViewer.ZoomToFactor(0.4f);
}
public static readonly DependencyProperty ImagesProperty = DependencyProperty.Register("Images",
typeof(List<VMImage>), typeof(ImageView), new PropertyMetadata(new List<VMImage>(12)));
public List<VMImage> Images
{
get { return (List<VMImage>)GetValue(ImagesProperty); }
set { SetValue(ImagesProperty, value); }
}
}
<ScrollViewer Height="700" Width="700"
x:Name="scrollViewer"
MinZoomFactor="0.2"
MaxZoomFactor="5.0"
ZoomSnapPointsType="Mandatory">
<Canvas Background="Black" Width="2000" Height="2000" >
<Image Canvas.Left="{Binding Images[0].Location.X}"
Canvas.Top="{Binding Images[0].Location.Y}"
Source="{Binding Images[0].Source}" ></Image>
<Image Canvas.Left="{Binding Images[1].Location.X}"
Canvas.Top="{Binding Images[1].Location.Y}"
Source="{Binding Images[1].Source}" ></Image>
</Canvas>
</ScrollViewer>
You should make your dependency property an ObservableCollection<VMImage>. This way you can attach a handler to its CollectionChanged event and get notified of changes. Just make sure in the property changed callback of your dependency property that you add the event handler to the new value and remove it from the old value.
public static readonly DependencyProperty ImagesProperty = DependencyProperty.Register("Images",
typeof(ObservableCollection<VMImage>), typeof(ImageView), new PropertyMetadata(null, OnImagesChanged));
public ObservableCollection<VMImage> Images
{
get { return (ObservableCollection<VMImage>)GetValue(ImagesProperty); }
set { SetValue(ImagesProperty, value); }
}
private static void OnImagesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
// use wrapper to pass DependencyObject to handler
NotifyCollectionChangedEventHandler handler = (s, args) => OnCollectionChanged(target, args);
if (e.OldValue is ObservableCollection<object>)
(e.OldValue as ObservableCollection<object>).CollectionChanged -= handler;
if (e.NewValue is ObservableCollection<object>)
(e.NewValue as ObservableCollection<object>).CollectionChanged += handler;
var imageView = target as ImageView
if (imageView != null)
{
// collection has changed completely, replace all images
}
}
static void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var imageView = sender as ImageView;
if (imageView != null)
{
if (e.OldItems != null)
{
// remove images
}
if (e.NewItems != null)
{
// add images
}
}
}

Select a row on mouse click in gridview

I have a problem, I want to select a row in gridview on mouse click.
My code is this :
protected void PeopleGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onmouseover"] = "this.style.cursor='hand';this.style.textDecoration='underline';";
e.Row.Attributes["onmouseout"] = "this.style.textDecoration='none';";
e.Row.Attributes["onclick"] = ClientScript.GetPostBackClientHyperlink(this.gvdetails, "Select$" + e.Row.RowIndex);
}
}
it is not working. i don't know why?
plz suggest me regarding that.
"Thanks"
Found the tutorial about ASP.Net select row in gridview
In ASPX page under GridView tag add:
<SelectedRowStyle BackColor="Orange" />
In code behind try the following:
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
foreach (GridViewRow row in PeopleGridView.Rows) {
if (row.RowType == DataControlRowType.DataRow) {
row.Attributes["onmouseover"] =
"this.style.cursor='hand';this.style.textDecoration='underline';";
row.Attributes["onmouseout"] =
"this.style.textDecoration='none';";
// Set the last parameter to True
// to register for event validation.
row.Attributes["onclick"] =
ClientScript.GetPostBackClientHyperlink(PeopleGridView,
"Select$" + row.DataItemIndex, true);
}
}
base.Render(writer);
}
You can then catch this event using the RowCommand (something like).
private void PeopleGridView_RowCommand(object sender, System.Web.UI.WebControls.GridViewCommandEventArgs e)
{
if (e.CommandName == "Select") {
// Get the list of customers from the session
List<Customer> customerList =
Session["Customers"] as List<Customer>;
Debug.WriteLine(customerList[Convert.ToInt32(e.CommandArgument)].LastName);
}
}

Resources