This project shows that how to load custom XML file in your code, and find specified control using name that you want in runtime. And do show some image, play some video file, and auto play some Youtube video link. There are so many articles about these issues on the internet. But those sources are scattered and have some issues.
Using the Code
At first, make a WPF project.
Next, load XML file and load in window class.
XmlTextReader xmlTextReader = new XmlTextReader(@".\LayoutResources\Main.xaml");
object instance = XamlReader.Load(xmlTextReader);
this.Loaded += MainController_Loaded;
this.Content = instance;
On upper codes, I make a 'Main.xaml' file. it, 'Main.xaml', file's build action property must be 'none
' and copy to output directory property must be 'copy always
' or 'copy it newer
'.
I wrote an XAML like this:
<Grid
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.Background>
<ImageBrush ImageSource="..\LayoutResources\Images\defaultBackground.png"></ImageBrush>
</Grid.Background>
<DockPanel LastChildFill="True">
<Grid DockPanel.Dock="Top" Height="150">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Name="btnExit" Background="Transparent" BorderThickness="0"></Button>
</Grid>
</Grid>
<Grid DockPanel.Dock="Bottom" Height="100">
<TextBlock Name="tblNotice" HorizontalAlignment="Center"
VerticalAlignment="Center"></TextBlock>
</Grid>
<DockPanel LastChildFill="True" Margin="20">
<Image Name="imgMain" Width="200" DockPanel.Dock="Left"></Image>
<MediaElement Name="mpeMain" Width="200" DockPanel.Dock="Left"></MediaElement>
<ContentControl Name="webMain"></ContentControl>
</DockPanel>
</DockPanel>
</Grid>
As upper, I used Image
, MediaElement
, and ContentControl
controls. ContentControl
is used for Chrome WebBrowser which plays a Youtube video. You already know why I should have used Chrome instead of default web browser provided in WPF. It has some issues on about JavaScript and compatibilities. If you insist on using it, you will face a lot of stress.
So to use Chrome, please install like the below code in nuget package console.
install-package cefsharp.common <enter>
install-package cefsharp.wpf <enter>
And then, add codes like below in MainController
constructor function. It is related to the latest Google policy.
If you want to play Youtube, you should do this:
CefSharp.Wpf.CefSettings settings = new CefSharp.Wpf.CefSettings();
if (settings.CefCommandLineArgs.ContainsKey("autoplay-policy"))
settings.CefCommandLineArgs["autoplay-policy"] = "no-user-gesture-required";
else
settings.CefCommandLineArgs.Add("autoplay-policy", "no-user-gesture-required");
CefSharp.Cef.Initialize(settings);
After that, fill codes in 'MainController_Loaded
' function.
Button btn = FindControl<Button>(this, "btnExit");
if (btn != null)
{
btn.Content = "Click Me";
btn.Click += btn_Click;
}
TextBlock tblNotice = FindControl<TextBlock>(this, "tblNotice");
if (tblNotice != null)
{
tblNotice.Text = "Hi";
tblNotice.FontSize = 20;
}
Image imgMain = FindControl<Image>(this, "imgMain");
if(imgMain != null)
{
String strPath = String.Format(
"{0}LayoutResources\\Images\\defaultImage.jpg",
AppDomain.CurrentDomain.BaseDirectory);
imgMain.Source = new BitmapImage(new Uri(strPath, UriKind.Absolute));
}
MediaElement mpeMain = FindControl<MediaElement>(this, "mpeMain");
if(mpeMain != null)
{
mpeMain.LoadedBehavior = MediaState.Manual;
mpeMain.MediaEnded += mpeMain_MediaEnded;
String strPath = String.Format(
"{0}LayoutResources\\Images\\defaultMedia.mp4",
AppDomain.CurrentDomain.BaseDirectory);
mpeMain.Source = new Uri(strPath, UriKind.Absolute);
mpeMain.SpeedRatio = 1;
mpeMain.Play();
}
ContentControl webMain = FindControl<ContentControl>(this, "webMain");
if (webMain != null)
{
String strUrl = "https://www.youtube.com/embed/LGxT88Ljdc4" + "?autoplay=1";
webMain.Content = new ChromiumWebBrowser(strUrl);
}
As you will understand the codes, the point is FindControl
function. This is a function finding a control that you want.
Let's tell about the finding control. This code can be used when you want to find a control that you want with name in WPF. There are so many useful articles about this issue on the internet. I also found useful sources there. Without them, I couldn't do anything. I referred to this article 'How can I find WPF controls by name or type?' But it is has one flawless point. An original code is simple. See below:
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
T childType = child as T;
if (childType == null)
{
foundChild = FindChild<T>(child, childName);
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null && frameworkElement.Name == childName)
{
foundChild = (T)child;
break;
}
}
else
{
foundChild = (T)child;
break;
}
}
return foundChild;
}
You can see this code in the article 'How can I find WPF controls by name or type?'. Please see the point that I mentioned, '/** this part **/'
You should see more code in there. If you find the same type of control, but it is not what you want, this code will skip to find its children. Even if it also has children, that is the point.
So, I added some code in there, see the below codes.
An added code in /************************* this part *************************/
foundChild = FindChild<T>(child, childName);
if (foundChild != null) break;
With the upper code, you can find the control wherever it is. See the full code I changed like below:
public T FindControl<T>(DependencyObject objParent, String strName) where T : DependencyObject
{
if (objParent == null || String.IsNullOrEmpty(strName)) return null;
T existedChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(objParent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(objParent, i);
if ((child as T) == null)
{
existedChild = FindControl<T>(child, strName);
if (existedChild != null) break;
}
else
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null)
{
if (!String.IsNullOrEmpty(frameworkElement.Name) &&
frameworkElement.Name == strName)
{
existedChild = (T)child;
break;
}
else
{
existedChild = FindControl<T>(child, strName);
if (existedChild != null) break;
}
}
}
}
return existedChild;
}
You will download that project I uploaded. Enjoy it!
Points of Interest
Load XAML, find control, and play Youtube video automatically
History
- 15th July, 2020: First issued