WPF window sablon

WPF window sablon
2018-07-26T17:07:14+02:00
2018-08-27T12:36:14+02:00
2022-10-15T21:26:36+02:00
fintagyula
Sziasztok.

Több, hasonló (vagy akár egyforma is) ablakot használok az adattáblák szerkesztéséhez. Annyira sikerült már uniformizálni, hogy mind a programkód, mind pedig az xaml kód egyforma. Természetesen azokkal az eltérésekkel, ami az adattáblák oszlopainak elnevezéséből és a hozzájuk rendelt label-ek szövegéből fakadnak. Szeretném, ha egyszer kellene megszerkesztenem az ablakot (mint valami user controlt) és a hozzá rendelendő adattáblafüggvényében változnának a feliratok akár a grid fejlécében, akár a nyomógombokon., stb.
Bonyolítja a képet, hogy entity framework-öt használok és bindingektől hemzseg a kód.
A kérdésem, hogy van-e erre valami idea, sablon, template, ami irányt mutatna, hogyan kell nagyüzemben legyártani az ablakokat?
Példának adom  a Torzsanyag.xaml-t:

<Window x:Name="TorzsAnyagW" x:Class="Rendeles.Torzsadat.TorzsAnyag" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Rendeles.Torzsadat" mc:Ignorable="d" Title="Anyagok" Height="333.924" Width="683" ResizeMode="NoResize" Closed="TorzsAnyagW_Closed" Icon="/Rendelo;component/Eroforrasok/view-pim-contacts.ico"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <DataGrid x:Name="AnyagokDg" Grid.Row="0" Grid.Column="0" AutoGenerateColumns="False" EnableRowVirtualization="True" Margin="5" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" IsReadOnly="True" SelectionMode="Single" Loaded="AnyagokDg_Loaded" SelectionChanged="AnyagokDg_SelectionChanged"> <DataGrid.ItemContainerStyle> <Style TargetType="DataGridRow"> <EventSetter Event="MouseDoubleClick" Handler="Row_DoubleClick"/> </Style> </DataGrid.ItemContainerStyle> <DataGrid.Columns> <DataGridTextColumn x:Name="anyagazon" Binding="{Binding anyagazon, Mode=TwoWay}" Header="ID" Width="50" Visibility="Hidden"/> <DataGridTextColumn x:Name="anyagcikkszam" Binding="{Binding anyagcikkszam, Mode=TwoWay}" Header="Cikkszám" Width="160"/> <DataGridTextColumn x:Name="anyagnev" Binding="{Binding anyagnev, Mode=TwoWay}" Header="Anyagnév" Width="160"/> <DataGridTextColumn x:Name="anyagcsnev" Binding="{Binding AnyagCsoport.anyagcsnev, Mode=TwoWay}" Header="Csoport" Width="100" /> <DataGridCheckBoxColumn x:Name="anyagaktiv" Binding="{Binding anyagaktiv, Mode=OneWay}" Header="Aktív" Width="50"/> </DataGrid.Columns> </DataGrid> <Grid Grid.Row="0" Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Button x:Name="Help24Bt" Grid.Row="0" Margin="5" Height="25" HorizontalAlignment="Right" Width="25" Padding="0" VerticalAlignment="Top" Click="Help24Bt_Click"> <Image Source="{Binding Source=/Rendelo;component/Eroforrasok/help-browser-2_24.ico}"/> </Button> <Button x:Name="AnyagNyomtatBt" Grid.Row="0" Grid.Column="1" Content="Nyomtatás" Margin="5" VerticalAlignment="Bottom" Click="AnyagNyomtatBt_Click"/> </Grid> <Grid x:Name="SzerkesztettanyagG" Grid.Row="1" Grid.Column="0"> <GroupBox x:Name="AnyagGb" Grid.Row="2" Header="Szerkesztés / új anyag" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" Width="524"> <Grid Margin="5"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid Grid.Column="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Label Content="Cikkszám:" Margin="5" Padding="4" /> <TextBox x:Name="CikkszamTb" Grid.Column="1" Height="25" Margin="5" Text="{Binding anyagcikkszam, Mode=OneWay, NotifyOnValidationError=true, ValidatesOnExceptions=true }" VerticalContentAlignment="Center" MaxLength="10" Width="160" /> <Label Content="Anyagnév:" Grid.Row="1" Margin="5" Padding="4"/> <TextBox x:Name="AnyagNevTb" Grid.Column="1" Grid.Row="1" Height="25" Text="{Binding anyagnev, Mode=OneWay, NotifyOnValidationError=true, ValidatesOnExceptions=true }" Margin="5" VerticalContentAlignment="Center" MaxLength="20" Width="160" /> <Label Content="Csoport:" Grid.Row="2" Margin="5" Padding="4"/> <ComboBox x:Name="AnyagcsoportCB" Grid.Column="1" Grid.Row="2" ItemsSource="{Binding Mode=OneWay}" DisplayMemberPath="anyagcsnev" SelectedValuePath="anyagcsazon" Height="25" Margin="5" Width="160"/> </Grid> <Grid Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Label Content="Leírás:" Margin="5" Padding="4"/> <TextBox x:Name="LeirasTb" Text="{Binding anyagleiras, Mode=OneWay, NotifyOnValidationError=true, ValidatesOnExceptions=true }" TextWrapping="Wrap" Margin="5" Grid.Column="1" Grid.ColumnSpan="3" MaxLength="255" Width="160" HorizontalAlignment="Left"/> <Label Content="Aktív:" Grid.Row="1" Padding="4" Margin="5" Width="41"/> <CheckBox x:Name="AnyagAktivCb" Grid.Row="1" Grid.Column="1" IsChecked="{Binding anyagaktiv, Mode=OneWay}" Margin="5" VerticalAlignment="Center"/> <Grid Grid.Row="2" Grid.ColumnSpan="2"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> </Grid> </Grid> </Grid> </GroupBox> </Grid> <Grid Grid.Row="1" Grid.Column="1" Margin="0" > <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Button x:Name="UjanyagBt" Grid.Row="2" Content="Új anyag" Margin="5" Click="UjanyagBt_Click"/> <Button x:Name="AnyagMentBt" Grid.Row="3" Content="Ment" Margin="5" Click="AnyagMentBt_Click"/> </Grid> </Grid> </Window>
valamint a hozzá tartozó csharp kódot:
using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Data.Entity; using Rendeles_DAL; namespace Rendeles.Torzsadat { public partial class TorzsAnyag : Window { public Anyag Szerkesztettanyag = new Anyag(); public Anyag Ujanyag = new Anyag(); public AnyagCsoport Szerkesztettanyagcsoport = new AnyagCsoport(); public List<AnyagCsoport> Anyagcsoportok = new List<AnyagCsoport>(); public TorzsAnyag() { InitializeComponent(); Anyagcsoportok = Rendelo._rendeles.AnyagCsoport.ToList(); SzerkesztettanyagG_kiurit(); } private void AnyagokDg_Loaded(object sender, RoutedEventArgs e) { var anyagok = Rendelo._rendeles.Anyag.ToList(); this.AnyagokDg.ItemsSource = anyagok; } private void Szerkesztett_ujanyag_feltoltes(object sender) { SzerkesztettanyagG.IsEnabled = true; if (sender is Button) { AnyagGb.Header = "Új anyag"; Ujanyag = new Anyag(); SzerkesztettanyagG.DataContext = Ujanyag; SzerkesztettanyagG_kiurit(); SzerkesztettanyagG.IsEnabled = true; } else if (sender is DataGrid) { AnyagGb.Header = "Anyag szerkesztése"; Szerkesztettanyag = (Anyag)AnyagokDg.SelectedItem; SzerkesztettanyagG.DataContext = Szerkesztettanyag; CikkszamTb.Text = Szerkesztettanyag.anyagcikkszam; AnyagNevTb.Text = Szerkesztettanyag.anyagnev; AnyagcsoportCB.ItemsSource = Anyagcsoportok; Szerkesztettanyagcsoport = Rendelo._rendeles.AnyagCsoport.Where(w => w.anyagcsazon == Szerkesztettanyag.anyagcsazon).SingleOrDefault(); if (Szerkesztettanyagcsoport != null) { AnyagcsoportCB.SelectedValue = Szerkesztettanyagcsoport.anyagcsazon.ToString(); } LeirasTb.Text = Szerkesztettanyag.anyagleiras; AnyagAktivCb.IsChecked = (bool)Szerkesztettanyag.anyagaktiv; } } private void AnyagMentBt_Click(object sender, RoutedEventArgs e) { if (SzerkesztettanyagG.DataContext == Ujanyag && SzerkesztettanyagG.IsEnabled) { if (CikkszamTb.Text != "" && AnyagNevTb.Text != "") { if (Rendelo._rendeles.Anyag.Where(w => w.anyagcikkszam == CikkszamTb.Text).SingleOrDefault() == null && Rendelo._rendeles.Anyag.Where(w => w.anyagnev == AnyagNevTb.Text).SingleOrDefault() == null) { var utolsoazon = Rendelo._rendeles.Anyag.OrderByDescending(p => p.anyagazon).FirstOrDefault(); if (utolsoazon != null) { Ujanyag.anyagazon = utolsoazon.anyagazon + 1; } Ujanyag.anyagcsazon = int.Parse(AnyagcsoportCB.SelectedValue.ToString()); Ujanyag.anyagcikkszam = CikkszamTb.Text; Ujanyag.anyagnev = AnyagNevTb.Text; Ujanyag.anyagleiras = LeirasTb.Text; Ujanyag.anyagaktiv = (bool)AnyagAktivCb.IsChecked; if (MessageBox.Show("Valóban hozzá akarja adni az Anyagokhoz " + CikkszamTb.Text + ", " + AnyagNevTb.Text + " anyagot?", "Új anyag", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { Rendelo._rendeles.Anyag.Add(Ujanyag); Rendelo._rendeles.SaveChanges(); AnyagokDg_Loaded(this, e); Ujanyag = null; Szerkesztett_ujanyag_feltoltes(UjanyagBt); } } else { MessageBox.Show("A cikkszám és/vagy név már használatban van", "Létező anyag", MessageBoxButton.OK); } } else { MessageBox.Show("Ellenőrizze a cikkszámot, anyagnevet!", "Anyagnevek", MessageBoxButton.OK); } } else if (SzerkesztettanyagG.DataContext == Szerkesztettanyag) { bool ervenyesanyag = true; var egyebanyagok = Rendelo._rendeles.Anyag.Where(a => a.anyagazon != Szerkesztettanyag.anyagazon).ToList(); if (egyebanyagok.Where(w => w.anyagcikkszam == CikkszamTb.Text).SingleOrDefault() == null) { Szerkesztettanyag.anyagcikkszam = CikkszamTb.Text; } else { MessageBox.Show("A cikkszám már használatban van", "Létező cikkszám", MessageBoxButton.OK); ervenyesanyag = fals
Mutasd a teljes hozzászólást!
Csatolt állomány
Talán egy újrahasznosítható UserControl-t kellene készítened és Dependency Property-ket használnod.

Egyszerű példa:
A Simple Pattern for Creating Re-useable UserControls in WPF / Silverlight

Esetleg kibővítheted Reflection-nel (pl futásidőben lekérdezheted az adott osztály adattagjait, stb ) ill. Attribute osztályok használatával.

Reflection (C#)
Attributes

Pl. én utóbbi kettőt arra használom, hogy C# osztályokból automatikusan CSV file-okat generáljak. Futás időben lekérdezem az input osztály adattagjait Reflection-nél, ezek lesznek a oszlopnevek, aztán az értékeket is, ezek lesznek a cellákban az adatok.

Totál fapados és nem túlzottan ajánlott, de egyszerű megoldás lehet, ha írsz egy console alkalmazást, ami Reflection használva legenerálja az adott osztályból a megfelelő XAML/C# kódot.
Mutasd a teljes hozzászólást!

  • Szia. T4 Text Template a kulcsszó (LINK). Eléggé bonyolult lenne jelen körülmények között értékelhető példát bemutatni rá, illetve kellő mértékig kifejteni.
    Nekem van egy olyan generátorom fejlesztés alatt, ami elég komoly szinten használ T4-et, például az alábbiak létrehozásához:

    - DbContext
    - Entities
    - Repositories
    - Unit of Work
    - Form

    Szóval megoldható a dolog,

    Itt van két oldal, ami sokat segíthet:
    Run-Time Text Generation with T4 Text Templates
    Writing a T4 Text Template
    Mutasd a teljes hozzászólást!
  • Köszönöm a gyors reagálást.
    Nem tudom elképzelni ezt a megoldást asztali alkalmazással. Az ASP.NET példák még inkább távol visznek a megértéstől: a program fordításakor az xaml és cs fájlokból lesz (majdnem) futó kód. Ez esetben - a futás közben generált kód (xaml-csharp) - hogy lesz értelmezhető a JIT-fordító számára?
    Pontosítom a problémámat: a sok window nem zavar (hisz a táblák révén vannak köztük aprócska különbségek), a gondom inkább a karbantarthatóság. Fejlesztés közben vissza-vissza nyúlok a kódhoz, mert egy-egy eseményt le kell kezelnem, vagy mást kell változtatnom. Azonban ezt x-szer végrehajtani (figyelve, hogy a helyes működés megmaradjon, tesztelni) az lélekölő - piramisépítő munka.
    A gondolat, hogy ezek az ablakok egy közös ősre lennének visszavezethetők, ezért született.
    Tanács?
    Mutasd a teljes hozzászólást!
  • Az enyém WinForms alkalmazáshoz készült. Az új adattáblákat, kapcsolatokat, adatokat, formokat Excel munkafüzetben lehet definiálni, és abból SQL szkriptet is előállít, de azt nem T4-gyel, ezért nem is említettem. Az SQL szkripten kívül minden mást az adatbázisban található táblák alapján készít el, de ha Excel munkafüzet van betöltve, automatikusan kiválasztja a benne található táblákat, ami nagy könnyebbséget jelent, mivel az adatbázisban 1000-nél is több van belőle. WPF ablakot is simán létre tudsz vele hozni, ha én is meg tudtam csinálni Form-mal, ahol szintén vagy egy UI definiáló (designer) fájl a kódon kívül. Mellékeltem egy képet. Eléggé zilált a kinézete, de jelen fejlesztési állapotban nem a UI a lényeg. Mivel ide nem tudok két képet mellékelni, egy másik hozzászóláshoz mellékelem a generált kódról készült képet, ami megmutatja, hogy nem csak jó, hanem szép kódot is lehet generálni.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Itt a generált kódról készült kép.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Most hétvégén beleolvasok a T4 világába és kipróbálom. Addig is köszönöm.
    Mutasd a teljes hozzászólást!
  • Forráskódot létre lehet hozni egyébként CodeDOM-mal is imperatív módon, de sokkal jobban jársz a deklaratív T4-gyel, amivel bármilyen szöveges fájlt előállíthatsz, így XAML fájlt is.
    Mutasd a teljes hozzászólást!
  • Talán egy újrahasznosítható UserControl-t kellene készítened és Dependency Property-ket használnod.

    Egyszerű példa:
    A Simple Pattern for Creating Re-useable UserControls in WPF / Silverlight

    Esetleg kibővítheted Reflection-nel (pl futásidőben lekérdezheted az adott osztály adattagjait, stb ) ill. Attribute osztályok használatával.

    Reflection (C#)
    Attributes

    Pl. én utóbbi kettőt arra használom, hogy C# osztályokból automatikusan CSV file-okat generáljak. Futás időben lekérdezem az input osztály adattagjait Reflection-nél, ezek lesznek a oszlopnevek, aztán az értékeket is, ezek lesznek a cellákban az adatok.

    Totál fapados és nem túlzottan ajánlott, de egyszerű megoldás lehet, ha írsz egy console alkalmazást, ami Reflection használva legenerálja az adott osztályból a megfelelő XAML/C# kódot.
    Mutasd a teljes hozzászólást!
  • Kedves akikari!

    Beleolvastam a Microsoftos leírásba (Code Generation and T4 Text Templates) illetve rátekintettem a generáló programod felületére. Nagy ráfordítást igényel tőlem és a munkák sürgetőek. Nem ezt az utat választom. Köszönöm a segítséged.
    Üdv. Gyula
    Mutasd a teljes hozzászólást!
  • Kedves Herendi!

    Bár az első link silverlight-os, azt megpróbálom majd átültetni az én alkalmazásaimra. Jelenleg vágom a fát tovább és egy kevésbé sürgős feladatnál megvalósítom ezt. Köszönöm a segítséget.
    Üdv. Gyula
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd