c# wpf MediaElement black flash - c#

When MediaElement starts playing video it shows like a black frame for a moment. Here is the code:
<Window x:Class="MediaElementTest.MainWindow" /* */
Title="MainWindow" Height="350" Width="525" Background="Red">
<Grid>
<ContentControl x:Name="contentControl"/>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
NextState();
}
public void NextState()
{
var content = new VideoState();
contentControl.Content = content;
}
}
And
<UserControl x:Class="MediaElementTest.VideoState" /* */
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<MediaElement x:Name="videoPlayer" MediaEnded="videoPlayer_MediaEnded" LoadedBehavior="Manual" />
</Grid>
</UserControl>
public partial class VideoState : UserControl
{
public VideoState()
{
InitializeComponent();
videoPlayer.Source = new Uri("C:\\wpf\\bin\\Debug\\data\\start.mp4");
//videoPlayer.Position = TimeSpan.FromMilliseconds(100); //!!! WORKS FINE WITH IT
videoPlayer.Play();
}
private void videoPlayer_MediaEnded(object sender, RoutedEventArgs e)
{
videoPlayer.Source = null;
videoPlayer = null;
GC.Collect();
MainWindow wnd = (MainWindow)Application.Current.MainWindow;
wnd.NextState();
}
}
If I set videoPlayer.Position to like 100 milliseconds it works fine. How can I get rid of this black frame. I've tried to set ScrubbingEnabled="true"and do something like :
videoPlayer.Play();
videoPlayer.Pause();
videoPlayer.Play();
But there is no difference and black popup still occurs. If I set videoPlayer.Position to 0ms at mediaEnded event and play it works also fine. I would appreciate any help.

Get the Loaded event of your User Control and move the below code in the handler of Loaded event in your User control's code behind file
videoPlayer.Source = new Uri("C:\\wpf\\bin\\Debug\\data\\start.mp4");
videoPlayer.Play();
Once the VideoState user control is properly loaded as the content of your window, only then you execute further logic to play the video. I hope that it will solve the black screen problem.

Related

How can i change a Page in my wpf Main Window?

