action-result.md
This commit is contained in:
@@ -0,0 +1,593 @@
|
||||
# Action result zwracany przez akcje (worker, extender, Command)
|
||||
|
||||
Akcje (metody worker, akcje extender, handlery Command, callbacki) zwracają **action result** — obiekt
|
||||
sterujący tym, co stanie się w UI po wykonaniu logiki biznesowej. Typ zwróconego obiektu decyduje
|
||||
o sposobie obsługi.
|
||||
|
||||
## Najważniejsza zasada
|
||||
|
||||
**Nie wywołuj sam UI z poziomu worker/extender.** Zamiast pokazywać MessageBox, otwierać formularz
|
||||
czy generować plik — **zwróć odpowiedni action result**. Framework zrobi resztę, panując nad sesją,
|
||||
transakcją i wątkiem UI.
|
||||
|
||||
```csharp
|
||||
// ŹLE - kod biznesowy nie powinien znać UI
|
||||
[Action("Sprawdź")]
|
||||
public void Sprawdz() {
|
||||
MessageBoxWindow.Show("Niepoprawne dane".Translate()); // <- nie tak
|
||||
}
|
||||
|
||||
// DOBRZE - zwracamy action result
|
||||
[Action("Sprawdź")]
|
||||
public object Sprawdz() {
|
||||
return new MessageBoxInformation("Walidacja".Translate(), "Niepoprawne dane".Translate());
|
||||
}
|
||||
```
|
||||
|
||||
## Wartości specjalne
|
||||
|
||||
| Zwrócona wartość | Działanie |
|
||||
|---|---|
|
||||
| `null` | Brak akcji. Transakcja jest commitowana. |
|
||||
| `void` (metoda bez return) | Brak akcji. |
|
||||
| `Task` / `Task<T>` | Framework czeka na zakończenie i obsługuje zwróconą wartość. |
|
||||
| `Exception` | Pokazuje okno błędu (`MessageBoxWindow.ShowException`). Transakcja jest commitowana (rollback w wyjątku robi się wcześniej). |
|
||||
|
||||
## Sterowanie aktualnym formularzem
|
||||
|
||||
### `FormAction` (enum)
|
||||
|
||||
Najprostsza forma — sama wartość enum jako action result. Handler konwertuje to
|
||||
do `FormActionResult` z ustawioną akcją.
|
||||
|
||||
| Wartość | Działanie |
|
||||
|---|---|
|
||||
| `None` | Brak akcji. |
|
||||
| `Save` | Zapis bez zamykania, bez potwierdzeń warningów. |
|
||||
| `SaveWithConfirmation` | Zapis bez zamykania, z potwierdzeniem warningów. |
|
||||
| `SaveAndClose` | Zapis i zamknięcie, bez potwierdzeń. |
|
||||
| `SaveAndCloseWithConfirmation` | Zapis i zamknięcie, z potwierdzeniem warningów. |
|
||||
| `Refresh` | Odczyt danych formularza z bazy. |
|
||||
| `RefreshOwner` | Odświeżenie formularza-rodzica. |
|
||||
| `Close` | Zamknięcie bez zapisu, bez ostrzeżeń. |
|
||||
|
||||
```csharp
|
||||
[Action("Zatwierdź")]
|
||||
public FormAction Zatwierdz() {
|
||||
Status = Status.Zatwierdzony;
|
||||
return FormAction.SaveAndClose;
|
||||
}
|
||||
```
|
||||
|
||||
### `FormActionResult`
|
||||
|
||||
Rozszerzona wersja `FormAction` — pozwala dodać `EditValue` (kontynuacja po zapisie), `Context`,
|
||||
`CommittedHandler` (kod wywoływany po commit transakcji).
|
||||
|
||||
```csharp
|
||||
return new FormActionResult {
|
||||
Action = FormAction.SaveAndClose,
|
||||
EditValue = nowyDokument, // otwarcie kolejnego obiektu po zapisie
|
||||
CommittedHandler = context => null,
|
||||
};
|
||||
```
|
||||
|
||||
## Okna informacyjne i pytania do użytkownika
|
||||
|
||||
### `string`
|
||||
|
||||
Krótki komunikat — handler konwertuje do `MessageBoxInformation` z domyślnym tytułem "Informacja".
|
||||
|
||||
```csharp
|
||||
return "Operacja zakończona pomyślnie".Translate();
|
||||
```
|
||||
|
||||
### `MessageBoxInformation`
|
||||
|
||||
Pełna kontrola nad okienkiem dialogowym. Przyciski (OK / Anuluj / Tak / Nie) pojawiają się
|
||||
automatycznie na podstawie ustawionych handlerów (`OKHandler`, `CancelHandler`, `YesHandler`,
|
||||
`NoHandler`). Handler każdego przycisku jest typu `Func<object>` — **może zwrócić kolejny action result**,
|
||||
który zostanie obsłużony rekurencyjnie (mechanizm `DelayedHandler`).
|
||||
|
||||
| Property | Znaczenie |
|
||||
|---|---|
|
||||
| `Caption` | Tytuł okna (NULL = standardowy zależny od `Type`). |
|
||||
| `Text` / `TextMarkdown` | Treść (czysty tekst lub markdown). |
|
||||
| `Type` | `Information` / `Warning` / `Error` — kolorystyka. |
|
||||
| `OKHandler` / `CancelHandler` / `YesHandler` / `NoHandler` | Akcje po wybraniu przycisku. |
|
||||
| `IsSecondDefault` | `Enter` wywołuje drugą akcję (No/Cancel zamiast Yes/OK). |
|
||||
|
||||
```csharp
|
||||
return new MessageBoxInformation("Potwierdzenie".Translate(), "Czy na pewno usunąć?".Translate()) {
|
||||
Type = MessageBoxInformationType.Warning,
|
||||
YesHandler = () => {
|
||||
Usun();
|
||||
return FormAction.RefreshOwner;
|
||||
},
|
||||
NoHandler = () => null,
|
||||
};
|
||||
```
|
||||
|
||||
## Otwieranie obiektów i okien
|
||||
|
||||
### Zwrócenie `Row` lub dowolnego `object`
|
||||
|
||||
Domyślny handler otwiera obiekt w nowym formularzu
|
||||
(`ObjectWindow` w HTML). Działa to dla każdego typu nieobsługiwanego przez specyficzne handlery — w tym
|
||||
`GuidedRow`, kreatorów, dialogów.
|
||||
|
||||
```csharp
|
||||
[Action("Otwórz kontrahenta")]
|
||||
public Kontrahent OtworzKontrahenta() => Wystawca;
|
||||
```
|
||||
|
||||
## Nawigacja po programie
|
||||
|
||||
### `NavigationResult`
|
||||
|
||||
Przejście do innego folderu danych lub bazy. Działa jak kliknięcie w drzewie folderów.
|
||||
|
||||
| Property | Znaczenie |
|
||||
|---|---|
|
||||
| `Address` | Ścieżka folderu (np. `"Handel/Sprzedaż/Faktury sprzedaży"`) lub `/<DB>/<ścieżka>` dla innej bazy. |
|
||||
| `Context` | Kontekst (filtry) folderu. |
|
||||
| `Target` | `Self` / `NewWindow` / `NewTab`. |
|
||||
| `KeepCurrentCredentials` | Logowanie do innej bazy aktualnymi danymi (JWT). |
|
||||
| `KeepSessionLiving` | Przeniesienie żywej sesji do folderu docelowego (`Self` only). |
|
||||
| `KeepCurrentViewInHistory` | Aktualny widok zostaje w historii nawigacji. |
|
||||
|
||||
Najważniejsze ścieżki do folderów aplikacji znajdują się w skill `/soneta-mcp-ui/common-folders.md`.
|
||||
|
||||
```csharp
|
||||
return new NavigationResult("Handel/Sprzedaż/Faktury sprzedaży") {
|
||||
Target = NavigationTarget.NewTab
|
||||
};
|
||||
```
|
||||
|
||||
### `HyperlinkResult`
|
||||
|
||||
Otwarcie URL w przeglądarce.
|
||||
|
||||
```csharp
|
||||
return new HyperlinkResult {
|
||||
Address = "https://soneta.pl",
|
||||
Target = NavigationTarget.NewWindow,
|
||||
};
|
||||
```
|
||||
|
||||
### `CommandMenu`
|
||||
|
||||
Menu poleceń wyświetlone użytkownikowi (drop-down z opcjami). Po wybraniu wykonuje się akcja
|
||||
przypisana do polecenia.
|
||||
|
||||
### `LoginParameters`
|
||||
|
||||
Wymusza przelogowanie (np. po zmianie operatora). Framework wywołuje `LoginService.Relogin`.
|
||||
|
||||
## Pliki i strumienie
|
||||
|
||||
### `NamedStream`
|
||||
|
||||
Pojedynczy plik do pobrania przez przeglądarkę lub ramkę SonetaFrame.
|
||||
|
||||
```csharp
|
||||
return new NamedStream("raport.pdf", () => GenerujPdfStream());
|
||||
```
|
||||
|
||||
### `NamedStream[]`
|
||||
|
||||
Tablica plików → spakowane jako ZIP (`Pliki_yyyyMMddHHmmssfff.zip`) i pobrane jako jeden plik lub zapisywane pojedynczo
|
||||
przez ramkę SonetaFrame.
|
||||
|
||||
### `StorageFileEditor`
|
||||
|
||||
Edycja pliku przechowywanego w storage bazy danych (XML, DOCX, REPX, itp.)
|
||||
|
||||
## Raporty
|
||||
|
||||
### `ReportResult`
|
||||
|
||||
Główny action result raportu — uruchamia mechanizm wydruków. Działa w **trzech trybach**:
|
||||
|
||||
1. **Tryb interaktywny (menu)** — bez `TemplateFileName`, framework otwiera okno raportu i ewentualne
|
||||
okno parametrów (`UseReportMenu == true`). Stosować, gdy chcemy pokazać użytkownikowi listę
|
||||
dostępnych wzorców dla danego typu/ViewInfo.
|
||||
2. **Tryb automatyczny (z kodu)** — z `TemplateFileName`, bez UI raportu. Wzorzec wskazany jawnie,
|
||||
wydruk od razu generowany. Można dodać `OutputHandler` do przejęcia strumienia wynikowego.
|
||||
3. **Tryb serwisowy (bez rezultatu)** — przez `IReportService.GenerateReport / GenerateReportStr /
|
||||
PrintReport`. Stosować w testach, taskach tła i kodzie nie-UI.
|
||||
|
||||
#### Najważniejsze property
|
||||
|
||||
| Property | Znaczenie |
|
||||
|---|---|
|
||||
| `TemplateFileName` | Nazwa lub ścieżka wzorca (`.repx`, `.repx.cs`, `.aspx`, `.dotx`) lub XML z ustawieniami wydruku. Ustawienie wyklucza `ReportName`. |
|
||||
| `TemplateFileSource` | `AspxSource.Local` (plik na dysku) / `Storage` (konfiguracja w bazie — pliki w `XtraReports/...`). |
|
||||
| `ReportName` | Nazwa raportu z menu (tryb interaktywny). Wyklucza `TemplateFileName`. |
|
||||
| `DataType` | Typ danych — `typeof(Towar)` (jeden obiekt), `typeof(Towary)` (cały View), `typeof(Towar[])` (zaznaczone wiersze). Steruje też ładowaniem listy dostępnych wydruków. |
|
||||
| `ViewInfo` | ViewInfo źródłowego widoku (np. dla raportów listy z customowym ViewInfo). |
|
||||
| `ViewNames` | Nazwy widoków, w których wyszukać raport po nazwie. |
|
||||
| `Rows` | `IEnumerable` z wierszami źródłowymi (zamiast pobierania z `Context`). **Nie działa** w trybie menu. |
|
||||
| `Context` | Kontekst raportu — źródło parametrów (`Context.Set(params)`), zaznaczeń, kultury. |
|
||||
| `OutputFormat` | `HTML` (domyślnie) / `PDF` / `TXT`. |
|
||||
| `Target` | `File` / `Preview` / `Printer`. Z `OutputHandler` traktowany jak `File`. |
|
||||
| `PrinterName` | Drukarka dla `Target = Printer`. |
|
||||
| `CultureInfo` | Język wydruku (nadpisuje kulturę sesji — patrz `DxReport_Generator_Dx_Zakup_English_ReportResult`). |
|
||||
| `AskForParameters` | `false` = wydruk bez pytania o parametry (wymaga ustawionych parametrów w `Context`). |
|
||||
| `Sign` / `VisibleSignature` / `Encrypt` | Podpis certyfikatem i hasło PDF (tylko tryb interaktywny w wersji desktop). |
|
||||
| `OutputHandler` | `Func<Stream, object>` — przejmuje wygenerowany strumień, jego wynik staje się rezultatem akcji. Tylko z `TemplateFileName`. |
|
||||
| `ParametersHandler` | `Action<Type, Context>` wywoływany przed pytaniem o parametry — sposób na zainicjowanie obiektów parametrów (oddzielnie dla każdego typu). |
|
||||
| `Caption` | Tytuł okna. |
|
||||
|
||||
#### Wzorzec: wydruk z akcji (worker / extender)
|
||||
|
||||
```csharp
|
||||
[Action("Drukuj fakturę")]
|
||||
public object DrukujFV() {
|
||||
Context.Set(new SprzedazSnippet.MyParametryWydruku(Context));
|
||||
return new ReportResult {
|
||||
TemplateFileName = "Sprzedaz.repx",
|
||||
DataType = typeof(DokumentHandlowy),
|
||||
Context = Context,
|
||||
AskForParameters = false,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### Wzorzec: wydruk z testu / taska (bez UI)
|
||||
|
||||
```csharp
|
||||
var rs = Session.GetRequiredService<IReportService>();
|
||||
|
||||
Context.Set(new SprzedazSnippet.MyParametryWydruku(Context));
|
||||
|
||||
var rr = new ReportResult {
|
||||
TemplateFileName = "Sprzedaz.repx",
|
||||
DataType = typeof(DokumentHandlowy),
|
||||
Context = Context,
|
||||
AskForParameters = false,
|
||||
};
|
||||
|
||||
string html = rs.GenerateReportStr(rr); // HTML jako string
|
||||
// lub
|
||||
using var stream = rs.GenerateReport(rr); // strumień (PDF / inny)
|
||||
// lub
|
||||
rs.PrintReport(rr, archive: true, archivePath: "C:\\Archive");
|
||||
```
|
||||
|
||||
#### Wzorzec: wzorzec ze storage (XtraReports/Wzorce użytkownika)
|
||||
|
||||
```csharp
|
||||
var rr = new ReportResult {
|
||||
TemplateFileName = "XtraReports/Wzorce użytkownika/EmptyReport.repx.cs",
|
||||
TemplateFileSource = AspxSource.Storage,
|
||||
Context = Context,
|
||||
AskForParameters = false,
|
||||
};
|
||||
```
|
||||
|
||||
#### Wzorzec: zaznaczone wiersze + custom params
|
||||
|
||||
```csharp
|
||||
Context.Set(towary); // tablica zaznaczonych Row
|
||||
Context.Set(new CennikViewInfo.CennikParams(Context));
|
||||
|
||||
var rr = new ReportResult {
|
||||
DataType = typeof(Towar[]), // l.mn. = zaznaczone
|
||||
TemplateFileName = "...",
|
||||
TemplateFileSource = AspxSource.Storage,
|
||||
Context = Context,
|
||||
OutputFormat = ReportFormats.TXT,
|
||||
AskForParameters = false,
|
||||
};
|
||||
```
|
||||
|
||||
#### Wzorzec: jeden obiekt + powiązane konteksty
|
||||
|
||||
```csharp
|
||||
var fvNewSession = Session.Get(fv);
|
||||
Context.Set(fvNewSession); // single
|
||||
Context.Set(new[] { fvNewSession }); // jako tablica (dla DataType = Towar[])
|
||||
Context.Set(new SprzedazSnippet.MyParametryWydruku(Context));
|
||||
|
||||
var rr = new ReportResult {
|
||||
TemplateFileName = "Sprzedaz.repx",
|
||||
DataType = typeof(DokumentHandlowy),
|
||||
Context = Context,
|
||||
AskForParameters = false,
|
||||
};
|
||||
```
|
||||
|
||||
#### Wzorzec: wymuszenie języka wydruku
|
||||
|
||||
```csharp
|
||||
var rr = new ReportResult {
|
||||
TemplateFileName = "Zakup.repx",
|
||||
DataType = typeof(DokumentHandlowy),
|
||||
Context = Context,
|
||||
OutputFormat = ReportFormats.TXT,
|
||||
CultureInfo = CoreTools.CultureEN,
|
||||
AskForParameters = false,
|
||||
};
|
||||
```
|
||||
|
||||
#### Sprawdzenie wymaganych typów parametrów
|
||||
|
||||
Przykład uzupełnia context standardowymi wartościami parametrów potrzebnymi dla raportu.
|
||||
|
||||
```csharp
|
||||
Type[] paramTypes = rs.GetParameterTypes("Sprzedaz.repx", Context);
|
||||
foreach (Type t in paramTypes) {
|
||||
Context.Set(Activator.CreateInstance(t, Context));
|
||||
}
|
||||
```
|
||||
|
||||
#### Deprecated property
|
||||
|
||||
- `TemplateType` → używać `TemplateFileName`.
|
||||
- `Format` (`ReportResultFormat`) → używać `OutputFormat` (`ReportFormats`).
|
||||
- `Preview` → używać `Target = ReportTargets.Preview`.
|
||||
- `SilentProgress` → używać `!AskForParameters`.
|
||||
|
||||
### `ReportOrganizerResult`
|
||||
|
||||
Menedżer raportów (lista raportów dla tabeli/widoku) — okno zarządzania zestawem raportów dla
|
||||
podanego typu danych.
|
||||
|
||||
### `ReportEditorResult`
|
||||
|
||||
Otwarcie edytora raportu (DOTX, DX) — w zależności od `Format` wybierany jest odpowiedni handler.
|
||||
|
||||
### `PdfResult`
|
||||
|
||||
Pojedynczy PDF (do podglądu, druku lub pobrania) sterowany przez `Action`:
|
||||
`Preview` / `Print` / `Save` / `OpenInBrowser`.
|
||||
|
||||
### `PdfResult[]`
|
||||
|
||||
Tablica PDF — handler (`PdfsResultHandler`) wysyła wszystkie na drukarkę przez `IPrintingService`.
|
||||
|
||||
### `DotxReportPrintResult`, `TextReportPrintResult`, `DxReportPrintResult`
|
||||
|
||||
Specjalizowane action result wydruku / podglądu konkretnych formatów (DOTX edytor, raport tekstowy,
|
||||
DevExpress).
|
||||
|
||||
## Dialogi parametrów
|
||||
|
||||
### `QueryContextInformation`
|
||||
|
||||
Otwiera okno z parametrami uzupełniającymi `Context` przed wywołaniem właściwej operacji. To samo
|
||||
okno pojawia się przed niektórymi czynnościami z menu lub przed raportami. Po `OK` wywoływany jest
|
||||
handler, który dostaje uzupełnione obiekty parametrów jako argumenty. Po `Cancel` — `CancelHandler`.
|
||||
|
||||
#### Mechanizm
|
||||
|
||||
1. Akcja zwraca `QueryContextInformation` z handlerem typu `Func<Tn, object>`.
|
||||
2. Framework patrzy na typy parametrów handlera (`T1`, `T2`, ...).
|
||||
3. Dla każdego typu sprawdza, czy `Context` zawiera już instancję — jeśli **tak**, pomija
|
||||
pytanie i od razu wywołuje handler.
|
||||
4. Jeśli czegoś brakuje, otwiera okno parametrów (renderowane przez `QueryContextRenderer`).
|
||||
5. Po `OK` wywołuje handler z parametrami pobranymi z `Context`.
|
||||
6. Wartość zwrócona z handlera staje się **kolejnym action result** (rekurencyjnie obsługiwana).
|
||||
|
||||
#### Tworzenie — fabryki `Create`
|
||||
|
||||
```csharp
|
||||
// Jeden typ parametrów
|
||||
QueryContextInformation.Create<Params>(p => DoWork(p));
|
||||
|
||||
// Kilka typów (do 6)
|
||||
QueryContextInformation.Create<Params1, Params2>((p1, p2) => DoWork(p1, p2));
|
||||
|
||||
// Context + parametry (Context można dostać jako pierwszy parametr)
|
||||
QueryContextInformation.Create<Context, Params>((cx, p) => DoWork(cx, p));
|
||||
|
||||
// Bez handlera — sama informacja "wypełnij te typy w kontekście"
|
||||
QueryContextInformation.CreateForTypes(typeof(Params1), typeof(Params2));
|
||||
|
||||
// Z dowolnego Delegate
|
||||
QueryContextInformation.CreateFromHandler(myDelegate);
|
||||
```
|
||||
|
||||
#### Klasa parametrów
|
||||
|
||||
Typowo dziedziczy z `ContextBase` (przyjmuje `Context` w konstruktorze, ma `OnChanged()` do
|
||||
odświeżania), używa atrybutów Soneta i `System.ComponentModel`:
|
||||
|
||||
```csharp
|
||||
[Caption("Parametry wydruku")]
|
||||
class MyParams(Context context) : ContextBase(context) {
|
||||
|
||||
[Category("Daty")] // grupowanie wizualne
|
||||
[Caption("Data od")]
|
||||
[Priority(1)] // kolejność w grupie
|
||||
[Accessor(AutoChange=true)]
|
||||
public Date DataOd { get; set; }
|
||||
|
||||
[Category("Daty")]
|
||||
[Caption("Zakres")]
|
||||
[Priority(3)]
|
||||
[Accessor(AutoChange=true)]
|
||||
public FromTo Okres { get; set; }
|
||||
|
||||
[Category("Informacje")]
|
||||
[Caption("Opis")]
|
||||
[Required]
|
||||
[Accessor(AutoChange=true)]
|
||||
public string Info { get; set; }
|
||||
|
||||
[Hidden] // ukrycie pola
|
||||
public int Internal { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
Renderer:
|
||||
|
||||
- grupuje pola po `[Category]` (`GroupContainer` z `CaptionHtml = nazwa kategorii`),
|
||||
- sortuje wewnątrz grupy po `[Priority]` (rosnąco),
|
||||
- pomija pola z `[Hidden]` / `[Browsable(false)]`,
|
||||
- `[Accessor(AutoChange=true)]` zadba o automatycznie wywołanie `Session.InvokeChanged()` na `set`.
|
||||
- może renderować tę samą kategorię wielokrotnie, jeśli pola są przeplatane innymi.
|
||||
|
||||
#### Wzorzec: zapytanie o parametr w workerze
|
||||
|
||||
```csharp
|
||||
[Action("Zmień podstawę zwolnienia")]
|
||||
public object Zmien() {
|
||||
return QueryContextInformation.Create<Params>(p => {
|
||||
using var t = Towar.Session.Logout(true);
|
||||
Towar.PodstawaZwolnienia = p.Podstawa;
|
||||
t.Commit();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### Wzorzec: łańcuch dialogów (wynik handlera = kolejny `QueryContextInformation`)
|
||||
|
||||
```csharp
|
||||
[Action("Dwuetapowy dialog")]
|
||||
public object Wieloetapowo() {
|
||||
return QueryContextInformation.Create<Params1>(p1 =>
|
||||
QueryContextInformation.Create<Params2>(p2 => {
|
||||
using var t = Session.Logout(true);
|
||||
// wykorzystaj p1 i p2
|
||||
t.Commit();
|
||||
return null;
|
||||
})
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Wzorzec: dialog wewnątrz `FormActionResult.CommittedHandler`
|
||||
|
||||
```csharp
|
||||
return new FormActionResult {
|
||||
EditValue = new SecondTestObject { Context = Context },
|
||||
UseDialog = true,
|
||||
CommittingHandler = cx => FormAction.Close,
|
||||
CommittedHandler = cx => QueryContextInformation.Create<Params>(p => {
|
||||
using var t = Towar.Session.Logout(true);
|
||||
Towar.PodstawaZwolnienia = p.Podstawa;
|
||||
t.Commit();
|
||||
return Towar; // otworzy formularz dla Towar po pytaniu
|
||||
})
|
||||
};
|
||||
```
|
||||
|
||||
#### Wzorzec: dialog z `MessageBoxInformation` jako wynikiem
|
||||
|
||||
```csharp
|
||||
public object Pokaz() {
|
||||
return QueryContextInformation.Create((MessageParams p) =>
|
||||
new MessageBoxInformation {
|
||||
Caption = "Test".Translate(),
|
||||
Text = p.Message,
|
||||
Type = p.IsWarning
|
||||
? MessageBoxInformationType.Warning
|
||||
: MessageBoxInformationType.Information
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### Wzorzec: dialog z plikami (`NamedStream[]`)
|
||||
|
||||
`QueryContextInformation` obsługuje też typy z plikami — w klasie parametrów `NamedStream` lub
|
||||
`NamedStream[]` z `GetListXxx()` zwracającym `FileDialogInfo`:
|
||||
|
||||
```csharp
|
||||
class NsArgs : ContextBase {
|
||||
public NsArgs(Context cx) : base(cx) {}
|
||||
|
||||
public NamedStream[] Streams { get; set; }
|
||||
|
||||
public FileDialogInfo GetListStreams()
|
||||
=> new FileDialogInfo { InitialDirectory = "x:\\" }
|
||||
.AddTxtFilter()
|
||||
.AddXmlFilter();
|
||||
}
|
||||
|
||||
// użycie:
|
||||
return QueryContextInformation.Create((NsArgs ns) => ns.Streams[0].FileName);
|
||||
```
|
||||
|
||||
#### Property obiektu
|
||||
|
||||
| Property | Znaczenie |
|
||||
|---|---|
|
||||
| `Context` | Kontekst, na którym pracuje okno. Standardowo `null` → użyty zostanie kontekst wywołania. |
|
||||
| `Caption` | Tytuł okna. |
|
||||
| `Data` | Dane przekazane do konstruktora (rzadko używane bezpośrednio). |
|
||||
| `Types` | Tablica typów do uzupełnienia w kontekście — gdy używamy `CreateForTypes`. |
|
||||
| `AcceptHandler` | `Func<object>` bez parametrów. Alias na handler ustawiony przez `Create<>`. |
|
||||
| `CancelHandler` | `Func<object>` — wynik traktowany jak kolejny action result. |
|
||||
| `ResultHandler` | `Func<object, object>` — postprocessing wartości zwróconej z handlera. |
|
||||
| `ObjectConstructor` | `ConstructorInfo` do tworzenia obiektu wynikowego (zaawansowane). |
|
||||
| `GetHandler()` | Zwraca `Delegate` przekazany do `Create<>` (dla refleksji w testach). |
|
||||
| `SetCaption(c)` / `SetCancelHandler(h)` | Fluent setter. |
|
||||
|
||||
#### `TryInvoke(Context)`
|
||||
|
||||
Pozwala uniknąć okna, gdy parametry **są już** w kontekście:
|
||||
|
||||
```csharp
|
||||
// 1) gdy w kontekście brakuje Params - zwraca self (otwarcie okna)
|
||||
object r = QueryContextInformation
|
||||
.Create<Params>(MyAction)
|
||||
.TryInvoke(cx);
|
||||
// r is QueryContextInformation == true
|
||||
|
||||
// 2) gdy Params jest w kontekście - wywołuje handler natychmiast
|
||||
cx.Set(new Params(cx) { ... });
|
||||
object r = QueryContextInformation
|
||||
.Create<Params>(MyAction)
|
||||
.TryInvoke(cx);
|
||||
// r == wynik MyAction
|
||||
```
|
||||
|
||||
#### Walidacja typu propertysów
|
||||
|
||||
Pola z atrybutem `[Context<T>(nameof(T.Prop))]` muszą mieć właściwy typ wartości docelowej (typ
|
||||
property `T.Prop`). Niezgodność → `Context.InvalidValueException` przy wywołaniu
|
||||
`ContextInvoker.CreateObject<>()`.
|
||||
|
||||
### `StartActionInformation`
|
||||
|
||||
Wewnętrzny action result — uruchomienie akcji w nowym kontekście (używany przez framework
|
||||
do delegowania wykonania workera). Rzadko zwracany ręcznie.
|
||||
|
||||
## Operacje klienta i bezpieczeństwo
|
||||
|
||||
### `ClientActionResult`
|
||||
|
||||
Wywołanie operacji w aplikacji klienckiej **SonetaFrame** (desktop wrapper). Działa tylko gdy
|
||||
`BusTools.DeviceType.IsBrowserApp()`. Pozwala wykonać akcję po stronie klienta (otwarcie pliku
|
||||
lokalnego, integracja z systemem operacyjnym) i opcjonalnie odebrać odpowiedź przez `ResponseHandler`.
|
||||
|
||||
### `MfaRequest` / `MfaSourceBase`
|
||||
|
||||
2FA (Multi-Factor Authentication) — uruchamia okno weryfikacji tożsamości użytkownika. Handler
|
||||
deleguje do serwisu `IMfaHandleResolver`. Stosować dla akcji wymagających dodatkowego potwierdzenia.
|
||||
|
||||
### `ClipboardStream`
|
||||
|
||||
Operacja na schowku przeglądarki (kopiowanie do / odczyt z).
|
||||
|
||||
## Tabela szybkiego wyboru
|
||||
|
||||
| Co chcę zrobić | Co zwrócić |
|
||||
|---|---|
|
||||
| Pokazać komunikat | `string` lub `MessageBoxInformation` |
|
||||
| Pokazać błąd | `Exception` (throw) lub `MessageBoxInformation` (Type = Error) |
|
||||
| Zapisać/zamknąć formularz | `FormAction.Save*` / `FormAction.Close` |
|
||||
| Zadać pytanie tak/nie | `MessageBoxInformation` z `YesHandler`/`NoHandler` |
|
||||
| Otworzyć obiekt do edycji | sam obiekt (`Row` lub inny) |
|
||||
| Otworzyć inny folder | `NavigationResult` |
|
||||
| Otworzyć stronę WWW | `HyperlinkResult` |
|
||||
| Pobrać plik | `NamedStream` |
|
||||
| Pobrać archiwum plików | `NamedStream[]` |
|
||||
| Wydruk PDF | `PdfResult` lub `PdfResult[]` |
|
||||
| Raport | `ReportResult` |
|
||||
| Zapytać o parametry | `QueryContextInformation` |
|
||||
| Nic nie robić | `null` / `void` |
|
||||
|
||||
Reference in New Issue
Block a user