0

first of all a short explanation to my app. I have to present my app on 8 to 16 screens per PC. On each screen is another part of the app. Some are showing videos in an endless repeat, some are showing an endless repeating slideshow and some have even more functionality. Some of the screens are even touchscreens, so it also has to be interactive. But when I call 16 windows on one thread, you can imagine what happens... So I use the following option: Inside the App.xaml.cs I use a foreach and go through all screens. Each screen has a configitem in a xml-file and is called with the screennumber and the kind of what it should show.

But almost at any start it crashes with another errormessage. I only can think of a memoryerror with this kind of multiple GUI threads. Sometimes I get unknown errors, sometimes the XML-Query crashes, sometimes it's the IOStream, and so on...

Has someone an idea what I can do better? Where can I optimize the settings? Or how can I show multiple windows with videos and so on without freezing each other?

For a better understanding what I am doing, I paste my code here.

Here is the XAML:

<Window x:Class="ASA_Videowand.WheelOfFortune"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WheelOfFortune" 
    Name="WheelWindow"
    WindowStyle="None"
    Height="1080" 
    Width="1920"
    Loaded="WheelOfFortune_OnLoaded">
<Window.Resources>
    <Style x:Key="ImgZIndexStyle" TargetType="{x:Type Image}">
        <Setter Property="Panel.ZIndex" Value="2"/>
        <Style.Triggers>
            <Trigger Property="Image.Opacity" Value="1">
                <Setter Property="Panel.ZIndex" Value="3"/>
            </Trigger>
        </Style.Triggers>
    </Style>
    <Storyboard x:Key="FaderStoryboardHide1Show2">
        <DoubleAnimation Storyboard.TargetName="FirstImage" 
         Storyboard.TargetProperty="Opacity"
         To="0" Duration="0:00:01" />
        <DoubleAnimation Storyboard.TargetName="SecondImage" 
         Storyboard.TargetProperty="Opacity"
         To="1" Duration="0:00:01" />
    </Storyboard>
    <Storyboard x:Key="FaderStoryboardHide2Show1">
        <DoubleAnimation Storyboard.TargetName="SecondImage" 
         Storyboard.TargetProperty="Opacity"
         To="0" Duration="0:00:01" />
        <DoubleAnimation Storyboard.TargetName="FirstImage" 
         Storyboard.TargetProperty="Opacity"
         To="1" Duration="0:00:01" />
    </Storyboard>
</Window.Resources>
<Grid>
    <Grid Name="SlideShowGrid" ZIndex="0">
        <Image x:Name="FirstImage" Stretch="UniformToFill" Style="{StaticResource ImgZIndexStyle}" Opacity="1" />
        <Image x:Name="SecondImage" Stretch="UniformToFill" Style="{StaticResource ImgZIndexStyle}" Opacity="0"/>
    </Grid>
    <Canvas Name="VideoCanvas" ZIndex="0">
        <Button Name="VideoButton" Click="VideoButton_OnClick">
            <MediaElement Height="{Binding ElementName=WheelWindow, Path=Height}" 
                          Width="{Binding ElementName=WheelWindow, Path=Width}"
                          UnloadedBehavior="Manual"
                          MediaEnded="MarketingVideoMediaElement_OnMediaEnded"
                          Name="MarketingVideoMediaElement" />
        </Button>
    </Canvas>
    <Grid Name="WheelGrid" ZIndex="1">
        <Button Name="SpinWheelButton" Click="SpinWheelButton_OnClick">
            <Grid>
                <Image Source="pics/gluecksrad_background.jpg" Stretch="UniformToFill" />
                <Border>
                    <Border.Effect>
                        <DropShadowEffect Direction="330" Opacity="0.7" ShadowDepth="5" Color="Black" BlurRadius="3" RenderingBias="Performance" />
                    </Border.Effect>
                    <Image Name="ArrowImage" Source="pics/pfeil.png" Height="300" RenderTransformOrigin="0.5,0.5" Margin="414,330,1390,420">
                        <Image.RenderTransform>
                            <RotateTransform />
                        </Image.RenderTransform>
                    </Image>
                </Border>
            </Grid>
        </Button>
    </Grid>
</Grid>

And the WheelOfFortune.xaml.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Microsoft.Win32;
using Panel = System.Windows.Controls.Panel;

namespace ASA_Videowand
{
    public partial class WheelOfFortune
    {
        private int _listCounter;
        private int _imageCounter;
        private int _countTimer;
        private int _screenNumber;
        private List<string> _fileList;
        private DoubleAnimation _rotateAnimation;
        private readonly int _imageChangeTime;
        private readonly string _myPath;
        private readonly List<int> _targetAngelList = new List<int>();
        private readonly DispatcherTimer _videoTimer = new DispatcherTimer();
        private readonly DispatcherTimer _slideShowTimer = new DispatcherTimer();
        private static readonly object MyLock = new object();

        public WheelOfFortune(int screenNumber, string configName)
        {
            lock (MyLock)
            {
                InitializeComponent();
            }
            BuildList();
            CreateVideoTimer();
            _screenNumber = screenNumber;
            var regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
            var openSubKey = regKey.OpenSubKey(@"SOFTWARE\ASA\Videowand", false);
            if (openSubKey != null)
            {
                _myPath = openSubKey.GetValue("ProgramPath").ToString();
                _imageChangeTime = Convert.ToInt32(openSubKey.GetValue("SlideShowTimer"));
            }
            GetDataFromHdd(configName);
        }

        private void GetDataFromHdd(string configName)
        {
            foreach (var fileList in from subDirectory in Directory.GetDirectories(_myPath, "*", SearchOption.AllDirectories) 
                                 where subDirectory.Contains(configName) 
                                 select Directory.GetFiles(subDirectory, "*", SearchOption.TopDirectoryOnly).ToList())
            {
                if (fileList[0].ToUpper().Contains(".JPG") || fileList[0].ToUpper().Contains(".GIF") ||
                fileList[0].ToUpper().Contains(".JPEG") || fileList[0].ToUpper().Contains(".PNG") ||
                fileList[0].ToUpper().Contains(".TIFF") || fileList[0].ToUpper().Contains(".BMP"))
                {
                    _fileList = fileList;
                    BuildSlideShow();
                }
                else
                    ShowMovie(fileList[0]);
            }
        }

        private void ShowMovie(string fileName)
        {
            CreateVideoStoryboard();
            Panel.SetZIndex(VideoCanvas, 2);
            MarketingVideoMediaElement.Source = new Uri(fileName);
        }

        private void BuildSlideShow()
        {
            Panel.SetZIndex(SlideShowGrid, 2);
            WheelGrid.Opacity = 0;
            FirstImage.Source = new BitmapImage(new Uri(_fileList[0]));
            _slideShowTimer.Interval = new TimeSpan(0, 0, _imageChangeTime);
            _slideShowTimer.Tick += Timer_Tick;
            _slideShowTimer.Start();
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            System.Windows.Controls.Image newImage;
            Storyboard tempStoryboard;
            if (FirstImage.Opacity == 1)
            {
                tempStoryboard = (Storyboard) FindResource("FaderStoryboardHide1Show2");
                newImage = SecondImage;
            }
            else
            {
                tempStoryboard = (Storyboard)FindResource("FaderStoryboardHide2Show1");
                newImage = FirstImage;
            }
            if (_imageCounter >= _fileList.Count - 1)
                _imageCounter = 0;
            else
                _imageCounter++;
            newImage.Source = new BitmapImage(new Uri(_fileList[_imageCounter]));
            tempStoryboard.Begin();
        }

        private void CreateVideoTimer()
        {
            _videoTimer.Interval = TimeSpan.FromSeconds(1);
            _videoTimer.Tick += VideoTimerOnTick;
        }

        private void VideoTimerOnTick(object sender, EventArgs eventArgs)
        {
            _countTimer++;
            if (_countTimer <= 8) return;
            Panel.SetZIndex(VideoCanvas, 2);
            _videoTimer.Stop();
            _countTimer = 0;
        }

        private void BuildList()
        {
            _targetAngelList.Add(11); // 1 Chip
            _targetAngelList.Add(33); // 1 Chip
            _targetAngelList.Add(56); // 1 Chip
            _targetAngelList.Add(78); // 0 Chips
            _targetAngelList.Add(101); // 2 Chips
            _targetAngelList.Add(123); // 0 Chips
            _targetAngelList.Add(146); // 1 Chip
            _targetAngelList.Add(168); // 1 Chip
            _targetAngelList.Add(191); // 1 Chip
            _targetAngelList.Add(214); // 1 Chip
            _targetAngelList.Add(237); // 1 Chip
            _targetAngelList.Add(259); // 1 Chip
            _targetAngelList.Add(281); // 0 Chips
            _targetAngelList.Add(304); // 2 Chips
            _targetAngelList.Add(327); // 0 Chips
            _targetAngelList.Add(349); // 1 Chip
        }

        private void SpinWheelButton_OnClick(object sender, RoutedEventArgs e)
        {
            _countTimer = 0;
            var targetAngel = new Random();
            _listCounter = targetAngel.Next(0, _targetAngelList.Count - 1);
            _rotateAnimation.To = 1800 + _targetAngelList[_listCounter];
            ((Storyboard)Resources["Storyboard"]).Begin();
        }

        private void CreateVideoStoryboard()
        {
            var spinningStoryboard = new Storyboard
            {
                Duration = new Duration(TimeSpan.FromMilliseconds(2500)),
            };
            _rotateAnimation = new DoubleAnimation
            {
                From = 0,
                To = 1800 + _targetAngelList[_listCounter],
                Duration = spinningStoryboard.Duration,
                DecelerationRatio = 0.9
            };
            Storyboard.SetTarget(_rotateAnimation, ArrowImage);
            Storyboard.SetTargetProperty(_rotateAnimation, new PropertyPath("(UIElement.RenderTransform).(RotateTransform.Angle)"));
            spinningStoryboard.Children.Add(_rotateAnimation);
            Resources.Add("Storyboard", spinningStoryboard);
        }

        private void VideoButton_OnClick(object sender, RoutedEventArgs e)
        {
            Panel.SetZIndex(VideoCanvas, 0);
            _videoTimer.Start();
        }

        private void MarketingVideoMediaElement_OnMediaEnded(object sender, RoutedEventArgs e)
        {
            MarketingVideoMediaElement.Position = new TimeSpan(0, 0, 0, 0, 1);
            MarketingVideoMediaElement.Play();
        }

        private void WheelOfFortune_OnLoaded(object sender, RoutedEventArgs e)
        {
            ShowOnMonitor();
        }

        private void ShowOnMonitor()
        {
            Screen[] screenArray = Screen.AllScreens;
            if (_screenNumber >= screenArray.Length)
            {
                _screenNumber = 0;
            }
            Left = Convert.ToInt32(screenArray[_screenNumber].Bounds.Left);
            Top = Convert.ToInt32(screenArray[_screenNumber].Bounds.Top);
            WindowState = WindowState.Maximized;
        }
    }
}
Marcel Grüger
  • 885
  • 1
  • 9
  • 25
  • 1
    What error message? What is the exact exception, including the call stack? Where did it occur? Did you try debugging the application? Without the exact error message and callstack, the rest of the information is useless. The only thing I can guess is that you are trying to modify a UI component from a background thread. This isn't allowed in any version of Windows. As for multiple GUI threads - there aren't any unless you created them explicitly. An application has only one GUI thread. – Panagiotis Kanavos Mar 04 '15 at 14:53
  • *But when I call 16 windows on one thread, you can imagine what happens* - nope, what happens? – Sinatr Mar 04 '15 at 15:04
  • As I already wrote: many different errors. but only when I use at least 8 monitors. here in my office, with only 2 screens, everything works fine. And its hard to copy and paste the errors from the applicationlog in windows, because everything is in german, but if you want, here are the last errors: http://pastebin.com/hCgyHwik – Marcel Grüger Mar 04 '15 at 15:15
  • @Sinatr: One video works fine, the other ones are freezing. The slideshows are stopping, and so on. Especially, because the videos are running in endless loops, so there are no breaks, where the thread can handle the other windows. – Marcel Grüger Mar 04 '15 at 15:16
  • 1
    possible duplicate of [What is a NullReferenceException and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Sinatr Mar 04 '15 at 15:17
  • You have a null reference exception, _targetAngelList or _rotateAnimation is null. You should read http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it. Probably nothing to do with threading. However if I look at your code, make it first working without multi threading, you do probably not need it at all. – Peter Mar 04 '15 at 15:19
  • guys, please read all errors. there are more than this one. And it does not work without multithreading. How will you show 16 videos that all are rendered on one thread? -.- – Marcel Grüger Mar 04 '15 at 15:36
  • 1
    Realize any given process is only allowed to use so much memory. Have 16 videos/powerpoints/etc. loading, rendering, playing, all at once could be a candidate for reaching that maximum. Instead, why not have one application which spins up 16 .exes, and by passing it a XML command line argument, have the application load the information and play what it needs to play. The rest is figuring out how to adjust layout of the windows. – Kcvin Mar 04 '15 at 15:52
  • Focus on one exception at a time. Create [a good, _minimal_, _complete_ code example](http://stackoverflow.com/help/mcve). Provide _specific_ and _precise_ details about what is actually going wrong; in this case, it means the full details of the first exception that occurs. – Peter Duniho Mar 04 '15 at 16:19

0 Answers0