Vlc.DotNet WPF video background issue - wpf

There is my code. I see the video in the top right corner, where control itself is located, but the main grid background is empty. It's supposed to take video through VisualBrush, right? I've googled few samples and they all use the same trick, but it doesn't work...
I've also tried to put some controls on top of the control, but nothing shows through, because I assume it's using WinForms control inside, which is top-most.
So how do I get this video as the background?
<Grid>
<vlc:VlcControl x:Name="myVlcControl" Width="100" Height="100" HorizontalAlignment="Right" VerticalAlignment="Top" />
<Grid>
<Grid.Background>
<VisualBrush Stretch="Uniform">
<VisualBrush.Visual>
<Image Source="{Binding VideoSource, ElementName=myVlcControl}" />
</VisualBrush.Visual>
</VisualBrush >
</Grid.Background>
</Grid>

MediaElement supports RTSP just fine, but it may not support the encoding/container you're trying to work with. The following produces a working streaming MediaElement, and uses a VisualBrush to paint the background of a Grid with the MediaElement:
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<MediaElement x:Name="MyPlayer"
Width="640"
Height="480"
LoadedBehavior="Play"
Source="rtsp://granton.ucs.ed.ac.uk/domsdemo/v2003-1.wmv" />
<Grid Grid.Row="1"
Width="320"
Height="240">
<Grid.Background>
<VisualBrush Stretch="Uniform" Visual="{Binding ElementName=MyPlayer}" />
</Grid.Background>
</Grid>
</Grid>

#Kolorowezworki made Airhack control to workaround this issue.
Example:
<airhack:AirControl DataContext="{Binding}">
<airhack:AirControl.Front>
<Image Source="{Binding VideoSource, ElementName=myVlcControl}" />
</airhack:AirControl.Front>
<airhack:AirControl.Back>
<vlc:VlcControl x:Name="myVlcControl" Width="100" Height="100" HorizontalAlignment="Right" VerticalAlignment="Top" />
</airhack:AirControl.Back>
</airhack:AirControl>
NOTE: By default AirControl does't support DataContext Binding, to solve this issue fork or copy repository and implement DataContext support by passing it 'airhack' window.
Example:
public AirControl()
{
InitializeComponent();
alpha = new Alpha(this);
alpha.DataContext = DataContext;
DataContextChanged += (sender, args) => alpha.DataContext = DataContext;
}

Related

Freezing part of a canvas when scrolling in WPF?

