# Rozszerzenia

Rozszerzenia są zaawansowanym narzędziem programistycznym w ekosystemie dodatku Dynamo. Umożliwiają programistom sterowanie funkcjami niestandardowymi opartymi na interakcjach i logice dodatku Dynamo. Rozszerzenia można podzielić na dwie główne kategorie, rozszerzenia i rozszerzenia widoku. Jak sugeruje nazwa, struktura rozszerzeń widoku umożliwia rozszerzenie interfejsu użytkownika dodatku Dynamo przez zarejestrowanie niestandardowych elementów menu. Zwykłe rozszerzenia działają w bardzo podobny sposób, ale bez interfejsu użytkownika. Przykładowo można utworzyć rozszerzenie rejestrujące określone informacje w konsoli dodatku Dynamo. Ten scenariusz nie wymaga niestandardowego interfejsu użytkownika i dlatego można go zrealizować również za pomocą rozszerzenia.

#### Analiza przypadku rozszerzenia <a href="#extension-case-study" id="extension-case-study"></a>

Korzystając z przykładu SampleViewExtension z repozytorium DynamoSamples z serwisu GitHub, przeanalizujemy czynności niezbędne do utworzenia prostego okna niemodalnego, w którym wyświetlane są aktywne węzły na wykresie w czasie rzeczywistym. Rozszerzenie widoku wymaga utworzenia interfejsu użytkownika dla tego okna i powiązania wartości z modelem widoku.

> 1. To okno rozszerzenia widoku opracowano na podstawie przykładu SampleViewExtension z repozytorium GitHub.

Mimo że utworzymy tu ten przykład od podstaw, można również pobrać i skompilować repozytorium DynamoSamples, a następnie używać go jako odniesienia.

Repozytorium DynamoSamples: <https://github.com/DynamoDS/DynamoSamples>

> W tym przewodniku będziemy odwoływać się konkretnie do projektu o nazwie SampleViewExtension znajdującego się w folderze `DynamoSamples/src/`.

#### Jak zaimplementować rozszerzenie widoku <a href="#how-to-implement-a-view-extension" id="how-to-implement-a-view-extension"></a>

Rozszerzenie widoku zawiera trzy zasadnicze części:

* Zespół zawierający klasę z zaimplementowanym interfejsem `IViewExtension` oraz klasę tworzącą model widoku
* Plik `.xml` informujący dodatek Dynamo, gdzie należy szukać tego zespołu w czasie wykonywania oraz jaki jest typ rozszerzenia
* Plik `.xaml`, który wiąże dane z wyświetlaniem grafiki i określa wygląd okna

**1. Tworzenie struktury projektu**

Rozpocznij od utworzenia nowego projektu `Class Library` o nazwie `SampleViewExtension`.

> 1. Utwórz nowy projekt, wybierając opcję `File > New > Project`
> 2. Wybierz opcję `Class Library`
> 3. Nadaj projektowi nazwę `SampleViewExtension`
> 4. Wybierz przycisk `Ok`

W tym projekcie będą potrzebne dwie klasy. W jednej klasie zostanie zaimplementowany interfejs `IViewExtension`, a w drugiej — klasa `NotificationObject.` Interfejs `IViewExtension` będzie zawierać wszystkie informacje o sposobie wdrażania, wczytywania, i usuwania rozszerzenia oraz odwoływania się do niego. Klasa `NotificationObject` będzie udostępniać powiadomienia o zmianach w dodatku Dynamo i interfejsie `IDisposable`. Po wprowadzeniu zmiany liczba zostanie odpowiednio zaktualizowana.

> 1. Plik klasy o nazwie `SampleViewExtension.cs`, w której zostanie zaimplementowany interfejs `IViewExtension`
> 2. Plik klasy o nazwie `SampleWindowViewMode.cs`, w której zostanie zaimplementowana klasa `NotificationObject`

Aby można było użyć interfejsu `IViewExtension`, potrzebny jest pakiet NuGet WpfUILibrary. Zainstalowanie tego pakietu spowoduje automatyczne zainstalowanie pakietów Core, Services i ZeroTouchLibrary.

> 1. Wybierz pakiet WpfUILibrary
> 2. Wybierz opcję `Install`, aby zainstalować wszystkie pakiety zależne

**2. Implementowanie klasy IViewExtension**

W klasie `IViewExtension` określimy, co się dzieje podczas uruchamiania dodatku Dynamo, gdy rozszerzenie jest wczytywane i gdy dodatek Dynamo zostaje zamknięty. W pliku klasy `SampleViewExtension.cs` dodaj następujący kod:

