WPF Consuming FileInputBox


Consuming our file input box user control is not difficult. This post illustrates how you might consume the FileInputBox that Adam Nathan developed in the previous post.

How do you consume this user control? I made a new WPF project called FileInputConsumerBrowseBox in Visual Studio 2017. I added a new user control to the project just as if I was going to write a new user control from scratch. How? Right-click the name of the project in Solution Explorer, click Add, New Item…, User Control and name it FileInputBrowseBox.xaml. All I have to do now is copy and paste the code of the two files from the source project to this new project. The two files are FileInputBrowseBox.xaml and FileInputBrowseBox.xaml.cs.

Here is what the end result looks like. Just for illustration and educational purposes, I have made some additional styling and color choices (along with Adam Nathan) that you would not likely make in a real-world project, but this way we can see that it worked.

Below is the XAML code for the MainWindow.xaml file, which is our project that is consuming (hosting) the file input box with the Browse button. Pay particular attention to the <my:FileInputBrowseBox> element. It’s very simple. Just a bit of optional styling and a reference to a static resource in the App.xaml file. Also, you need to add the namespace. xmlns:my=”clr-namespace:FileInputBox” but substitute your namespace (use the name of the project) for FileInputBox in that line of code.

<Window x:Class="FileInputConsumerBrowseBox.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:my="clr-namespace:FileInputBox" 
        xmlns:local="clr-namespace:FileInputConsumerBrowseBox"
        mc:Ignorable="d"
        WindowStartupLocation="CenterScreen"
        Title="FileInputConsumerBrowseBox" Height="300" Width="600">
    <StackPanel>
        <TextBlock Margin="10">Consuming Adam Nathan's User Control on pages 719 - 728.</TextBlock>
        <my:FileInputBrowseBox Margin="10" Background="Blue" BorderBrush="Orange"
                               BorderThickness="3"
                               Style="{StaticResource myFIBBStyle}">
        </my:FileInputBrowseBox>
        <TextBlock TextWrapping="Wrap" Margin="10">I made a new WPF project. I added a new user control to the project just as if I was going to 
        write a new user control from scratch. How? Right-click the name of the project in Solution Explorer, click Add, 
        New Item..., User Control and name it <Span FontWeight="Bold">FileInputBrowseBox.xaml</Span>. All I have to do now is copy and paste
        the code of the two files from the source project to this new project. The two files
        are FileInputBrowseBox.xaml and FileInputBrowseBox.xaml.cs.</TextBlock>
        <TextBlock TextWrapping="Wrap" Margin="10">The source solution/project is called <Span FontWeight="Bold">FileInputBox.sln.</Span></TextBlock>
    </StackPanel>
</Window>

Below is the App.xaml file. Editing this file is optional. You don’t need to add these styles if you don’t wan to.

<Application x:Class="FileInputConsumerBrowseBox.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:FileInputConsumerBrowseBox"
             xmlns:my="clr-namespace:FileInputBox" 
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <Style x:Key="myFIBBStyle" TargetType="{x:Type my:FileInputBrowseBox}">
            <Setter Property="FontSize" Value="18" />
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="FileName" Value="hey dude"/>
        </Style>
    </Application.Resources>
</Application>

Below is the XAML code of the user control. This file is called FileInputBrowseBox.xaml. Do not forget about the code x:Name=”root”. It need to be there so that the file that the user picks shows up in the text box.

<UserControl x:Class="FileInputBox.FileInputBrowseBox"
             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:local="clr-namespace:FileInputBox"
             x:Name="root"
             mc:Ignorable="d" 
             d:DesignHeight="60" d:DesignWidth="600">
    <DockPanel>
        <Button x:Name="theButton" DockPanel.Dock="Right" Click="theButton_Click" 
                ToolTip="Click to Browse" Margin="2">
            <Button.Style>
                <Style TargetType="Button">
                    <Setter Property="Foreground" Value="Blue"></Setter>
                    <Style.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Foreground" Value="Red" />
                            <Setter Property="FontWeight" Value="Bold"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
            Browse...</Button>
        <TextBox x:Name="theTextBox" MinWidth="{Binding ActualWidth, ElementName=theButton}" 
                 Text="{Binding FileName, ElementName=root}" Margin="2,2,2,2"
                 ToolTip="Enter in the location and name of a file or click Browse to find it."/>
    </DockPanel>
</UserControl>

Below is the code behind the user control. This file is called FileInputBrowseBox.xaml.cs.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using Microsoft.Win32;

namespace FileInputBox
{
    [ContentProperty("FileName")]
    public partial class FileInputBrowseBox : UserControl
    {
        public FileInputBrowseBox()
        {
            InitializeComponent();
            theTextBox.TextChanged += new TextChangedEventHandler(OnTextChanged);
        }
        private void theButton_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog d = new OpenFileDialog();
            if (d.ShowDialog() == true) // Result could be true, false, or null
                FileName = d.FileName;
        }
        public string FileName
        {
            get { return (string)GetValue(FileNameProperty); }
            set { SetValue(FileNameProperty, value); }
        }
        private void OnTextChanged(object sender, TextChangedEventArgs e)
        {
            FileName = theTextBox.Text;
            e.Handled = true;
            RoutedEventArgs args = new RoutedEventArgs(FileNameChangedEvent);
            RaiseEvent(args);
        }
        public event RoutedEventHandler FileNameChanged
        {
            add { AddHandler(FileNameChangedEvent, value); }
            remove { RemoveHandler(FileNameChangedEvent, value); }
        }
        public static readonly DependencyProperty FileNameProperty =
           DependencyProperty.Register("FileName", typeof(string), typeof(FileInputBrowseBox));

        public static readonly RoutedEvent FileNameChangedEvent =
            EventManager.RegisterRoutedEvent("FileNameChanged",
            RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FileInputBrowseBox));

        // below is from top of page 724 of Adam Nathan book
        protected override void OnContentChanged(object oldContent, object newContent)
        {
            if (oldContent != null)
                throw new InvalidOperationException("You cannot change Content");
        }
    }
}