Create new stackpanel from an existing one

Viewed 78

I have this fileholder marked as 2. on the image. When I click on Upload PDF I want to create a new exactly the same looking fileholder from it's existing xaml after I have added a new file.

What im trying to ask is how can I access the xaml so that this would be possible?

enter image description here

The XAML:

<UserControl
x:Class="ModernDesign.MVVM.View.LibraryView"
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:local="clr-namespace:ModernDesign.MVVM.View"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="460"
d:DesignWidth="800"
mc:Ignorable="d">
<StackPanel>
    <TextBlock
        Margin="0,20,0,0"
        HorizontalAlignment="Center"
        FontFamily="/Fonts/#TiroGurmukhi"
        FontSize="28"
        Foreground="White"
        Text="Your PDF Library" />

    <StackPanel
        Margin="0,10,0,0"
        HorizontalAlignment="Center"
        Orientation="Horizontal">

        <Button
            x:Name="UploadButton"
            Width="70"
            Background="White"
            Click="UploadFileToLibrary"
            Content="Upload PDF"
            Cursor="Hand">
            <Button.Resources>
                <Style TargetType="Border">
                    <Setter Property="CornerRadius" Value="5" />
                </Style>
            </Button.Resources>
        </Button>
    </StackPanel>

    <StackPanel Orientation="Horizontal">
        <Border Width="192">
            <StackPanel x:Name="FileContentHolder">
                <Border
                    Width="110"
                    Height="105"
                    HorizontalAlignment="Center"
                    Background="#844eff"
                    CornerRadius="10">

                    <Button
                        x:Name="OpenPDF"
                        Width="45"
                        Margin="0,75,0,15"
                        HorizontalAlignment="Center"
                        Background="White"
                        Click="OpenFile">
                        <Button.Resources>
                            <Style TargetType="Border">
                                <Setter Property="CornerRadius" Value="5" />
                            </Style>
                        </Button.Resources>
                        <TextBlock
                            HorizontalAlignment="Center"
                            FontSize="9"
                            Foreground="#3b3939"
                            Text="Open" />
                    </Button>

                </Border>
                <TextBlock
                    x:Name="FileNameHolder"
                    Margin="0,5,0,0"
                    HorizontalAlignment="Center"
                    FontFamily="/Fonts/#TiroGurmukhi"
                    FontSize="12"
                    Foreground="White"
                    Text="FileName" />
            </StackPanel>
        </Border>
    </StackPanel>

</StackPanel>

The existing logic:

    public partial class LibraryView : UserControl
{
    string globalFilepath;

    public LibraryView()
    {
        InitializeComponent();
    }


    public void UploadFileToLibrary(object sender, RoutedEventArgs e)
    {
        Microsoft.Win32.OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Filter = "pdf files (*.pdf)|*.pdf|All files (*.*)|*.*";

        bool? response = openFileDialog.ShowDialog();

        if (response == true)
        {
            string filepath = openFileDialog.FileName;
            string filename = Path.GetFileNameWithoutExtension(filepath);
            //string fullpath = Path.GetFullPath(filepath);
            FileNameHolder.Text = filename;
            globalFilepath = filepath;
        }
    }


    public void OpenFile(object sender, RoutedEventArgs e)
    {
        var openSelectedFile = new Process();
        openSelectedFile.StartInfo = new ProcessStartInfo(globalFilepath)
        { UseShellExecute = true };

        openSelectedFile.Start();
    }
}
2 Answers

You should define the repeating layout elements as DataTemplate and then show it using a ListBox. The items of the ListBox are the filenames.
You can redefine the ListBox.ItemsPanel to configure it to display the items horizontally.

MainWindow.xaml

<Window>
  <ListBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=UploadedFiles}">
    <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
        <VirtualizingStackPanel Orientation="Horizontal" />
      </ItemsPanelTemplate>
    </ListBox.ItemsPanel>

    <ListBox.ItemTemplate>
      <DataTemplate>
        <Border Width="192"
                x:Name="Stack">
          <StackPanel x:Name="FileContentHolder">
            <Border Width="110"
                    Height="105"
                    HorizontalAlignment="Center"
                    Background="#844eff"
                    CornerRadius="10">

              <Button x:Name="OpenPDF"
                      Width="45"
                      Margin="0,75,0,15"
                      HorizontalAlignment="Center"
                      Background="White"
                      Click="OpenFile">
                <Button.Resources>
                  <Style TargetType="Border">
                    <Setter Property="CornerRadius"
                            Value="5" />
                  </Style>
                </Button.Resources>
                <TextBlock HorizontalAlignment="Center"
                           FontSize="9"
                           Foreground="#3b3939"
                           Text="Open" />
              </Button>
            </Border>
            <TextBlock x:Name="FileNameHolder"
                       Margin="0,5,0,0"
                       HorizontalAlignment="Center"
                       FontFamily="/Fonts/#TiroGurmukhi"
                       FontSize="12"
                       Foreground="White"
                       Text="{Binding}" />
          </StackPanel>
        </Border>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</Window>

MainWindow.xaml.cs

// The binding source for the ListView
public ObservableCollection<string> UploadedFiles
{
  get => (ObservableCollection<string>)GetValue(UploadedFilesProperty);
  set => SetValue(UploadedFilesProperty, value);
}

public static readonly DependencyProperty UploadedFilesProperty = DependencyProperty.Register(
  "UploadedFiles",
  typeof(ObservableCollection<string>),
  typeof(MainWindow),
  new PropertyMetadata(default));

public MainWindow()
{
  InitializeComponent();

  this.UploadedFiles = new ObservableCollection<string>();

  // TODO::If necessary initialize UploadedFiles collection with filenames
}

public void UploadFileToLibrary(object sender, RoutedEventArgs e)
{
  Microsoft.Win32.OpenFileDialog openFileDialog = new OpenFileDialog();
  openFileDialog.Filter = "pdf files (*.pdf)|*.pdf|All files (*.*)|*.*";

  bool? response = openFileDialog.ShowDialog();
  if (response == true)
  {
    string filepath = openFileDialog.FileName;
    string filename = Path.GetFileNameWithoutExtension(filepath);

    // Display a new "fileholder" box in the view
    this.UploadedFiles.Add(filename);

    ...
  }

  ...
}

See

You could clone the StackPanel using the System.Windows.Markup.XamlWriter class:

string xaml = XamlWriter.Save(FileContentHolder);
StackPanel newStackPanel = (StackPanel)XamlReader.Parse(xaml);
Button openPdf = newStackPanel.FindName("OpenPDF") as Button;
if (openPdf != null)
{
    openPdf.Click += OpenFile;
}
root.Children.Add(newStackPanel);

Note that you'll have to programmatically re-attach any event handlers:

Serialization Limitations of XamlWriter.Save

Related