```
using System;
using System.Windows;
using System.Windows.Controls;
using Dynamo.Wpf.Extensions;

namespace SampleViewExtension
{

    public class SampleViewExtension : IViewExtension
    {
        private MenuItem sampleMenuItem;

        public void Dispose()
        {
        }

        public void Startup(ViewStartupParams p)
        {
        }

        public void Loaded(ViewLoadedParams p)
        {
            // Save a reference to your loaded parameters.
            // You'll need these later when you want to use
            // the supplied workspaces

            sampleMenuItem = new MenuItem {Header = "Show View Extension Sample Window"};
            sampleMenuItem.Click += (sender, args) =>
            {
                var viewModel = new SampleWindowViewModel(p);
                var window = new SampleWindow
                {
                    // Set the data context for the main grid in the window.
                    MainGrid = { DataContext = viewModel },

                    // Set the owner of the window to the Dynamo window.
                    Owner = p.DynamoWindow
                };

                window.Left = window.Owner.Left + 400;
                window.Top = window.Owner.Top + 200;

                // Show a modeless window.
                window.Show();
            };
            p.AddExtensionMenuItem(sampleMenuItem);
        }

        public void Shutdown()
        {
        }

        public string UniqueId
        {
            get
            {
                return Guid.NewGuid().ToString();
            }  
        } 

        public string Name
        {
            get
            {
                return "Sample View Extension";
            }
        } 

    }
}
```

Klasa `SampleViewExtension` tworzy element menu, który można kliknąć, służący do otwierania okna, i łączy go z oknem i modelem widoku.

* Instrukcja `public class SampleViewExtension : IViewExtension` `SampleViewExtension` powoduje dziedziczenie po interfejsie `IViewExtension` i udostępnia wszystkie funkcje potrzebne do utworzenia elementu menu.
* Instrukcja `sampleMenuItem = new MenuItem { Header = "Show View Extension Sample Window" };` tworzy element MenuItem i dodaje go do menu `View`.

> 1. Element menu

* Instrukcja `sampleMenuItem.Click += (sender, args)` wyzwala zdarzenie, które powoduje otwarcie nowego okna po kliknięciu elementu menu
* Instrukcja `MainGrid = { DataContext = viewModel }` ustawia kontekst danych dla siatki głównej w oknie, odwołując się do elementu `Main Grid` w pliku `.xaml`, który zostanie utworzony
* Instrukcja `Owner = p.DynamoWindow` ustawia dodatek Dynamo jako właściciela wyskakującego okna. Oznacza to, że nowe okno jest zależne od dodatku Dynamo, więc takie operacje jak zminimalizowanie, zmaksymalizowanie i przywrócenie dodatku Dynamo spowodują, że nowe okno będzie działało tak samo
* Metoda `window.Show();` wyświetla okno, w którym ustawiono dodatkowe właściwości okna

**3. Implementowanie modelu widoku**

Po ustaleniu niektórych podstawowych parametrów okna dodamy logikę reagowania na różne zdarzenia związane z dodatkiem Dynamo i poinstruujemy interfejs użytkownika, aby dokonał aktualizacji na podstawie tych zdarzeń. Skopiuj następujący kod do pliku klasy `SampleWindowViewModel.cs`:

```
using System;
using Dynamo.Core;
using Dynamo.Extensions;
using Dynamo.Graph.Nodes;

namespace SampleViewExtension
{
    public class SampleWindowViewModel : NotificationObject, IDisposable
    {
        private string activeNodeTypes;
        private ReadyParams readyParams;

        // Displays active nodes in the workspace
        public string ActiveNodeTypes
        {
            get
            {
                activeNodeTypes = getNodeTypes();
                return activeNodeTypes;
            }
        }

        // Helper function that builds string of active nodes
        public string getNodeTypes()
        {
            string output = "Active nodes:\n";

            foreach (NodeModel node in readyParams.CurrentWorkspaceModel.Nodes)
            {
                string nickName = node.Name;
                output += nickName + "\n";
            }

            return output;
        }

        public SampleWindowViewModel(ReadyParams p)
        {
            readyParams = p;
            p.CurrentWorkspaceModel.NodeAdded += CurrentWorkspaceModel_NodesChanged;
            p.CurrentWorkspaceModel.NodeRemoved += CurrentWorkspaceModel_NodesChanged;
        }

        private void CurrentWorkspaceModel_NodesChanged(NodeModel obj)
        {
            RaisePropertyChanged("ActiveNodeTypes");
        }

        public void Dispose()
        {
            readyParams.CurrentWorkspaceModel.NodeAdded -= CurrentWorkspaceModel_NodesChanged;
            readyParams.CurrentWorkspaceModel.NodeRemoved -= CurrentWorkspaceModel_NodesChanged;
        }
    }
}
```

Ta implementacja klasy modelu widoku nasłuchuje elementu `CurrentWorkspaceModel` i wyzwala zdarzenie w przypadku dodania lub usunięcia węzła z obszaru roboczego. Powoduje to zgłoszenie zmiany właściwości i powiadomienie interfejsu użytkownika lub powiązanych elementów o zmianie danych i konieczności ich zaktualizowania. Wywoływany jest mechanizm pobierania `ActiveNodeTypes`, który wewnętrznie wywołuje dodatkową funkcję pomocniczą `getNodeTypes()`. Ta funkcja iteruje przez wszystkie aktywne węzły w obszarze rysunku, wypełnia ciąg zawierający nazwy tych węzłów i zwraca ten ciąg do powiązania w pliku .xaml do wyświetlenia w wyskakującym oknie.