i want to switch pages that are hosted on my main window. The first page (at App Start) is beeing shown correctly. But if i want to change the page it won´t happen. I even don´t get an error. It just shows the first page! Here´s my code:
The constructor of MainWindow:
public MainWindow(SchraubUser _schraubUser, string page = "")
{
schraubUser = _schraubUser;
db = new AccessDatabase(schraubUser._DATABASE_PATH);
ViewModel.ViewModel wzViewModel = new ViewModel.ViewModel(schraubUser, db);
InitializeComponent();
if (page == "")
{
Main.Content = new View.Werkzeug_Window(wzViewModel);
}
else
{
Main.Content = new View.Freigaben(wzViewModel);
}
}
At Application start the optional variable is "" so the mainwindow will display View.Werkzeug_Window (works correctly).
Here`s the code for changing the page:
private void Button_Freigaben_Click(object sender, RoutedEventArgs e)
{
mainWindow = new MainWindow(sb_vm.schraubUser, "Freigabe");
}
But it will still show the first page. Why is that?
XAML of MainWindow:
<Window x:Class="SchrauberDB.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:local="clr-namespace:SchrauberDB"
mc:Ignorable="d"
Title="MainWindow" Height="750" Width="1100"
WindowState="Maximized">
<Grid x:Name="mainGrid">
<Frame x:Name="Main" />
</Grid>
</Window>
This is so embarrassing...
private void Button_Freigaben_Click(object sender, RoutedEventArgs e)
{
mainWindow = new MainWindow(sb_vm.schraubUser, "Freigabe");
mainWindow.Show();
}

How to recenter UserControl(s) in Window

We have BaseDialogView with next xaml code:
<Window x:Class="Test.BaseDialogView"
Height="475"
WindowStartupLocation="CenterOwner"
SizeToContent="Height"
ResizeMode="CanResize"
SizeChanged="Window_SizeChanged">
<ContentControl Content="{Binding ContentPage}" />
</Window>
BaseDialogViewModel class:
public class BaseDialogViewModel : AbstractNotifyPropertyChangedItem
{
private UserControl contentPage;
public UserControl ContentPage
{
get { return this.contentPage; }
set
{
if (this.contentPage != value)
{
this.contentPage = value;
this.RaisePropertyChanged(() => this.ContentPage);
}
}
}
}
The usage is very simple:
BaseDialog dialog = new BaseDialog();
BaseDialogViewModel dialogVm = new BaseDialogViewModel();
dialog.Owner = Application.Current.MainWindow;
dialog.DataContext = dialogVm ;
dialogVm.ContentPage = new ActivationView();
dialogVm.ContentPage.DataContext = new ActivationViewModel();
So basically once you have an instance of BaseDialog, you just set ContentControl (by setting dialog.ContentPage and dialog.ContentPage.DataContext).
ActivationView is very simple. For example:
<UserControl x:Class="Test.ActivationView" d:DesignHeight="400" d:DesignWidth="700" MaxWidth="700">
<Grid> .... what ever you need
</UserControl>
The problem is that different UserControls windows are set, which have different width and height. When the first UserControl is shown it's place in the center of the MainWindow, which is ok. Then each new userControl is shown, but it's not centered. How do I center the BaseDialog window for each usercontrol?
I tried this (BaseDialogView):
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
Window w = sender as Window;
this.Top = (Application.Current.MainWindow.Height - w.ActualHeight) / 2;
}
but does not work ok (Some usercontrols are still not pixel centered). I also tried adding this to BaseDialogView Xaml
<Window .... VerticalAlignment="Center">
but it seems to be working only for initial instance.
First of you should really consider propperly implementing the MVVM pattern.
It will make your live easier, also instead of centering the element manually in the size change event you should set its owner and WindowStartupLocation by using
Window win = new Window();
win.Content = new MyUserControl();
win.Owner = this;
win.WindowStartupLocation = WindowStartupLocation.CenterOwner;
Instead of having one window where you keep changing the content i would consider having different windows..but that may vary on your specific case

When changing call order of UIElement.CaptureMouse() on Canvas containing two Image, I get different result

I'm now just trying to create a simple image viewer with panning and zooming, for studying WPF.
I wrote my XAML code like this:
<Window x:Class="PanningImageTest.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:local="clr-namespace:PanningImageTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Border Name="panBorder" ClipToBounds="True">
<Canvas Name="panImage" MouseLeftButtonDown="Image_MouseLeftButtonDown"
MouseMove="Image_MouseMove"
MouseLeftButtonUp="Image_MouseLeftButtonUp">
<!-- Two Image is intended, as in real situation,
they will use different sources -->
<Image Source="Wallpaper.jpg" Stretch="None"/>
<Image Source="Wallpaper.jpg" Stretch="None"/>
</Canvas>
</Border>
</Grid>
</Window>
And wrote my code like this:
using System.Windows;
using System.Windows.Media;
namespace PanningImageTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private Point _start;
private Point _origin;
private void Image_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.panImage.CaptureMouse();
_start = e.GetPosition(this.panBorder);
_origin.X = this.panImage.RenderTransform.Value.OffsetX;
_origin.Y = this.panImage.RenderTransform.Value.OffsetY;
}
private void Image_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (!this.panImage.IsMouseCaptured)
{
return;
}
Point mousePos = e.GetPosition(this.panBorder);
Matrix matrix = this.panImage.RenderTransform.Value;
matrix.OffsetX = _origin.X + (mousePos.X - _start.X);
matrix.OffsetY = _origin.Y + (mousePos.Y - _start.Y);
this.panImage.RenderTransform = new MatrixTransform(matrix);
}
private void Image_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.panImage.ReleaseMouseCapture();
}
}
}
If I call this.panImage.CaptureMouse() BEFORE the _start = ... etc ... lines, All the Images just teleports to the position of the mouse as soon as I clicked somewhere on the image.
Like this:
Call before
But if I call the same function after the lines, like the following, it just works as intended:
_start = e.GetPosition(this.panBorder);
_origin.X = this.panImage.RenderTransform.Value.OffsetX;
_origin.Y = this.panImage.RenderTransform.Value.OffsetY;
this.panImage.CaptureMouse();
Like this:
Call After
If I use only one Image tag in Canvas, it works nicely in both cases.
I tried changing .NET versions, moving events to Border instead of Canvas, but everything just failed to explain these results.
I have no idea why this happens. Can anyone give some explanations?
MouseMove event has started to be fired even the MouseLeftButtonDown method has not yet finished.
So you call CaptureMouse() method as the last line, and use the following check as a guard to prevent the image from being dragged when you have not yet gotten the value of _origin.
if (!this.panImage.IsMouseCaptured)
{
return;
}
You need to set the start position and the coordinates before you start to calculate the offsets. Otherwise you get the offsets wrong. So it makes no sense to capture the mouse before you have done this.
Note that the MouseMove event will be raised as soon as you move the mouse(all the time basically) but until you have captured it, the event handler will just return without moving the image by setting its RenderTransform property.
So you should set the start position and the X and Y coordinates and then move the image based on these. Not the other way around.

KinectColorViewer SDK 1.7

I'm trying to make KinectColorViewer to work with SDK 1.7 but without success. I can display video picture only if I manually copy pixels from camera to Image element.
I have the following XAML:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:k="http://schemas.microsoft.com/kinect/2013"
xmlns:WpfViewers="clr-namespace:Microsoft.Samples.Kinect.WpfViewers;assembly=Microsoft.Samples.Kinect.WpfViewers" x:Class="KinectD.Camera"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="500"
Title="Camera">
<Grid>
<k:KinectUserViewer k:KinectRegion.KinectRegion="{Binding ElementName=kinectRegion}" Height="100" HorizontalAlignment="Center" VerticalAlignment="Top" />
<k:KinectSensorChooserUI HorizontalAlignment="Center" VerticalAlignment="Top" x:Name="sensorChooserUi" />
<k:KinectRegion x:Name="kinectRegion">
<Grid>
<k:KinectCircleButton Label="Menu" HorizontalAlignment="Right" Height="200" VerticalAlignment="Top" Click="MenuButtonOnClick" >
<StackPanel>
<Image Source="Images/smile.png" Height="30"/>
</StackPanel>
</k:KinectCircleButton>
</Grid>
</k:KinectRegion>
<WpfViewers:KinectColorViewer HorizontalAlignment="Left" Height="240" Margin="10,10,0,0" VerticalAlignment="Top" Width="320" Kinect="{Binding ElementName=sensorChooserUi, Mode=OneWay, Path=Kinect}"/>
</Grid>
And XAML.CS:
public partial class Camera : Page
{
#region "Kinect"
private KinectSensorChooser sensorChooser;
#endregion
public Camera()
{
this.InitializeComponent();
// initialize the sensor chooser and UI
this.sensorChooser = new KinectSensorChooser();
//Assign the sensor chooser with the sensor chooser from the mainwindow.
//We are reusing the sensorchoosing declared in the first window that can in contact with kinect
this.sensorChooser = Generics.GlobalKinectSensorChooser;
//subscribe to the sensorChooserOnKinectChanged event
this.sensorChooser.KinectChanged += SensorChooserOnKinectChanged;
//Assign Kinect Sensorchooser to the sensorchooser we got from our static class
this.sensorChooserUi.KinectSensorChooser = sensorChooser;
// Bind the sensor chooser's current sensor to the KinectRegion
var regionSensorBinding = new Binding("Kinect") { Source = this.sensorChooser };
BindingOperations.SetBinding(this.kinectRegion, KinectRegion.KinectSensorProperty, regionSensorBinding);
}
private void SensorChooserOnKinectChanged(object sender, KinectChangedEventArgs args)
{
bool error = false;
if (args.OldSensor != null)
{
try
{
args.OldSensor.DepthStream.Range = DepthRange.Default;
args.OldSensor.SkeletonStream.EnableTrackingInNearRange = false;
args.OldSensor.DepthStream.Disable();
args.OldSensor.SkeletonStream.Disable();
args.OldSensor.ColorStream.Disable();
}
catch (InvalidOperationException)
{
// KinectSensor might enter an invalid state while enabling/disabling streams or stream features.
// E.g.: sensor might be abruptly unplugged.
error = true;
}
}
if (args.NewSensor != null)
{
try
{
args.NewSensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
args.NewSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
args.NewSensor.SkeletonStream.Enable();
}
catch (InvalidOperationException)
{
error = true;
// KinectSensor might enter an invalid state while enabling/disabling streams or stream features.
// E.g.: sensor might be abruptly unplugged.
}
}
if (!error)
kinectRegion.KinectSensor = args.NewSensor;
}
private void MenuButtonOnClick(object sender, RoutedEventArgs e)
{
//Unsubscribe to the sensorchooser's event SensorChooseronkinectChanged
this.sensorChooser.KinectChanged -= SensorChooserOnKinectChanged;
(Application.Current.MainWindow.FindName("_mainFrame") as Frame).Source = new Uri("MainMenu.xaml", UriKind.Relative);
}
}
In tutorial I was following (http://channel9.msdn.com/Series/KinectQuickstart/Camera-Fundamentals) instructor just drops KinectColorViewer to a screen, sets path and it's working.
The KinectColorViewer available in the KinectWpfViewers assembly is used in the "Kinect Explorer" example, and that is the best place to see how it is used and behaves. From this example you will find that the proper way to initialize the viewer in the XAML and the bindings that are necessary.
From the code you posted, you appear to binding the Kinect itself (a reference to the hardware) to the KinectColorViewer, which is not what it is expecting. You need to be setting a reference to a KinectSensorManager class, which is part of the KinectWpfViewers assembly.
Here is a simplified XAML with a KinectColorViewer
<Window x:Class="Microsoft.Samples.Kinect.KinectExplorer.KinectWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Microsoft.Samples.Kinect.KinectExplorer"
xmlns:kt="clr-namespace:Microsoft.Samples.Kinect.WpfViewers;assembly=Microsoft.Samples.Kinect.WpfViewers"
Title="Kinect Explorer" Width="812" Height="768">
<Grid>
<kt:KinectColorViewer x:Name="ColorViewer" KinectSensorManager="{Binding KinectSensorManager}" CollectFrameRate="True" RetainImageOnSensorChange="True" />
</Grid>
</Window>
Then you XAML.CS constructor will look something similar to:
public KinectWindow()
{
this.viewModel = new KinectWindowViewModel();
// The KinectSensorManager class is a wrapper for a KinectSensor that adds
// state logic and property change/binding/etc support, and is the data model
// for KinectDiagnosticViewer.
this.viewModel.KinectSensorManager = new KinectSensorManager();
Binding sensorBinding = new Binding("KinectSensor");
sensorBinding.Source = this;
BindingOperations.SetBinding(this.viewModel.KinectSensorManager, KinectSensorManager.KinectSensorProperty, sensorBinding);
// Attempt to turn on Skeleton Tracking for each Kinect Sensor
this.viewModel.KinectSensorManager.SkeletonStreamEnabled = true;
this.DataContext = this.viewModel;
InitializeComponent();
}
Review the "Kinect Explorer" example for complete details.
I had the same problem with using KinectSensorManager. It turns out you need to call to Microsoft.Samples.Kinect.Wpf.Viewers and not just the kinect.dll, kinect.toolkit.dll, and kinect.controls.dll.
However, when I implemented KinectSensorManager, then the KinectUI and SensorChooser stopped working on my xaml interface.

Setting control to be content of several controls

I have a control which i'm putting in dialog as a content. Due to relization of this dialog i have to create it every time when i need it(Show/Hide won't do the trick). I want my control to remember field content beetween calls. While i can apply viewmodel to achieve this i prefer just keep control as a field and assing it as content of dialog every time i need it. But i run into following error:
"Specified element is already the logical child of another element. Disconnect it first."
I tried to assing null to dialog window's content before closing it, but it doesn't solve the problem. Is there anything i can do?
Setting window.Content = null works fine for me. Following is the code I used:
public partial class MainWindow : Window
{
TextBlock textBlock = new TextBlock();
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
TestWindow testWindow = new TestWindow();
testWindow.Content = textBlock;
testWindow.Closing += HandleTestWindowClosing;
testWindow.Show();
}
void HandleTestWindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
var testWindow = sender as TestWindow;
if(testWindow!=null)
{
testWindow.Content = null;
testWindow.Closing -= HandleTestWindowClosing;
}
}
}
Check out the following working example. It isn't exactly your scenario, but pretty close. The key is setting the 'Child' property to null. It moves the TextBox from the top border to the bottom.
<Window x:Class="SO.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button Grid.Row="0" Click="Move_Click">Move</Button>
<Border x:Name="topBorder" Grid.Row="1">
<TextBlock x:Name="ctrl">Some Text Block</TextBlock>
</Border>
<Border x:Name="bottomBorder" Grid.Row="2"/>
</Grid>
</Window>
and the code behind:
using System.Windows;
namespace SO
{
public partial class MainWindow :Window
{
public MainWindow( )
{
InitializeComponent( );
}
private void Move_Click( object sender, RoutedEventArgs e )
{
this.topBorder.Child = null;
this.bottomBorder.Child = this.ctrl;
}
}
}

Categories