I'm a bit of a novice with WPF and XAML. I'm working on a piano roll interface for reading MIDI files, which, so far, looks something like this:
https://i.imgur.com/hBJZhnH.png
I have a canvas for the whole piano roll (wrapped around a ScrollViewer for horizontal and vertical scrolling). In that canvas, I have a grdPiano grid for drawing the piano notes, a grdGridColours grid for drawing the horizontal row fill colours, a cnvGridLines canvas where I draw the vertical grid lines (this is done in C# code), and a grdNotes grid where I draw the MIDI notes in C# code.
This works fine, but when I scroll horizontally, the piano keys (grdPiano) scroll out of view. I want it such that if I scroll vertically, everything scrolls, but if I scroll horizontally, the piano keys stay frozen in view on the left side of the screen. I've been messing around with nested ScrollViewers but I can't seem to get it to work.
Here's my XAML:
<ScrollViewer x:Name="srlPianoScroll" Margin="125,20,0,0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Canvas x:Name="cnvPianoRoll" HorizontalAlignment="Left" Height="1592" VerticalAlignment="Center" Width="132">
<Grid x:Name="grdPiano" HorizontalAlignment="Left" Height="1638" VerticalAlignment="Center" Width="132" Canvas.Top="-8">
<Grid.RowDefinitions>
<!--Row definitions...-->
</Grid.RowDefinitions>
<!--Drawing piano notes...-->
</Grid>
<Grid x:Name="grdGridColours" HorizontalAlignment="Left" Height="1628" VerticalAlignment="Center" Width = "0" Canvas.Top="2" Canvas.Left="132" Panel.ZIndex="1">
<Grid.RowDefinitions>
<!--Row definitions...-->
</Grid.RowDefinitions>
<!--Drawing horizontal fill colours...-->
</Grid>
<Canvas x:Name="cnvGridLines" HorizontalAlignment="Left" Height="1592" VerticalAlignment="Center" Width = "0" Canvas.Top="2" Canvas.Left="132" Panel.ZIndex="2"/>
<!--Vertical grid lines are drawn programatically.-->
<Grid x:Name="grdNotes" HorizontalAlignment="Left" Height="1628" VerticalAlignment="Center" Width = "0" Canvas.Top="2" Canvas.Left="132" Panel.ZIndex="3">
<Grid.RowDefinitions>
<!--Row definitions...-->
</Grid.RowDefinitions>
</Grid>
</Canvas>
</ScrollViewer>
Thanks!
Try binding grdPiano's Canvas.Left to the scrollviewer's HorizontalOffset.
When the scrollviewer scrolls horizontally, the binding will update Canvas.Left to be on the left edge of the visible area. You can use a converter to add an offset, if needed.
Here is an example:
XAML
<Window x:Class="WpfApp38.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:WpfApp38"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:OffsetConverter x:Key="OffsetConverter" />
</Window.Resources>
<ScrollViewer Name="sv" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Canvas Width="10600" Height="500">
<!-- Rectangle that stays on the left side, your grdPiano -->
<Rectangle Canvas.Left="{Binding ElementName=sv, Path=HorizontalOffset}" Canvas.Top="0" Width="50" Height="500" Fill="Blue" Panel.ZIndex="1" />
<!-- Rectangle that stays on the left side, your grdPiano - - using the OffsetConverter to offset it 300 to the right -->
<!--<Rectangle Canvas.Left="{Binding ElementName=sv, Path=HorizontalOffset, Converter={StaticResource OffsetConverter}, ConverterParameter=300}" Canvas.Top="0" Width="50" Height="500" Fill="LightBlue" Panel.ZIndex="1" />-->
<!-- Rectangles that scrolls normally -->
<Rectangle Canvas.Left="150" Canvas.Top="50" Width="200" Height="25" Fill="Black" />
<Rectangle Canvas.Left="50" Canvas.Top="100" Width="100" Height="25" Fill="Black" />
<Rectangle Canvas.Left="350" Canvas.Top="200" Width="250" Height="25" Fill="Black" />
<Rectangle Canvas.Left="600" Canvas.Top="235" Width="10000" Height="25" Fill="Black" />
</Canvas>
</ScrollViewer>
</Window>
And the code for the converter:
public class OffsetConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double scrollViewerHorizontalOffset && parameter is string s)
{
double offsetAmount;
double.TryParse(s, out offsetAmount);
return scrollViewerHorizontalOffset + offsetAmount;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Control blocking input to lower control

Hopefully this is a WPF issue and not a esri issue. I have an ESRI map control, and I am placing a control on top of the map. When I do this, the map no longer receives input(I can't move around or click anything). If I modify the z-index of the top control to place it behind the map, the map works fine again.
<Grid Name="MapGrid" DockPanel.Dock="Top" >
<Grid Name="MapGrid" DockPanel.Dock="Top" >
<esri:MapView x:Name="MainMapView" Panel.ZIndex="0" KeyDown="MyMapView_KeyDown" MapViewTapped="MyMapView_MapViewTapped" Map="{Binding Source={StaticResource MapResource}}" WrapAround="True" Grid.Row="0" Grid.Column="0" Initialized="MyMapView_Initialized" >
</esri:MapView>
<Expander Header="Properties" ExpandDirection="Right" Panel.ZIndex="-1">
<ItemsControl Background="Transparent" Height="700" Width="500" HorizontalAlignment="Left" VerticalAlignment="Top" Name="FeaturePropertyRegion" cal:RegionManager.RegionName="FeaturePropertyRegion" />
</Expander>
</Grid>
This code works, but if I raise the ZIndex of the Expander pannel, the map no longer receives input. I am assuming the issue has to do with the visual tree of WPF, and how input cascades down. Any ideas on what the issue could be? Thanks.
EDIT
The issue seems to be with the expander, as the map works if I remove the expander and just have the ItemsControl.
Try :
<Expander IsHitTestVisible="False">
<ItemsControl />
</Expander>
It doesn't seem to be a problem with extender, which would be very wired if it did
I tried this :
<Grid>
<Button />
<Expander HorizontalAlignment="Left" ExpandDirection="Right" VerticalAlignment="Top">
<Rectangle Fill="Red" Stretch="Fill" Width="525" Height="350"/>
</Expander>
</Grid>

Creating a sidebar - flyout like Windows desktop app in WPF

what i am trying to do is create a Desktop application in WPF whose UI is such that a small icon will remain fixed in the center of the left edge of screen and on click(or maybe hover) will slide open a sidebar(like the google desktop bar) running along the left edge of the screen (fixed position, cannot be moved).
do note that what i'm asking for might be like an appbar but i do not want the desktop icons along the left edge to be moved as it happens with an appbar i.e. i do not want it to hog up the desktop spacce....can anyone please suggest me a way out ??
I have implemented a partial solution using this, but i cant get the slide animation and fixed position to workout
Something like this could work:
then of course you could create a slide in animation for the sidebar. This shows (partial) transparency and the switching principle.
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStyle="None" Topmost="True" WindowState="Maximized"
AllowsTransparency="True" Background="Transparent">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Name="rect" Width="100" VerticalAlignment="Stretch" Fill="#99000000" Visibility="Collapsed" />
<Button Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" Width="32" Height="32" FontSize="16" VerticalAlignment="Center" HorizontalAlignment="Right" Background="White" Click="Button_Click">></Button>
</Grid>
</Window>
C#:
private void Button_Click(object sender, RoutedEventArgs e)
{
if (rect.Visibility == System.Windows.Visibility.Collapsed)
{
rect.Visibility = System.Windows.Visibility.Visible;
(sender as Button).Content = "<";
}
else
{
rect.Visibility = System.Windows.Visibility.Collapsed;
(sender as Button).Content = ">";
}
}
Based on this answer and more answers on this site I made a side bar, I liked the result so i made a repo.
https://github.com/beto-rodriguez/MaterialMenu
you can install it from nuget too.
here is an example
<materialMenu:SideMenu HorizontalAlignment="Left" x:Name="Menu"
MenuWidth="300"
Theme="Default"
State="Hidden">
<materialMenu:SideMenu.Menu>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<StackPanel Orientation="Vertical">
<Border Background="#337AB5">
<Grid Margin="10">
<TextBox Height="150" BorderThickness="0" Background="Transparent"
VerticalContentAlignment="Bottom" FontFamily="Calibri" FontSize="18"
Foreground="WhiteSmoke" FontWeight="Bold">Welcome</TextBox>
</Grid>
</Border>
<materialMenu:MenuButton Text="Administration"></materialMenu:MenuButton>
<materialMenu:MenuButton Text="Packing"></materialMenu:MenuButton>
<materialMenu:MenuButton Text="Logistics"></materialMenu:MenuButton>
</StackPanel>
</ScrollViewer>
</materialMenu:SideMenu.Menu>
</materialMenu:SideMenu>

Error trying to freeze a Rectangle filled with a BitmapCacheBrush

I'm trying to Freeze a BitmapCacheBrush, but when I call Freeze it errors stating it can't be frozen.
What I'm trying to do is fill a Rectangle with a BitmapCacheBrush and then at some point, Freeze it so I can then animate the Rectangle and reuse the source Grid for something else (whilst animating the Rectangle).
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50*"></RowDefinition>
<RowDefinition Height="50*"></RowDefinition>
</Grid.RowDefinitions>
<Grid x:Name="LISTING">
<Grid.CacheMode>
<BitmapCache RenderAtScale="1" SnapsToDevicePixels="True"/>
</Grid.CacheMode>
<Rectangle x:Name="Rectangle1" Fill="Red" />
<Label Content="Test" FontSize="20" Foreground="Black" />
<Button x:Name="Button1" Click="Button1_Click"/>
</Grid>
<Rectangle Grid.Row="1" x:Name="Rectangle2" >
<Rectangle.Fill>
<BitmapCacheBrush x:Name="BMCB" Target="{Binding ElementName=LISTING}"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
In my test I am trying to see if I can Freeze the BMCB BitmapCacheBrush when the button is clicked, then as a test I want to hide the button and still see the bottom rectangle intact.
I'm wanting to use BitmapCacheBrush for the performance aspect.
Is this even possible?
Thanks
Ben
I would say No: But my only source to prove that is the Freezable documentation in the msdn, which says:
A Freezable can't be frozen if any of the following are true:
It has animated or data bound properties.
It has properties set by a dynamic resource.
It contains Freezable sub-objects that can't be frozen.
So i guess you can't freeze it because of your Target="{Binding ElementName=LISTING}" binding.

How can you align a canvas background in WPF?

I have set a canvas' background to an image of a company logo. I would like for this image to be aligned to the bottom right corner of the canvas.
Is it possible to do this, or would it require for the image to be added into the canvas as a child? That would not work with this program as all children of the canvas are handled differently.
Thank You
Will this work? (It worked for me, anyway.)
<Canvas>
<Canvas.Background>
<ImageBrush ImageSource="someimage.jpg" AlignmentX="Right"
AlignmentY="Bottom" Stretch="None" />
</Canvas.Background>
</Canvas>
AFAIK The WPF Canvas needs child UI elements to be positioned using absolute co-ordinates.
To achieve the right-bottom-anchored effect, I think you'd need to handle the window resize event, recalculate and apply the Top,Left co-ordinates for the child Image element to always stick to the right buttom corner.
<Window x:Class="HelloWPF.Window1" xmlns...
Title="Window1" Height="300" Width="339">
<Canvas>
<Image Canvas.Left="195" Canvas.Top="175" Height="87" Name="image1" Stretch="Fill" Width="122" Source="dilbert2666700071126ni1.gif"/>
</Canvas>
</Window>
How about containing the canvas and image inside of a Grid control like so?
<Window ...>
<Grid>
<Canvas/>
<Image HorizontalAlignment="Right" VerticalAlignment="Bottom" .../>
<Grid>
</Window>
This is my solution using a border inside the canvas to align the image. This solution works well when canvas is resized:
<Canvas x:Name="MiCanvas" Height="250" Width="500" Background="Aqua">
<Border x:Name="MiBorderImage"
Width="{Binding ElementName=MiCanvas, Path=ActualWidth}"
Height="{Binding ElementName=MiCanvas, Path=ActualHeight}"
Background="Transparent">
<Image x:Name="MiImage" Source="/GraphicsLibrary/Logos/MiLogo.png"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Stretch="None" />
</Border>
</Canvas>

Resources