Po zdefiniowaniu logiki podstawowej rozszerzenia określimy teraz szczegóły wyglądu okna za pomocą pliku `.xaml`. Wystarczy proste okno, w którym ten ciąg będzie wyświetlany za pomocą powiązania właściwości `ActiveNodeTypes` w kontrolce `TextBlock` `Text`.

> 1. Kliknij prawym przyciskiem myszy projekt i wybierz pozycję `Add > New Item...`
> 2. Wybierz szablon kontroli użytkownika, który zmienimy w celu utworzenia okna
> 3. Nadaj nowemu plikowi nazwę `SampleWindow.xaml`
> 4. Wybierz opcję `Add`

W kodzie `.xaml` okna należy powiązać element `SelectedNodesText` z blokiem tekstowym. Dodaj następujący kod do pliku `SampleWindow.xaml`:

```
<Window x:Class="SampleViewExtension.SampleWindow"
             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:SampleViewExtension"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
            Width="500" Height="100">
    <Grid Name="MainGrid" 
          HorizontalAlignment="Stretch"
          VerticalAlignment="Stretch">
        <TextBlock HorizontalAlignment="Stretch" Text="{Binding ActiveNodeTypes}" FontFamily="Arial" Padding="10" FontWeight="Medium" FontSize="18" Background="#2d2d2d" Foreground="White"/>
    </Grid>
</Window>
```

* Instrukcja `Text="{Binding ActiveNodeTypes}"` wiąże wartość właściwości `ActiveNodeTypes` w pliku `SampleWindowViewModel.cs` z wartością `Text` elementu `TextBlock` w oknie.

Teraz zainicjujemy okno przykładowe w pliku zaplecza pliku C# .xaml: `SampleWindow.xaml.cs`. Dodaj następujący kod do pliku `SampleWindow.xaml`:

```
using System.Windows;

namespace SampleViewExtension
{
    /// <summary>
    /// Interaction logic for SampleWindow.xaml
    /// </summary>
    public partial class SampleWindow : Window
    {
        public SampleWindow()
        {
            InitializeComponent();
        }
    }
}
```

Rozszerzenie widoku jest teraz gotowe do skompilowania i dodania do dodatku Dynamo. Dodatek Dynamo wymaga pliku `xml`, aby zarejestrować wynikowy plik `.dll` jako rozszerzenie.

> 1. Kliknij prawym przyciskiem myszy projekt i wybierz pozycję `Add > New Item...`
> 2. Wybierz plik XML
> 3. Nadaj plikowi nazwę `SampleViewExtension_ViewExtensionDefinition.xml`
> 4. Wybierz opcję `Add`

* Ta nazwa pliku jest zgodna ze standardem dodatku Dynamo dotyczącego odwoływania się do zespołu rozszerzenia: `"extensionName"_ViewExtensionDefinition.xml`

W pliku `xml` dodaj następujący kod, aby wskazać dodatkowi Dynamo, gdzie ma szukać zespołu rozszerzenia:

```
<ViewExtensionDefinition>
  <AssemblyPath>C:\Users\username\Documents\Visual Studio 2015\Projects\SampleViewExtension\SampleViewExtension\bin\Debug\SampleViewExtension.dll</AssemblyPath>
  <TypeName>SampleViewExtension.SampleViewExtension</TypeName>
</ViewExtensionDefinition>
```

* W tym przykładzie skompilowaliśmy zespół w domyślnym folderze projektu programu Visual Studio. Zastąp położenie docelowe `<AssemblyPath>...</AssemblyPath>` położeniem zespołu.

Ostatnią czynnością jest skopiowanie pliku `SampleViewExtension_ViewExtensionDefinition.xml` do folderu rozszerzeń widoku dodatku Dynamo znajdującego się w katalogu instalacyjnym Dynamo Core `C:\Program Files\Dynamo\Dynamo Core\1.3\viewExtensions`. Należy pamiętać, że istnieją oddzielne foldery dla rozszerzeń `extensions` i `viewExtensions`. Umieszczenie pliku `xml` w niewłaściwym folderze może spowodować błąd podczas wczytywania pliku w trakcie wykonywania.

> 1. Plik `.xml` skopiowany do folderu rozszerzeń widoku dodatku Dynamo

Jest to podstawowe wprowadzenie do rozszerzeń widoku. Bardziej zaawansowaną analizę przypadku zawiera pakiet DynaShape, projekt open source w serwisie GitHub. Ten pakiet zawiera rozszerzenie widoku umożliwiające edycję na żywo w widoku modelu dodatku Dynamo.

Instalator pakietu DynaShape można pobrać z forum dodatku Dynamo: <https://forum.dynamobim.com/t/dynashape-published/11666>

Kod źródłowy można sklonować z serwisu GitHub: <https://github.com/LongNguyenP/DynaShape>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://primer2.dynamobim.org/pl/1_developer_primer_intro/3_developing_for_dynamo/7-extensions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
