Intersoft ClientUI Documentation
How-to: Bind Uploaded Files using MVVM Pattern

The following example shows how to bind the upload results from UXFileUpload to a property in the ViewModel using MVVM design pattern.

Example

Description

You can learn the basics of UXFileUpload control in UXFileUpload Overview, such as configuring the pre-upload settings and customizing the uploading behaviors. Once the files are uploaded to server, you may want to display the results to the users, such as displaying the list of uploaded files to a ListBox, or showing the uploaded photo in an Image control.

UXFileUpload makes it easy for developers to obtain the uploaded files by leveraging the data binding and MVVM design pattern. It is a common approach to bind the results to a property in the ViewModel in an MVVM application. This allows you to streamline the user interaction logic in the ViewModel along with other properties, such as document details in a document submission application.

Built with architecture that is optimized for MVVM design pattern, UXFileUpload allows you to use your own entity as the model, such as a Document class, or a File class. Since the upload results might be different with the data stored in the persistence database, it is best practice to separate the raw files input and the final collection that attached to the model by providing the interaction logic in the ViewModel.

The following examples show how to implement the model to represent a File entity, and then create a ViewModel that contains user interaction logic to hold the raw input files and add the results to the actual entity in the collection changed event. Finally, the example includes the XAML that shows how to bind the UXFileUpload control to the properties in the ViewModel.

To learn the basics of MVVM pattern, please see MVVM Pattern Overview.

Code

The following example shows the code listing for the File model. The File class generally contains simple properties that describe a file object, such as Name, Size, Source and Description. You can place this file in the Models folder in your Silverlight application.

