aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage')
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Converters/StorageItemToImageConverter.cs39
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Helpers/FileIconHelper.cs146
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/file.pngbin0 -> 1184 bytes
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/folder.pngbin0 -> 756 bytes
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj13
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs79
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml126
7 files changed, 401 insertions, 2 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Converters/StorageItemToImageConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Converters/StorageItemToImageConverter.cs
new file mode 100644
index 000000000..e9d2c8c18
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Converters/StorageItemToImageConverter.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+using Tango.Integration.Storage;
+using Tango.SharedUI.Helpers;
+
+namespace Tango.MachineStudio.Storage.Converters
+{
+ public class StorageItemToImageConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ StorageItem item = value as StorageItem;
+
+ if (item != null)
+ {
+ if (item is StorageFolder)
+ {
+ return ResourceHelper.GetImageFromResources("Images/folder.png");
+ }
+ else
+ {
+ return Helpers.FileIconHelper.FindIconForFilename(item.Name, true);
+ }
+ }
+
+ return null;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Helpers/FileIconHelper.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Helpers/FileIconHelper.cs
new file mode 100644
index 000000000..47dab8e5e
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Helpers/FileIconHelper.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Interop;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Tango.MachineStudio.Storage.Helpers
+{
+ public static class FileIconHelper
+ {
+ private static readonly Dictionary<string, ImageSource> _smallIconCache = new Dictionary<string, ImageSource>();
+ private static readonly Dictionary<string, ImageSource> _largeIconCache = new Dictionary<string, ImageSource>();
+ /// <summary>
+ /// Get an icon for a given filename
+ /// </summary>
+ /// <param name="fileName">any filename</param>
+ /// <param name="large">16x16 or 32x32 icon</param>
+ /// <returns>null if path is null, otherwise - an icon</returns>
+ public static ImageSource FindIconForFilename(string fileName, bool large)
+ {
+ var extension = Path.GetExtension(fileName);
+ if (extension == null)
+ return null;
+ var cache = large ? _largeIconCache : _smallIconCache;
+ ImageSource icon;
+ if (cache.TryGetValue(extension, out icon))
+ return icon;
+ icon = IconReader.GetFileIcon(fileName, large ? IconReader.IconSize.Large : IconReader.IconSize.Small, false).ToImageSource();
+ cache.Add(extension, icon);
+ return icon;
+ }
+ /// <summary>
+ /// http://stackoverflow.com/a/6580799/1943849
+ /// </summary>
+ static ImageSource ToImageSource(this Icon icon)
+ {
+ var imageSource = Imaging.CreateBitmapSourceFromHIcon(
+ icon.Handle,
+ Int32Rect.Empty,
+ BitmapSizeOptions.FromEmptyOptions());
+ return imageSource;
+ }
+ /// <summary>
+ /// Provides static methods to read system icons for both folders and files.
+ /// </summary>
+ /// <example>
+ /// <code>IconReader.GetFileIcon("c:\\general.xls");</code>
+ /// </example>
+ static class IconReader
+ {
+ /// <summary>
+ /// Options to specify the size of icons to return.
+ /// </summary>
+ public enum IconSize
+ {
+ /// <summary>
+ /// Specify large icon - 32 pixels by 32 pixels.
+ /// </summary>
+ Large = 0,
+ /// <summary>
+ /// Specify small icon - 16 pixels by 16 pixels.
+ /// </summary>
+ Small = 1
+ }
+ /// <summary>
+ /// Returns an icon for a given file - indicated by the name parameter.
+ /// </summary>
+ /// <param name="name">Pathname for file.</param>
+ /// <param name="size">Large or small</param>
+ /// <param name="linkOverlay">Whether to include the link icon</param>
+ /// <returns>System.Drawing.Icon</returns>
+ public static Icon GetFileIcon(string name, IconSize size, bool linkOverlay)
+ {
+ var shfi = new Shell32.Shfileinfo();
+ var flags = Shell32.ShgfiIcon | Shell32.ShgfiUsefileattributes;
+ if (linkOverlay) flags += Shell32.ShgfiLinkoverlay;
+ /* Check the size specified for return. */
+ if (IconSize.Small == size)
+ flags += Shell32.ShgfiSmallicon;
+ else
+ flags += Shell32.ShgfiLargeicon;
+ Shell32.SHGetFileInfo(name,
+ Shell32.FileAttributeNormal,
+ ref shfi,
+ (uint)Marshal.SizeOf(shfi),
+ flags);
+ // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
+ var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
+ User32.DestroyIcon(shfi.hIcon); // Cleanup
+ return icon;
+ }
+ }
+ /// <summary>
+ /// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
+ /// courtesy of MSDN Cold Rooster Consulting case study.
+ /// </summary>
+ static class Shell32
+ {
+ private const int MaxPath = 256;
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Shfileinfo
+ {
+ private const int Namesize = 80;
+ public readonly IntPtr hIcon;
+ private readonly int iIcon;
+ private readonly uint dwAttributes;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxPath)]
+ private readonly string szDisplayName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Namesize)]
+ private readonly string szTypeName;
+ };
+ public const uint ShgfiIcon = 0x000000100; // get icon
+ public const uint ShgfiLinkoverlay = 0x000008000; // put a link overlay on icon
+ public const uint ShgfiLargeicon = 0x000000000; // get large icon
+ public const uint ShgfiSmallicon = 0x000000001; // get small icon
+ public const uint ShgfiUsefileattributes = 0x000000010; // use passed dwFileAttribute
+ public const uint FileAttributeNormal = 0x00000080;
+ [DllImport("Shell32.dll")]
+ public static extern IntPtr SHGetFileInfo(
+ string pszPath,
+ uint dwFileAttributes,
+ ref Shfileinfo psfi,
+ uint cbFileInfo,
+ uint uFlags
+ );
+ }
+ /// <summary>
+ /// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
+ /// </summary>
+ static class User32
+ {
+ /// <summary>
+ /// Provides access to function required to delete handle. This method is used internally
+ /// and is not required to be called separately.
+ /// </summary>
+ /// <param name="hIcon">Pointer to icon handle.</param>
+ /// <returns>N/A</returns>
+ [DllImport("User32.dll")]
+ public static extern int DestroyIcon(IntPtr hIcon);
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/file.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/file.png
new file mode 100644
index 000000000..a8cf88667
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/file.png
Binary files differ
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/folder.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/folder.png
new file mode 100644
index 000000000..1d32e80bf
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/folder.png
Binary files differ
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj
index e2f41df43..0ce2a1cb4 100644
--- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj
@@ -43,6 +43,7 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
+ <Reference Include="System.Drawing" />
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\MahApps.Metro.1.5.0\lib\net45\System.Windows.Interactivity.dll</HintPath>
</Reference>
@@ -63,6 +64,8 @@
<Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs">
<Link>GlobalVersionInfo.cs</Link>
</Compile>
+ <Compile Include="Converters\StorageItemToImageConverter.cs" />
+ <Compile Include="Helpers\FileIconHelper.cs" />
<Compile Include="StorageModule.cs" />
<Compile Include="ViewModelLocator.cs" />
<Compile Include="ViewModels\MainViewVM.cs" />
@@ -103,6 +106,10 @@
<Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
<Name>Tango.Core</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Integration\Tango.Integration.csproj">
+ <Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project>
+ <Name>Tango.Integration</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
<Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
<Name>Tango.Logging</Name>
@@ -126,9 +133,13 @@
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
- <ItemGroup />
+ <ItemGroup>
+ <Resource Include="Images\file.png" />
+ <Resource Include="Images\folder.png" />
+ </ItemGroup>
<ItemGroup>
<Resource Include="Images\storage.png" />
</ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs
index d7eec4d36..f28783590 100644
--- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs
@@ -3,15 +3,94 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Tango.Core.Commands;
+using Tango.Integration.ExternalBridge;
+using Tango.Integration.Storage;
using Tango.MachineStudio.Common;
+using Tango.MachineStudio.Common.StudioApplication;
namespace Tango.MachineStudio.Storage.ViewModels
{
public class MainViewVM : StudioViewModel
{
+ private IStudioApplicationManager _applicationManager;
+ private bool _machine_operator_changed = true;
+
+ private StorageManager _storageManager;
+ public StorageManager StorageManager
+ {
+ get { return _storageManager; }
+ set { _storageManager = value; RaisePropertyChangedAuto(); }
+ }
+
+ private StorageItem _selectedStorageItem;
+ public StorageItem SelectedStorageItem
+ {
+ get { return _selectedStorageItem; }
+ set { _selectedStorageItem = value; RaisePropertyChangedAuto(); }
+ }
+
+ private String _currentPath;
+ public String CurrentPath
+ {
+ get { return _currentPath; }
+ set { _currentPath = value; RaisePropertyChangedAuto(); }
+ }
+
+ public RelayCommand BackCommand { get; set; }
+
+ public RelayCommand RefreshCommand { get; set; }
+
+ public RelayCommand GoCommand { get; set; }
+
+ public MainViewVM(IStudioApplicationManager applicationManager)
+ {
+ _applicationManager = applicationManager;
+ _applicationManager.ConnectedMachineChanged += _applicationManager_ConnectedMachineChanged;
+
+ GoCommand = new RelayCommand(NavigateToCurrentPath);
+ }
+
+ private void _applicationManager_ConnectedMachineChanged(object sender, IExternalBridgeClient e)
+ {
+ _machine_operator_changed = true;
+
+ if (IsVisible)
+ {
+ Initialize();
+ }
+ }
+
public override void OnApplicationReady()
{
}
+
+ public override void OnNavigatedTo()
+ {
+ base.OnNavigatedTo();
+
+ if (_machine_operator_changed)
+ {
+ _machine_operator_changed = false;
+ Initialize();
+ }
+ }
+
+ private async void NavigateToCurrentPath()
+ {
+ await StorageManager.GetFolder(CurrentPath);
+ }
+
+ private async void Initialize()
+ {
+ if (_applicationManager.ConnectedMachine != null)
+ {
+ StorageManager = _applicationManager.ConnectedMachine.CreateStorageManager();
+ await StorageManager.GetStorageDrive();
+ await StorageManager.GetRootFolder();
+ CurrentPath = StorageManager.StorageDrive.Root;
+ }
+ }
}
}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml
index 0350dc789..46ef31c6b 100644
--- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml
@@ -5,10 +5,134 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:Tango.MachineStudio.Storage.ViewModels"
xmlns:global="clr-namespace:Tango.MachineStudio.Storage"
+ xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls"
+ xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI"
+ xmlns:localConverters="clr-namespace:Tango.MachineStudio.Storage.Converters"
+ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:local="clr-namespace:Tango.MachineStudio.Storage.Views"
mc:Ignorable="d"
d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}">
+
+ <UserControl.Resources>
+ <localConverters:StorageItemToImageConverter x:Key="StorageItemToImageConverter" />
+ <converters:ByteArrayToFileSizeConverter x:Key="ByteArrayToFileSizeConverter" />
+ </UserControl.Resources>
+
<Grid>
-
+ <Grid>
+ <DockPanel>
+
+ <Border Background="#ECECEC" Margin="20" Width="350" CornerRadius="5">
+ <DockPanel>
+ <TextBlock HorizontalAlignment="Center" DockPanel.Dock="Top" Margin="20 55 20 20" FontSize="30" FontStyle="Italic" Foreground="{StaticResource AccentColorBrush}" FontWeight="Bold">ACTIONS</TextBlock>
+ <StackPanel Margin="0 40 0 0">
+
+ </StackPanel>
+ </DockPanel>
+ </Border>
+
+ <Grid>
+ <DockPanel>
+ <Border DockPanel.Dock="Top" Background="#ECECEC" Margin="20" Height="150" CornerRadius="5" Padding="20 0">
+ <DockPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" DockPanel.Dock="Left">
+ <Button Style="{StaticResource MaterialDesignFlatButton}" Width="80" Height="80" Padding="0" Command="{Binding BackCommand}">
+ <materialDesign:PackIcon Kind="ArrowLeft" Width="60" Height="60" />
+ </Button>
+
+ <Button Style="{StaticResource MaterialDesignFlatButton}" Width="80" Height="80" Padding="0" Command="{Binding RefreshCommand}">
+ <materialDesign:PackIcon Kind="Refresh" Width="60" Height="60" />
+ </Button>
+ </StackPanel>
+
+ <Border DockPanel.Dock="Right" Width="250" Margin="0 20" Background="{StaticResource AccentColorBrush}" TextElement.Foreground="White" CornerRadius="5" Padding="10">
+ <DockPanel>
+ <TextBlock DockPanel.Dock="Top" FontSize="18" FontWeight="Bold" FontStyle="Italic" HorizontalAlignment="Center">STORAGE</TextBlock>
+ <StackPanel>
+ <TextBlock Margin="0 5 0 0">
+ <Run>Root:</Run>
+ <Run FontWeight="Bold" FontStyle="Italic" Text="{Binding StorageManager.StorageDrive.Root}"></Run>
+ </TextBlock>
+ <TextBlock Margin="0 5 0 0">
+ <Run>Capacity:</Run>
+ <Run FontWeight="Bold" FontStyle="Italic" Text="{Binding StorageManager.StorageDrive.Capacity}"></Run>
+ </TextBlock>
+ <TextBlock Margin="0 5 0 0">
+ <Run>Free Space:</Run>
+ <Run FontWeight="Bold" FontStyle="Italic" Text="{Binding StorageManager.StorageDrive.FreeSpace}"></Run>
+ </TextBlock>
+ </StackPanel>
+ </DockPanel>
+ </Border>
+
+ <DockPanel VerticalAlignment="Center" Margin="50 0 50 0">
+ <Button Margin="10 0 0 0" DockPanel.Dock="Right" Style="{StaticResource MaterialDesignFlatButton}" Width="80" Height="80" Padding="0" Command="{Binding GoCommand}">
+ <materialDesign:PackIcon Kind="SubdirectoryArrowRight" Width="60" Height="60" />
+ </Button>
+ <Border Height="35" Background="{StaticResource AccentColorBrush}" CornerRadius="5" Padding="5">
+ <TextBox Style="{x:Null}" Background="Transparent" Foreground="White" FontSize="18" BorderThickness="0" CaretBrush="White" Text="{Binding CurrentPath,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
+ <TextBox.InputBindings>
+ <KeyBinding Command="{Binding Path=GoCommand}" Key="Enter"/>
+ </TextBox.InputBindings>
+ </TextBox>
+ </Border>
+ </DockPanel>
+ </DockPanel>
+ </Border>
+
+ <Grid Margin="20">
+ <Border Background="#1DFFFFFF" CornerRadius="5" Padding="20">
+ <DataGrid AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeRows="False" CanUserSortColumns="True" IsReadOnly="True" Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding StorageManager.CurrentFolder.Items}" SelectedItem="{Binding SelectedStorageItem}">
+ <DataGrid.CellStyle>
+ <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
+ <Setter Property="BorderThickness" Value="0"/>
+ <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
+ <Setter Property="VerticalContentAlignment" Value="Center"></Setter>
+ </Style>
+ </DataGrid.CellStyle>
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Width="100">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <Image Width="40" Height="40" HorizontalAlignment="Left" Source="{Binding Converter={StaticResource StorageItemToImageConverter}}"></Image>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="NAME" Width="1*" SortMemberPath="Name">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Name}" VerticalAlignment="Center" FontSize="16" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="TYPE" Width="150" SortMemberPath="Attribute">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Attribute}" VerticalAlignment="Center" FontSize="16" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="SIZE" Width="150" SortMemberPath="Length">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Length,Converter={StaticResource ByteArrayToFileSizeConverter},FallbackValue='',TargetNullValue=''}" VerticalAlignment="Center" FontSize="16" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="LAST MODIFIED" Width="200" SortMemberPath="LastModified">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding LastModified}" VerticalAlignment="Center" FontSize="16" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </DataGrid>
+ </Border>
+ </Grid>
+ </DockPanel>
+ </Grid>
+ </DockPanel>
+ </Grid>
</Grid>
</UserControl>