Codebasis als Dateien ins Arbeitsrepo statt als Gitlink

QuellCode/CentronERP war nur als Gitlink (Submodul-Referenz auf 79c1142)
getrackt, ohne .gitmodules und ohne erreichbares Remote. Der
Untersuchungsgegenstand der Versuchsreihe war damit nicht reproduzierbar
gesichert: Ein Klon haette ein leeres Verzeichnis erhalten, und die Belege
der 3.287 Anforderungen waeren nicht ueberpruefbar gewesen.

Umstellung:
- Historie nach c:\DEV\CentronERP_git_snapshot_79c1142 ausgelagert
  (vollstaendig lesbar, enthaelt 79c1142 und Vorgaenger 89ccfd6)
- Gitlink aus dem Index entfernt
- Dateiinhalt aufgenommen: 24.557 Dateien, rund 333 MB

Die verschachtelte .gitignore der Codebasis gilt weiter, Build-Artefakte
bleiben ausgeschlossen. Details in Versuche/Versuch_01/_Codebasis-Nachweis.md
This commit is contained in:
Christoph Schwörer
2026-08-26 07:43:51 +02:00
parent 18edae75b6
commit f045b99a25
24664 changed files with 5846716 additions and 1 deletions
@@ -0,0 +1,3 @@
# How to create a dialog window
I don't know, but I would like to - please tell me.
@@ -0,0 +1,116 @@
# How to create a module in c-entron.NET
A module in the c-entron<span>.NET is just a view that can be displayed in the main window. It can show up in the module list on the left and can be docked and undocked from the main window.
We'll be using a module to manage our `Thingies` again. If you want to know how to create webservice methods for our thingies check out [this](How-to-add-webservice-methods.md).
## ICentronAppModuleController
The first class to create is a `..AppModuleController`. For us this will be named `ThingiesAppModuleController`.
This class needs to implement the `ICentronAppModuleController` interface. If you go to the `ICentronAppModuleController.cs` file there are summaries for each property and how to fill them properly.
``` csharp
public class TicketListAppModuleController : ICentronAppModuleController
{
public string ModuleName => "Dinge-Liste";
public BitmapImage ImageSmall => new BitmapImage(new Uri("pack://application:,,,/c-entron 2.0;component/Images/Icons/16x16/Thingies_16x16.png"));
public BitmapImage ImageLarge => new BitmapImage(new Uri("pack://application:,,,/c-entron 2.0;component/Images/Icons/32x32/Thingies_32x32_32x32.png"));
public string Description => "Alle Ihre Dinge auf einen Blick";
public CentronModuleCategory MainCategory => CentronModuleCategory.MyCentron;
public string ID => "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}";
public string ReportGroupGuid => null;
public CentronConnectionType[] SupportsConnectionTypes => new[] { ronConnectionType.CentronWebServices, entronConnectionType.SqlServer }
public BaseModule CreateModuleInstance(params object[] param)
{
var viewModel = new ThingiesViewModel();
return new ThingiesView
{
DataContext = viewModel
};
}
public IList<ICentronAppModuleSettingController> GetSettings() => new <ICentronAppModuleSettingController>
{
new ThingiesSettingsController()
};
public void Dispose()
{
}
}
```
## BaseModule (View)
Next we'll create the view and as we've already seen in our `AppModuleController.CreateModuleInstance(..)` it will be called `ThingiesView`. The easiest way to create it, is just to let VisualStudio create a `User Control(WPF)` then change it's type to `BaseModule`. To do this go to the `ThingiesView.xaml.cs` and delete the inheritance of `UserControl`. Next go to `ThingiesView.xaml` and replace `UserControl` with ` controls:BaseModule`, then add this namespace: `xmlns:controls="clr-namespace:CentronSoftware.Centron.WPF.UI.Extension.Controls;assembly=Centron.WPF.UI.Extension"`
*Pro tip: add `d:DataContext="{d:DesignInstance module:TicketListModuleViewModel}"` for intelisense in xaml.*
As all our modules need a ribbon you'll need to implement one of 3 interfaces in your code-behind (`Thingies.xaml.cs`):
interface|function
--|--
IRibbonControlModule|Adds the GetRibonControl() method where your ribbon gets returned
IRibbonControlModuleWithDefaultButtons|Same as above, but also adds our default buttons (Save layout, reset layout, settings, videoportal, reports)
IRibbonControlModuleWithDefaultButtonsAndPreferredSendType|Same as above, but also adds buttons for send type for reports.
``` csharp
public partial class ThingiesView : IRibbonControlModuleWithDefaultButtons
{
public ThingiesView()
{
this.InitializeComponent();
}
public RibbonControl GetRibbonControl()
{
return this.Ribbon;
}
}
```
``` xml
<controls:BaseModule x:Class="CentronSoftware.Centron.WPF.UI.Modules.Helpdesk.TicketDetails.TicketDetailView"
xmlns:controls="clr-namespace:CentronSoftware.Centron.WPF.UI.Extension.Controls;assembly=Centron.WPF.UI.Extension"
[..]
>
[..]
<dxb:RibbonControl x:Name="Ribbon">
[..]
</dxb:RibbonControl>
[..]
</controls:BaseModule>
```
If you want to display a message box on closing or cancel closing, you can override `public override void FormClosing(out bool cancel)` and cancel the close by settings the boolean to **true**.
## ViewModel
At last we will create our viewmodel aptly named `ThingiesViewModel`. It doesnt really need anything, just implement `BindableBase` like every other viewmodel and set it as datacontext for the view in your appmodulecontroller.
## ModuleRegistration
If your module is supposed to be available via the module list on the left, then we also need to register it in `ModuleRegistration.cs`. Simply go to the constructor and add your module to the _module list like this:
``` csharp
ModuleRegistrationItem.For<ThingiesAppModuleController>(
() => Helper.NoRightCheck(),
() => ModuleFeatures.IsThingiesAvailable),
```
The first parameter allows you to check if the user has the specified rights.
The second allows you to hide your module until it is ready to be released. Simply create an entry in `ModuleFeatures.cs`.
@@ -0,0 +1,52 @@
# How to create a settings page
Naming convention for your settingspage is simple:
[YourSettingsName]Settings[Controller/View/ViewModel]
## Create your Controller
First you have to create a class that implements `ICentronAppModuleSettingController`.
`CreateSettingControlInstance()` needs to handle the creation of the view and the viewmodel and **set the DataContext for the view**. This should all be done in this method and not in the ctor of the view.
**You MUST also add an ImageLarge.**
## Create your View
Next create a view of the type `BaseSettingControl`.
You have to implement `DoInitalize()` and simply route it through to your viewmodel. It should handle all the loading of settings.
Then implement `DoSave()` and again simply route it to your viewmodel. If you want to restrict saving you can also implement `CanSave()`. `DoAfterSave()` allows you to execute something after saving of all pages is complete.
The view should not implement a WaitIndicator. One will be shown on initialization and on saving by the container.
## Create your ViewModel
The viewmodel does not need to implement anything specific aside from `BindableBase`.
It should handle initialization and loading of settings in a asnyc method called from the view. Nothing should be loaded via the ctor.
Saving should be done with another async method that is called from the view.
If there is an error during loading or saving you need to throw an exception. The container will handle it and show a error dialog. **Do NOT display a messagebox yourself**.
Of course all other c-entron<span>.NET conventions apply ;)
## Register your Controller
If your settings applies to a specific module it needs to be registered in that modules `ICentronAppModuleController.GetSettings()`.
If it does not belong to a specific module it needs to be registered in `ModuleRegistration.GetSettingsWithoutModule()`.
If your settings page is a personal settings it needs to be registered in `ModuleRegistration.GetPersonalSettings()`.
**If the specific module is not registered in the moduleslist you need to register your settings in both `ICentronAppModuleController.GetSettings()` in your module and `ModuleRegistration.GetSettingsWithoutModule()`.**
## Examples
```
Centron.WPF.UI/Modules/Administration/CentronConfigDb/CentronConfigDbSettingsController.cs
Centron.WPF.UI/Modules/Helpdesk/Settings/TypesHelpdeskTypeSettingsControllers.cs
Centron.WPF.UI/Modules/MyCentron/PersonalSettings/UI/PersonalUISettingsController.cs
```
@@ -0,0 +1,280 @@
# Localization
## General structure
We use the .NET default approach for the localization. Each DLL which needs localized strings, adds the necessary resource files.
The used language is determined by CultureInfo.CurrentUICulture.
## Resource Files Structure
The application has separate resource files for different layers and supports multiple languages:
**WPF UI Layer:**
- **German (default)**: `src/centron/Centron.WPF.UI/Resources/LocalizedStrings.resx`
- **English**: `src/centron/Centron.WPF.UI/Resources/LocalizedStrings.en.resx`
**Business Logic Layer:**
- **German (default)**: `src/backend/Centron.BL/Resources/LocalizedStrings.resx`
- **English**: `src/backend/Centron.BL/Resources/LocalizedStrings.en.resx`
### Language Support
- **Default Language**: German - stored in the base resource files (`LocalizedStrings.resx`)
- **Additional Languages**: English - stored in language-specific resource files (`LocalizedStrings.en.resx`)
- **Language Selection**: Determined by `CultureInfo.CurrentUICulture`
Each resource file contains the same keys but with text in the respective language. When creating new localized strings, you must provide translations for both German and English.
**Example of the same key in different languages:**
```
German (LocalizedStrings.resx):
LoginDialogView_Benutzername = "Benutzername"
English (LocalizedStrings.en.resx):
LoginDialogView_Benutzername = "Username"
```
## Usage Examples
### XAML Usage
In XAML files, localized strings are accessed using static property syntax with the appropriate namespace declaration.
**Namespace Declaration:**
Add this to your XAML file's root element:
```xml
xmlns:properties="clr-namespace:CentronSoftware.Centron.WPF.UI.Resources"
```
**Usage in XAML:**
```xml
<!-- For text properties -->
<Label Content="{x:Static properties:LocalizedStrings.LoginDialogView_Benutzername}" />
<!-- For placeholder text -->
<TextEdit NullText="{x:Static properties:LocalizedStrings.LoginDialogView_Benutzername}" />
<!-- For tooltip text -->
<Button ToolTip="{x:Static properties:LocalizedStrings.SomeTooltipKey}" />
```
**Real Example from LoginDialogView.xaml:**
```xml
<dxe:TextEdit Name="UsernamTextEdit"
ShowNullTextForEmptyValue="True"
NullText="{x:Static properties:LocalizedStrings.LoginDialogView_Benutzername}"
Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}" />
```
### Code-Behind Usage (WPF UI)
In C# code-behind files in the WPF UI project, add the using statement and access strings directly.
**Using Statement:**
```csharp
using CentronSoftware.Centron.WPF.UI.Resources;
```
**Usage in Code:**
```csharp
// For status messages
using (CentronApplication.Instance.AppStatusBar.PushMessage(
LocalizedStrings.LoginDialogViewModel_DoLogin_Anmeldung))
{
// Your code here
}
// For exception messages
throw new Exception(LocalizedStrings.SomeErrorMessageKey);
// For dialog messages
var message = LocalizedStrings.ConfirmationMessageKey;
```
**Real Example from LoginDialogViewModel.cs:**
```csharp
using (CentronApplication.Instance.AppStatusBar.PushMessage(
LocalizedStrings.LoginDialogViewModel_DoLogin_Anmeldung))
{
var preResult = await PreDoLoginToCentron();
// ... rest of login logic
}
```
### Business Logic Usage
In business logic classes, localized strings are accessed similarly but using the business logic resource namespace.
**Using Statement:**
```csharp
using Centron.BusinessLogic.Resources;
```
**Usage in Business Logic:**
```csharp
// For exception messages
throw new ResultException(
LocalizedStrings.AppSettingsGroupBL_UpdateUpdateAvailableNotificationSettings_WählenSieMitarbeiterAusDieBeiVerfügbarenUpdatesEineBenachrichtigungAngezeigtBekommenSollen,
DefaultMessageCodes.BadRequest);
// For validation messages
var errorMessage = LocalizedStrings.ValidationErrorKey;
```
**Real Example from AppSettingsGroupBL.cs:**
```csharp
throw new ResultException(
LocalizedStrings.AppSettingsGroupBL_UpdateUpdateAvailableNotificationSettings_WählenSieMitarbeiterAusDieBeiVerfügbarenUpdatesEineBenachrichtigungAngezeigtBekommenSollen,
DefaultMessageCodes.BadRequest);
```
## Common WPF Properties Requiring Localization
When auditing XAML files for hardcoded text that needs localization, pay special attention to these classic WPF properties that commonly contain user-facing text:
### Primary Text Properties
- **`Text`** - Direct text content (TextBlock, Run, etc.)
- **`Content`** - Button content, CheckBox content, etc.
- **`Label`** - LayoutItem labels, form field labels
- **`Header`** - Headers in controls like TabItem, TreeViewItem, **GridColumn headers**
- **`Title`** - Window titles, ToolTip titles
- **`Caption`** - Ribbon page captions, group captions
### Input Control Properties
- **`NullText`** - Placeholder text in DevExpress editors
- **`Watermark`** - Placeholder text in standard controls
- **`ToolTip`** - Tooltip text for controls **and images in DataTemplates**
### Converter and Template Values
- **Converter Target Values** - Hardcoded strings in ObjectToObjectConverter mappings
- **DataTemplate Content** - Text within data templates, **including ToolTip properties on images and controls**
- **Style Setter Values** - Hardcoded text in style setters
### Grid Controls and Data Tables
- **`Header`** - GridColumn header text that displays column titles
- **Runtime Localization Strings** - Grid control runtime strings like "NoRecords" messages
- **DataTemplate ToolTips** - Tooltip text on images, buttons, and other controls within cell templates
- **Custom Grid Messages** - Any hardcoded text in grid customization areas
### Example Search Patterns
When auditing XAML files, search for these patterns:
```xml
Title="German Text"
Content="German Text"
Label="German Text"
Text="German Text"
Caption="German Text"
Header="German Text"
NullText="German Text"
Target="German Text"
ToolTip="German Text"
Value="German Text"
```
### Grid-Specific Examples
Pay special attention to grid controls:
```xml
<!-- GridColumn headers -->
<dxg:GridColumn Header="Bezeichnung" />
<dxg:GridColumn Header="Standard" />
<!-- DataTemplate tooltips -->
<Image ToolTip="Änderungen vorhanden" />
<!-- Runtime localization strings -->
<dxg:RuntimeStringIdInfo Value="Keine Verbindungen vorhanden." />
```
## Key Naming Conventions
Localization keys follow a structured naming pattern to ensure uniqueness and maintainability:
- **Format**: `[ClassName]_[MethodName]_[Description]` or `[ViewName]_[PropertyName]_[Description]`
- **Examples**:
- `LoginDialogView_Benutzername` - Username field in LoginDialogView
- `LoginDialogViewModel_DoLogin_Anmeldung` - Login process message
- `AppSettingsGroupBL_UpdateUpdateAvailableNotificationSettings_WählenSieMitarbeiterAusDieBeiVerfügbarenUpdatesEineBenachrichtigungAngezeigtBekommenSollen` - Business logic validation message
## Tools
#### ResXManager
Great tool for managing the language resource files. It is a visual studio extension. It provides a dialog too manage the resource and translate the resources.
It also adds a right click menu item "Move to Resource" for quick resource entry creation.
## Working
If we encounter strings which are localized through the old workflow (CentronLocalization.Instance.GetLocalizedString()) we replace it with the new workflow.
### Translate strings in code
1. Click into the string. (Complete string selection is not nessassry. The VS-Extension extends the selection automaticly. Be careful if your string contains ". In this case check if the complete text got selected. If not, select manualy.)
2. Right Click.
3. Select "Move to Resource".
4. The popup "Move to Resource" appears.
- For better read ability select at "Code" the format which adds the class and method name too the generated code.
- If the string contains variables {0}, {1} add a "Comment" for them. So we have a info in the resource file what values can be expected in the variables.
- After a klick on "OK" the extension creates a new entry in the resource file and replaces the string with the generated code property.
#### Namespaces
.xaml: `xmlns:properties="clr-namespace:CentronSoftware.Centron.WPF.UI.Resources"`
.cs: `using CentronSoftware.Centron.WPF.UI.Resources;`
#### Useful searches
These can be used by using the inbuilt search function: Open 'Find and Replace', disable 'Match case' and 'Match whole word', enable 'Use regular expressions' then select 'Currrent document' and 'Entire document'. Now you can just go through the file using 'Find Next' and you should catch most strings.
.cs:
`"[^"]*?"` - finds all strings
`(?=(^((?!///).)*$)).*((".+?")|('.+?')).*` - finds all strings excluding comments
`(LocalizationManager|CentronLocalization)\.Instance\.GetLocalizedString\("[0-9]*", "[^"]*?"\);` - finds texts already translated by the old system
.xaml:
`(Text|Label|Caption|ToolTip|Content|Header)="[^{]*?"` - finds most common string literals
`{lex:Loc[^"]*?"` - finds texts already translated by the old system
#### Keybindings
1. Open `Tools`>`Options`>`Keyboard`
2. Search for `EditorContextMenus.CodeWindow.Movetoresource`
3. Bind to the keys you like (don't foregt to press Assign)
4. Profit
### Translate entries in the resource file
1. To translate a resource entry, navigate to the Resource directory in your assembly.
2. Locate the file "LocalizedStrings.resx".
3. Right-Click it and select "Open in ResX Manager".
If the Resource Manager shows no files, click on "Refresh view".
- The manager highlights the not translated entries with a red background color.
- Additionaly this Tool contains a own tab for the translation. It shows the entries which are not translated. There is a auto translate function too.
## Setup localization for a assembly
1. Create a "Resources" directory, if not existing.
2. Add "New Item"
3. Select "Resources File"
4. Use as Name: LocalizedStrings.resx
5. Press "Add"-Button
6. If visual studio does open the resource file automaticly, close it.
7. Select the new file in the Solution Explorer.
8. Check The properties.
- Build Action: Embedded resource
- Custom Tool: ResXFileCodeGenerator. Enter PublicResXFileCodeGenerator if the assembly contains XAML UI.
9. Open "ResX Manager" through Tools (Visual Studio menu)
10. Click on "Refresh View", the new resource file should be visibly now.
11. Close the manager.
12. Translate a string in the source code.
13. Open the ResX Manager again.
14. If not selected, select the new resource file.
15. Because we have no resource files for the other languages yet, double click into the edit box and add a translation for the language. The tool will create a new resource file for the language.
16. Done. We can close the manager.
Its possible that the Resource Manager does not show the new created langugage files from the start. In this case press Refresh. This should fix the issue.
## Get localized strings through Web-Service call
To get the message in a specific langugage, it is necessary too add a new Attribut too the header "Accept-Language" (Value example: de-DE).
Example:
httpRequest.Headers.Add("Accept-Language", CultureInfo.CurrentUICulture.Name);