File.cs (Model)
Copy Code
    public class File : ModelBase
    {
        private string _name;
        private long _size;
        private Uri _source;
        private string _description;

        public File()
        {
        }

        public File(object rawFile)
        {
            if (rawFile is FileUploadInfo)
            {
                FileUploadInfo file = rawFile as FileUploadInfo;
                _name = file.TargetFileName;
                _size = file.Size;
                _source = file.ResultUrl;
            }
            else
            {
                throw new NotSupportedException("The 'rawFile' type is not supported.");
            }
        }

        public string Description
        {
            get { return _description; }
            set
            {
                if (_description != value)
                {
                    _description = value;
                    OnPropertyChanged("Description");
                }
            }
        }

        public Uri Source
        {
            get { return _source; }
            set
            {
                if (_source != value)
                {
                    _source = value;
                    OnPropertyChanged("Source");
                }
            }
        }

        public long Size
        {
            get { return _size; }
            set
            {
                if (_size != value)
                {
                    _size = value;
                    OnPropertyChanged("Size");
                }
            }
        }

        public string Name
        {
            get { return _name; }
            set
            {
                if (_name != value)
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
        }

        public string Extension
        {
            get
            {
                if (!string.IsNullOrEmpty(this.Name))
                {
                    if (this.Name.IndexOf(".") > -1)
                        return "." + this.Name.Split('.').GetValue(1).ToString();
                }

                return string.Empty;
            }
        }
    }

Next, you create a FileViewModel that describes the File model, shown in the following code listing. The FileViewModel introduces a Title property that will be used in the View (UI).

File.cs (Model)
Copy Code
    public class FileViewModel : ViewModelBase
    {
        private File _fileInfo;

        public FileViewModel(File fileInfo)
        {
            _fileInfo = fileInfo;
        }

        public File FileInfo
        {
            get { return _fileInfo; }
            set
            {
                if (_fileInfo != value)
                {
                    _fileInfo = value;
                    OnPropertyChanged("FileUploadInfo");
                }
            }
        }

        public string Title
        {
            get
            {
                return this.FileInfo.Name + " (" + this.FileInfo.Size.ToString("#,##") + " bytes)";
            }
        }
    }

The following example shows the code listing for both the View and the ViewModel that describes the View respectively. Notice that the UXFileUpload control is bound to the RawInputFiles, while the UXListBox is bound to the UploadedFiles property.

DocumentManager.xaml
Copy Code
<Intersoft:UXPage 
        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"
        mc:Ignorable="d"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"
          xmlns:ViewModels="clr-namespace:Samples.UXInput.ViewModels"
        x:Class="Samples.UXInput.Views.UXFileUpload.DocumentManager" 
        Title="Default Page"
        d:DesignWidth="1024" d:DesignHeight="800">
        <Intersoft:UXPage.Resources>

                <DataTemplate x:Key="FileUploadItemTemplate">
                        <StackPanel Orientation="Horizontal">
                                <TextBlock VerticalAlignment="Center" Text="{Binding Title}" Margin="8"/>
                        </StackPanel>
                </DataTemplate>

        <ViewModels:DocumentManagerViewModel x:Key="DocumentManagerViewModel"/>
        
        </Intersoft:UXPage.Resources>
        
        <Grid x:Name="LayoutRoot">
            <Grid DataContext="{StaticResource DocumentManagerViewModel}">
                <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
                    <Intersoft:DockPanel Width="580" Height="350" FillChildMode="Custom">

                        <Intersoft:UXFileUpload Intersoft:DockPanel.IsFillElement="True"
                                                UploadedFiles="{Binding RawInputFiles, Mode=TwoWay}"
                                                MaxFilesCount="5" AllowDrop="True"
                                                MaxFileSize="512000"
                                                MaxUploadSize="1024000"
                                                ServiceUrl="http://localhost:7373/UXFileUploadHandler.ashx"
                                                TargetFolder="~/ClientBin/Assets/Documents"
                                                TargetWebUrl="http://{host}/ClientBin/Assets/Documents">
                            
                        </Intersoft:UXFileUpload>

                        <Intersoft:UXListBox Width="400" Height="250" 
                                             ItemTemplate="{StaticResource FileUploadItemTemplate}" 
                                             ItemsSource="{Binding UploadedFiles}" />

                    </Intersoft:DockPanel>
                </Grid>
            </Grid>
        </Framework:SamplePage>
        </Grid>
</Intersoft:UXPage>
DocumentManagerViewModel.cs
Copy Code
    public class DocumentManagerViewModel : ViewModelBase
    {
        private ObservableCollection<FileViewModel> _uploadedFiles;
        private INotifyCollectionChanged _rawInputFiles;

        public CloudBoxViewModel()
        {
            this.UploadedFiles = new ObservableCollection<FileViewModel>();
        }

        public ObservableCollection<FileViewModel> UploadedFiles
        {
            get { return _uploadedFiles; }
            private set
            {
                if (_uploadedFiles != value)
                {
                    _uploadedFiles = value;
                    OnPropertyChanged("UploadedFiles");
                }
            }
        }

        public INotifyCollectionChanged RawInputFiles
        {
            get { return _rawInputFiles; }
            set
            {
                if (_rawInputFiles != value)
                {
                    if (_rawInputFiles != null)
                        _rawInputFiles.CollectionChanged -= RawInputFiles_CollectionChanged;
                    
                    _rawInputFiles = value;
                    _rawInputFiles.CollectionChanged += new NotifyCollectionChangedEventHandler(RawInputFiles_CollectionChanged);
                    
                    OnPropertyChanged("RawInputFiles");
                }
            }
        }

        private void RawInputFiles_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                this.UploadedFiles.Add(new FileViewModel(new File(e.NewItems[0])));
            }
            else if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                this.UploadedFiles.Clear();
            }
        }
    }

Notice that the DocumentManagerViewModel uses only the plain CLR types and does not require a strong reference to any types in the UXFileUpload control. This conforms to the best practice in implementing MVVM design pattern in which the ViewModel should not refer to the UI elements (View) or any types associated to it. For more information on implementing MVVM design pattern, please see MVVM Pattern Overview.

See Also

Concepts