WPF MVVM adatkötés c#

WPF MVVM adatkötés c#
2021-09-29T18:28:37+02:00
2021-10-05T12:42:00+02:00
2022-10-15T21:26:07+02:00
Igthorn3
Sziasztok!
Próbálkozom WPF tanulással, de van egy kis döccenő, amit sehogy sem értek.
Az MVVM minta elgondolását elméletben értem (végigolvastam Bennage-Eisenberg WPF könyvét, és sok online példát, magyarázatot). Több példakódot megnéztem, kipróbáltam, de a saját elképzelésemet nem sikerül ezek alapján megvalósítani.

A megvalósítandó saját példám:
Egy ablakon négy darab TextBoxba írt számot gombnyomásra szeretnék megkeresni egy bizonyos mappában lévő fájlok nevében. Ha vannak ilyen fájlok, azokat listázni szeretném az ablakon egy ListViewban vagy ListBoxban.
Ha ebben kiválasztok elemeket, akkor gombnyomásra a fájlnevet és a fájl metaadatait szeretném tárolni egy szövegfájlban.
Úgy gondoltam, hogy létrehoznék egy osztályt, ami a fájlok keresésért felel, egy másikat, ami a szövegfájlba írást végzi, és egy harmadikat ami a két osztály és a View közötti kapcsolatért felel.
Azzal nem boldogulok, hogy a View és a három osztály viszonyát megfelelően összehozzam. Nem áll össze, hogy mit hol példányosítok, a gombok hol indítják az adott feladatot, a fájlkereső osztály hogyan kommunikál a kiíró osztállyal.

Ez lehet, hogy egy haszontalannak tűnő példa, de annak az elméletét és gyakorlatát szeretném megérteni, hogy több osztály hogyan kell viszonyuljon egymáshoz, a Viewhoz és a ViewModelhez.

Előre is köszönöm segítő hozzászólásaitokat.
Mutasd a teljes hozzászólást!
Ennyi olvasás után sem egyértelmű, az azt jelenti, hogy nem érted a XAML és az adatkötés lényegét. De ez nem baj, mert nem egyszerű, miközben mégis az.

Az Binding alapja, hogy minden, ami a felhasználói felületen történik, azt ezzel az interface-el kell kezdeni: INotifyPropertyChanged

Ezért szükséged van egy ősmodellre. Ezt nevezzük ÉrtesítésTulajdonságVáltozásról osztálynak, amit az INotifyPropertyChanged iterfész imlementálása

ÉrtesítésTulajdonságVáltozásról.cs

public class ÉrtesítésTulajdonságVáltozásról : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void TulajdonságVáltozott([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
Ez tartalmaz egy kötelező PropertyChanged eseményt, amit egy metódusból TulajdonságVáltozott hívunk meg. Erre a metódusra még visszatérek.

Nézzük a feladat végét, fájl adatainak mentése fájlba. Ezt csak kommenttel fogom jelölni, hol tudod elmenteni, de itt a példában egy UserControl lesz a tanulás kedvéért.
Szükség van egy modellre, legyen a neve Fájl modell, amit az ÉrtesítésTulajdonságVáltozásról osztályból származtatunk. Ez egy tulajdonságot tartalmaz, a neve Név. Ezt bővítheted, ezt fogod elmenteni. Itt láthatsz egy furcsságot, a setter miután beállította az értéket meghívja az ÉrtesítésTulajdonságVáltozásról ősosztály TulajdonságVáltozott metódusát. Ez jelszi a felhasználói felületnek, hogy frissítenie kell. Tartalmaz még egy felülírást, a ToString metódust, ami a fájl nevét adja vissza

Fájl.cs

public class Fájl : ÉrtesítésTulajdonságVáltozásról { string _név; public string Név { get => _név; set { _név = value; TulajdonságVáltozott(); } } public override string ToString() => _név; }
Ehhez tartozik a fent említett UserControl, ami a fájl adatait hivatott megjeleníteni, Ennek a neve legyen FájlAdatai.xaml(.cs). A XAML-ban beállítjuk a DataContext-et, hogy a fájl modellt vegye. Itt jelzed a XAML-nak hogy mostantól a Fájl modell amivel dolgozni fog. Van még itt Label és TextBox, ahol a TextBox Text attribútumnak beállítjuk hogy a Fájl modell Név tulajdonságát jelenítse meg. Text="{Binding Név}" Itt van az adatkötés.
A FájlAdatai.xaml.cs fájl nem tartalmaz semmi extrát az alapon kívül.

FájlAdatai.xaml

<UserControl x:Class="WpfApp1.FájlAdatai" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp1"> <UserControl.DataContext> <local:Fájl/> </UserControl.DataContext> <StackPanel Orientation="Vertical"> <Label VerticalAlignment="Top">Fájl neve</Label> <TextBlock Text="{Binding Név}" VerticalAlignment="Top"/> </StackPanel> </UserControl>

FájlAdatai.xaml.cs

public partial class FájlAdatai : UserControl { public FájlAdatai() { InitializeComponent(); } }
Most hogy van fájl adati, a következő feladat hogy rákattints egy lista elemére. Ez is egy UserControl lesz, amiben lesz egy iciri piciri varázslat. Készítsünk egy modellt, aminek a neve legyen FájlGyűjtemény ami egy lista lesz és a lista elemei pedig a Fájl. Fontos megjegyezni, hogy a listákat mindig olyan osztályból kell származtatni, ami értesíti a felhasználói felületet, ha változás történik, ezért most a FájlGyűjtemény modellt az ObservableCollection osztályból származtatjuk.

FájlGyűjtemény.cs

public class FájlGyűjtemény : ObservableCollection<Fájl> { }
Most jöhet a UserControl, a neve pedig FájlLista.xaml(.cs). A XAML első beállítása itt is a DataContext, ezzel jelezzük a fájl listának melyik modellből dolgozzon, jelen esetben a FájlGyűjtemény modellből. A következő fontos element, a ListView, ahol az ItemSource forrása a FájlGyűjtemény ezt így állítható be ItemsSource="{Binding .}" ahol a (pont) maga a DataContext, egy ObservableCollection<Fájl>, azaz FájlGyűjtemény.

FájlLista.xaml

<UserControl x:Class="WpfApp1.FájlLista" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp1"> <UserControl.DataContext> <local:FájlGyűjtemény/> </UserControl.DataContext> <StackPanel VerticalAlignment="Top"> <TextBlock>Fájlok</TextBlock> <ListView ItemsSource="{Binding .}" SelectionChanged="Kiválasztottam_A_Fájlt"> <ListView.View> <GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Fájl"> <GridViewColumn DisplayMemberBinding="{Binding Path=Név}" Header="Név" Width="100"/> </GridView> </ListView.View> </ListView> </StackPanel> </UserControl>
A ListView SelectionChanged egy esemény ami a  FájlLista.xaml.cs metódusa, ami egy sort tartalmaz, KiválasztottFájl = (Fájl)(sender as ListBox).SelectedItem; A KiválasztottFájl az ici pici varázslat amit említettem. Ez egy olyan tulajdonság, amit a későbbiek során használni fogunk. Ez egy DependencyProperty, amit XAML element-ként használunk később, és Fájl modell a tartalma.

public partial class FájlLista : UserControl { public static readonly DependencyProperty KiválasztottFájlTulajdonság = DependencyProperty.Register(nameof(KiválasztottFájl), typeof(Fájl), typeof(FájlLista)); public Fájl KiválasztottFájl { get => (Fájl)GetValue(KiválasztottFájlTulajdonság); set => SetValue(KiválasztottFájlTulajdonság, value); } public FájlLista() { InitializeComponent(); } private void Kiválasztottam_A_Fájlt(object sender, SelectionChangedEventArgs e) { // Itt tárolhatod fájlban az adatokat KiválasztottFájl = (Fájl)(sender as ListBox).SelectedItem; } }
Van fájl adatai (UserControl), van fájl lista (UserControl), ezekkel kezdhetünk már valamit. Szükség van itt is egy modellre, FájlListaSzűrő amit az ÉrtesítésTulajdonságVáltozásról osztályból származtatunk. Két tulajdonságot tartalmaz, amit Neked kell majd kibővíteni, FájlNévSzűrő1 ebbe kerül a felületen az a szám amit keresni akarsz, és FájlGyűjtemény amibe a szűrt fájlok listája kerül.  

Ehhez a modellhez készítsünk egy oldalt (Page). Legyen a neve FájlListaSzűrőOldal.xaml(.cs). Szokásos fontos DataContext beállítás, jelen esetben FájlListaSzűrő modell

Ebben van egy TextBox Text="{Binding FájlNévSzűrő1}", ez a beállított DataContext FájlListaSzűrő modell FájlNévSzűrő1 tulajdonságára mutat, ez tartalmazza pl „*.dll” vagy mármilyen szűrést.

FájlListaSzűrőOldal.xaml

<Page x:Class="WpfApp1.FájlListaSzűrőOldal" 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:WpfApp1" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" Title="Fájl Lista Szűrő"> <Page.DataContext> <local:FájlListaSzűrő/> </Page.DataContext> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*" /> <ColumnDefinition Width="1*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="1*" /> <RowDefinition Height="5*" /> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal" VerticalAlignment="Top"> <TextBox Text="{Binding FájlNévSzűrő1}" Width="200" /> <Button Content="Szűrés" Click="Szűrésre_Kattintás" /> </StackPanel> <local:FájlLista Grid.Row="1" Grid.Column="0" DataContext="{Binding FájlGyűjtemény}" x:Name="Fájlok" /> <local:FájlAdatai Grid.Row="1" Grid.Column="1" DataContext="{Binding ElementName=Fájlok, Path=KiválasztottFájl}" /> </Grid> </Page>
Tartalmazza a FájlLista UserControl-t, aminek megadjuk hogy a DataContext="{Binding FájlGyűjtemény}" ez a beállított DataContext FájlListaSzűrő modell FájlGyűjtemény tulajdonságára mutat.
Majd ici pici varázslat, van még a FájlAdatai UserControl, ami viszont a FájlLista UserControl KiválasztottFájl DependencyProperty-re mutat. DataContext="{Binding ElementName=Fájlok, Path=KiválasztottFájl}". ahol az ElementName=Fájlok a FájlLista neve <FájlLista … x:Name="Fájlok" /> a Path pedig a KiválasztottFájl DependencyProperty.

Van itt egy  <Button … Click="Szűrésre_Kattintás" /> ami tartalmaz egy újabb varázslatot, kiterjesztést, csak az átláthatóság kedvéért.  A System.IO.Directory.GetFiles amit használunk, egy tömböt ad vissza, viszont a FájlLista UserControl DataContext egy ObservableCollection<Fájl>, azaz FájlGyűjtemény. Ehhez van itt egy kiterjesztés ami tömböt alakít át fájl gyűjteménnyé. Kattintásnál így jól olvasható mi történik

FájlListaSzűrő.FájlGyűjtemény = System.IO.Directory.GetFiles(".", FájlListaSzűrő.FájlNévSzűrő1).KészítsFájlGyűjteményt();



FájlListaSzűrőOldal.xaml.cs

public partial class FájlListaSzűrőOldal : Page { public FájlListaSzűrő FájlListaSzűrő => (FájlListaSzűrő)DataContext; public FájlListaSzűrőOldal() { InitializeComponent(); } private void Szűrésre_Kattintás(object sender, RoutedEventArgs e) { if (string.IsNullOrEmpty(FájlListaSzűrő.FájlNévSzűrő1)) FájlListaSzűrő.FájlNévSzűrő1 = "*"; FájlListaSzűrő.FájlGyűjtemény = System.IO.Directory.GetFiles(".", FájlListaSzűrő.FájlNévSzűrő1).KészítsFájlGyűjteményt(); } }

TömbKiterjesztés.cs

public static class TömbKiterjesztés { public static FájlGyűjtemény KészítsFájlGyűjteményt(this Array tömb) { var válasz = new FájlGyűjtemény(); foreach (var item in tömb) { válasz.Add(new Fájl { Név = (string)item }); } return válasz; } }
A MainWindow.xaml-ba pedig csak bele kell rakni a FájlListaSzűrőOldal-t, és szűr, kattint megjelenik.

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow" 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:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <local:FájlListaSzűrőOldal/> </Window>
Mutasd a teljes hozzászólást!
Csatolt állomány

  • Szia!

    Miért tartod fontosnak egy harmadik, közvetítő osztály használatát? Miért nem példányosítod a két service-t a viewmodelben? Ebben az esetben a gombokhoz tartozó command a viewmodelben indítja a fájlkeresést és a kiírást.
    Mutasd a teljes hozzászólást!
  • Bocs, lehet, hogy félreérthető voltam. A harmadik osztály a ViewModel. Tehát nincs közvetítő.
    Szóval a ViewModel felelne az osztályok közötti kommunikációért és a megjelenítésért mint model? Itt valósulna meg a működési logika egy része is, ami az osztályok együttműködését illeti?
    A ViewModelt kellene példányosítani a MainWindow datacontextjeként?
    Mutasd a teljes hozzászólást!
  • Feltételezve, hogy mást nem csinál a programod, én 1db view-viewmodel-t használnék: MainWindow - MainViewModel. Több ablak vagy usercontrol esetén persze ez változik. A te esetedben a MainViewModel lenne a MainWindow datacontext-je. A MainViewModel-ben példányosítanád a két service osztályt. Amikor a view-n változik az adott textbox értéke, az adatkötésnek köszönhetően ez a viewmodel propertyben is megjelenik (OnPropertyChanged). Ha a gombra kattintasz az triggerel egy commandot, aminek hatására lefut a megadott metódusod. Mivel a metódus szintén a ViewModelben van, ezért látja a textboxokhoz bindolt propertyk értékét és át tudja adni őket paraméterként a service metódusnak. A metódus visszatérési értékét így el tudod tárolni a listboxhoz kötött propertyben, ami az adatkötés miatt szintén változást eredményez a view-n, és így tovább.
    Mutasd a teljes hozzászólást!
  • Ha a gombra kattintasz az triggerel egy commandot

    Ezen a ponton nem tiszta még.
    A view gombjának click eseményére történik a ViewModelben a kívánt metódus lefuttatása? Vagy ez a "triggerel egy commandot" ennél bonyolultabb megoldás?

    Ha nem túl nagy kérés, ennek a kódrészletét leírnád nekem?
    Mutasd a teljes hozzászólást!
  • Nagyjából ezt látom itt: wpf-icommand-in-mvvm ?
    Mutasd a teljes hozzászólást!
  • Az eventeket a code behindban tudod lekezelni. Viszont ha az MVVM mintát tartani szeretnéd akkor használhatsz Commandot pl így:

    <Button Command="{Binding NewProjectCommand}" ToolTip="New project"> New project </Button>
    A viewmodelben lesz egy propertyd, aminek a típusa implementálja az ICommand interfészt:

    public RelayCommand NewProjectCommand { get; set; }
    A konstruktorban inicializálod:

    NewProjectCommand = new RelayCommand(o => NewProject());
    A NewProject method lesz az ami a gomb megnyomásakor lefut.

    ICommand implementáció:

    public class RelayCommand : ICommand { public event EventHandler CanExecuteChanged; private readonly Action<object> _execute; private readonly Func<object, bool> _canExecute; public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null) { _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } public void RaiseCanExecuteChanged() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } }
    Mutasd a teljes hozzászólást!
  • Ennyi olvasás után sem egyértelmű, az azt jelenti, hogy nem érted a XAML és az adatkötés lényegét. De ez nem baj, mert nem egyszerű, miközben mégis az.

    Az Binding alapja, hogy minden, ami a felhasználói felületen történik, azt ezzel az interface-el kell kezdeni: INotifyPropertyChanged

    Ezért szükséged van egy ősmodellre. Ezt nevezzük ÉrtesítésTulajdonságVáltozásról osztálynak, amit az INotifyPropertyChanged iterfész imlementálása

    ÉrtesítésTulajdonságVáltozásról.cs

    public class ÉrtesítésTulajdonságVáltozásról : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void TulajdonságVáltozott([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
    Ez tartalmaz egy kötelező PropertyChanged eseményt, amit egy metódusból TulajdonságVáltozott hívunk meg. Erre a metódusra még visszatérek.

    Nézzük a feladat végét, fájl adatainak mentése fájlba. Ezt csak kommenttel fogom jelölni, hol tudod elmenteni, de itt a példában egy UserControl lesz a tanulás kedvéért.
    Szükség van egy modellre, legyen a neve Fájl modell, amit az ÉrtesítésTulajdonságVáltozásról osztályból származtatunk. Ez egy tulajdonságot tartalmaz, a neve Név. Ezt bővítheted, ezt fogod elmenteni. Itt láthatsz egy furcsságot, a setter miután beállította az értéket meghívja az ÉrtesítésTulajdonságVáltozásról ősosztály TulajdonságVáltozott metódusát. Ez jelszi a felhasználói felületnek, hogy frissítenie kell. Tartalmaz még egy felülírást, a ToString metódust, ami a fájl nevét adja vissza

    Fájl.cs

    public class Fájl : ÉrtesítésTulajdonságVáltozásról { string _név; public string Név { get => _név; set { _név = value; TulajdonságVáltozott(); } } public override string ToString() => _név; }
    Ehhez tartozik a fent említett UserControl, ami a fájl adatait hivatott megjeleníteni, Ennek a neve legyen FájlAdatai.xaml(.cs). A XAML-ban beállítjuk a DataContext-et, hogy a fájl modellt vegye. Itt jelzed a XAML-nak hogy mostantól a Fájl modell amivel dolgozni fog. Van még itt Label és TextBox, ahol a TextBox Text attribútumnak beállítjuk hogy a Fájl modell Név tulajdonságát jelenítse meg. Text="{Binding Név}" Itt van az adatkötés.
    A FájlAdatai.xaml.cs fájl nem tartalmaz semmi extrát az alapon kívül.

    FájlAdatai.xaml

    <UserControl x:Class="WpfApp1.FájlAdatai" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp1"> <UserControl.DataContext> <local:Fájl/> </UserControl.DataContext> <StackPanel Orientation="Vertical"> <Label VerticalAlignment="Top">Fájl neve</Label> <TextBlock Text="{Binding Név}" VerticalAlignment="Top"/> </StackPanel> </UserControl>

    FájlAdatai.xaml.cs

    public partial class FájlAdatai : UserControl { public FájlAdatai() { InitializeComponent(); } }
    Most hogy van fájl adati, a következő feladat hogy rákattints egy lista elemére. Ez is egy UserControl lesz, amiben lesz egy iciri piciri varázslat. Készítsünk egy modellt, aminek a neve legyen FájlGyűjtemény ami egy lista lesz és a lista elemei pedig a Fájl. Fontos megjegyezni, hogy a listákat mindig olyan osztályból kell származtatni, ami értesíti a felhasználói felületet, ha változás történik, ezért most a FájlGyűjtemény modellt az ObservableCollection osztályból származtatjuk.

    FájlGyűjtemény.cs

    public class FájlGyűjtemény : ObservableCollection<Fájl> { }
    Most jöhet a UserControl, a neve pedig FájlLista.xaml(.cs). A XAML első beállítása itt is a DataContext, ezzel jelezzük a fájl listának melyik modellből dolgozzon, jelen esetben a FájlGyűjtemény modellből. A következő fontos element, a ListView, ahol az ItemSource forrása a FájlGyűjtemény ezt így állítható be ItemsSource="{Binding .}" ahol a (pont) maga a DataContext, egy ObservableCollection<Fájl>, azaz FájlGyűjtemény.

    FájlLista.xaml

    <UserControl x:Class="WpfApp1.FájlLista" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp1"> <UserControl.DataContext> <local:FájlGyűjtemény/> </UserControl.DataContext> <StackPanel VerticalAlignment="Top"> <TextBlock>Fájlok</TextBlock> <ListView ItemsSource="{Binding .}" SelectionChanged="Kiválasztottam_A_Fájlt"> <ListView.View> <GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Fájl"> <GridViewColumn DisplayMemberBinding="{Binding Path=Név}" Header="Név" Width="100"/> </GridView> </ListView.View> </ListView> </StackPanel> </UserControl>
    A ListView SelectionChanged egy esemény ami a  FájlLista.xaml.cs metódusa, ami egy sort tartalmaz, KiválasztottFájl = (Fájl)(sender as ListBox).SelectedItem; A KiválasztottFájl az ici pici varázslat amit említettem. Ez egy olyan tulajdonság, amit a későbbiek során használni fogunk. Ez egy DependencyProperty, amit XAML element-ként használunk később, és Fájl modell a tartalma.

    public partial class FájlLista : UserControl { public static readonly DependencyProperty KiválasztottFájlTulajdonság = DependencyProperty.Register(nameof(KiválasztottFájl), typeof(Fájl), typeof(FájlLista)); public Fájl KiválasztottFájl { get => (Fájl)GetValue(KiválasztottFájlTulajdonság); set => SetValue(KiválasztottFájlTulajdonság, value); } public FájlLista() { InitializeComponent(); } private void Kiválasztottam_A_Fájlt(object sender, SelectionChangedEventArgs e) { // Itt tárolhatod fájlban az adatokat KiválasztottFájl = (Fájl)(sender as ListBox).SelectedItem; } }
    Van fájl adatai (UserControl), van fájl lista (UserControl), ezekkel kezdhetünk már valamit. Szükség van itt is egy modellre, FájlListaSzűrő amit az ÉrtesítésTulajdonságVáltozásról osztályból származtatunk. Két tulajdonságot tartalmaz, amit Neked kell majd kibővíteni, FájlNévSzűrő1 ebbe kerül a felületen az a szám amit keresni akarsz, és FájlGyűjtemény amibe a szűrt fájlok listája kerül.  

    Ehhez a modellhez készítsünk egy oldalt (Page). Legyen a neve FájlListaSzűrőOldal.xaml(.cs). Szokásos fontos DataContext beállítás, jelen esetben FájlListaSzűrő modell

    Ebben van egy TextBox Text="{Binding FájlNévSzűrő1}", ez a beállított DataContext FájlListaSzűrő modell FájlNévSzűrő1 tulajdonságára mutat, ez tartalmazza pl „*.dll” vagy mármilyen szűrést.

    FájlListaSzűrőOldal.xaml

    <Page x:Class="WpfApp1.FájlListaSzűrőOldal" 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:WpfApp1" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" Title="Fájl Lista Szűrő"> <Page.DataContext> <local:FájlListaSzűrő/> </Page.DataContext> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*" /> <ColumnDefinition Width="1*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="1*" /> <RowDefinition Height="5*" /> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal" VerticalAlignment="Top"> <TextBox Text="{Binding FájlNévSzűrő1}" Width="200" /> <Button Content="Szűrés" Click="Szűrésre_Kattintás" /> </StackPanel> <local:FájlLista Grid.Row="1" Grid.Column="0" DataContext="{Binding FájlGyűjtemény}" x:Name="Fájlok" /> <local:FájlAdatai Grid.Row="1" Grid.Column="1" DataContext="{Binding ElementName=Fájlok, Path=KiválasztottFájl}" /> </Grid> </Page>
    Tartalmazza a FájlLista UserControl-t, aminek megadjuk hogy a DataContext="{Binding FájlGyűjtemény}" ez a beállított DataContext FájlListaSzűrő modell FájlGyűjtemény tulajdonságára mutat.
    Majd ici pici varázslat, van még a FájlAdatai UserControl, ami viszont a FájlLista UserControl KiválasztottFájl DependencyProperty-re mutat. DataContext="{Binding ElementName=Fájlok, Path=KiválasztottFájl}". ahol az ElementName=Fájlok a FájlLista neve <FájlLista … x:Name="Fájlok" /> a Path pedig a KiválasztottFájl DependencyProperty.

    Van itt egy  <Button … Click="Szűrésre_Kattintás" /> ami tartalmaz egy újabb varázslatot, kiterjesztést, csak az átláthatóság kedvéért.  A System.IO.Directory.GetFiles amit használunk, egy tömböt ad vissza, viszont a FájlLista UserControl DataContext egy ObservableCollection<Fájl>, azaz FájlGyűjtemény. Ehhez van itt egy kiterjesztés ami tömböt alakít át fájl gyűjteménnyé. Kattintásnál így jól olvasható mi történik

    FájlListaSzűrő.FájlGyűjtemény = System.IO.Directory.GetFiles(".", FájlListaSzűrő.FájlNévSzűrő1).KészítsFájlGyűjteményt();



    FájlListaSzűrőOldal.xaml.cs

    public partial class FájlListaSzűrőOldal : Page { public FájlListaSzűrő FájlListaSzűrő => (FájlListaSzűrő)DataContext; public FájlListaSzűrőOldal() { InitializeComponent(); } private void Szűrésre_Kattintás(object sender, RoutedEventArgs e) { if (string.IsNullOrEmpty(FájlListaSzűrő.FájlNévSzűrő1)) FájlListaSzűrő.FájlNévSzűrő1 = "*"; FájlListaSzűrő.FájlGyűjtemény = System.IO.Directory.GetFiles(".", FájlListaSzűrő.FájlNévSzűrő1).KészítsFájlGyűjteményt(); } }

    TömbKiterjesztés.cs

    public static class TömbKiterjesztés { public static FájlGyűjtemény KészítsFájlGyűjteményt(this Array tömb) { var válasz = new FájlGyűjtemény(); foreach (var item in tömb) { válasz.Add(new Fájl { Név = (string)item }); } return válasz; } }
    A MainWindow.xaml-ba pedig csak bele kell rakni a FájlListaSzűrőOldal-t, és szűr, kattint megjelenik.

    MainWindow.xaml

    <Window x:Class="WpfApp1.MainWindow" 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:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <local:FájlListaSzűrőOldal/> </Window>
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Köszönöm mindkettőtöknek!
    Igyekszem megérteni a leírtakat, és próbálgatom a kódjaitokat.

    Lehet, hogy lesz még kérdésem. Megoldás elfogadásáig addig türelmeteket kérem.
    Mutasd a teljes hozzászólást!
  • Mi volt ez? szintfelmérő? lemaradt a licenc. Prog.hu tanuló licenc. Üzleti célra a prog.hu-nak átutalás 20% a bevételből, amit a prog.hu a gyerekekre fordít.
    Mutasd a teljes hozzászólást!
  • Dehogy! Csak időm nagy részét gyerekekre fordítom. Ezért nem biztos, hogy egy héten belül érdemben tudok foglalkozni a leírtakkal. Nem akartam, hogy úgy tűnjön: dolgoztatok egy csomót én meg elolvasom és lelépek szó nélkül.

    Ez az a könyv, amit olvasok. Egyébként leírásod máris jobban megvilágította a UserControl lényegét. Az értesítés tulajdonságváltozásról már világos.
    Mutasd a teljes hozzászólást!
  • Ajánlom figyelmedbe WPF resource témák mintámat is
    Mutasd a teljes hozzászólást!
  • Szeretnék mutatni Neked egy technikát, ami sokkal átláthatóbbá teszi a alkalmazást. Bármit is akarsz készíteni, a "Hello World!" appon kívül, fel fog merülni egy kérdés, hogyan kommunikálhatnak egymás között a UserControl-ok. Ez az előző példában a DependencyProperty volt, ami a kiválasztott fájlt megjelenítette egy másik UserControl-ban. Ez szép, és jól működik, de van egy módszer, amivel egyszerűbbé válik a kommunikáció a UserControl-ok között. Ez a módszer bármilyen osztály között lehetővé teszi, hogy bármilyen, szó szerint bármilyen osztályt vagy adattípust elküldhetsz az egyik helyről a másikra.

    Ha a keresést választod, vadabbnál vadabb elméletekkel fogsz találkozni.

    Talán nem ismeretlen számodra a Xamarin.Forms, vagy az új változata a Microsoft.Maui. Utóbbira fogok hivatkozni. A Maui-ban van egy osztály, amit úgy hívnak hogy MessagingCenter.

    A MessagingCenter lehetőséget biztosít arra, példában egy UserControl-ban, hogy feliratkozz bármilyen általános adattípusra C# Generic Type.  A másik UserControl pedig adatváltozás esetén a MessagingCenter-rel képes elküldeni a megváltozott adatot.

    A minta projekt tartalmazza a MessagingCenter.cs osztályt, ami módosítás nélkül használható. Letöltöd és bármelyik projektedhez hozzáadhatod. Ez a minta ugyan azt csinálja, mint az előző, csak a MessagingCenter osztályt használja adatcserére.

    A minta három UserControl-t tartalmaz, amik kommunikálnak egymással. A feliratkozáshoz a Loaded eseményt használom, amit a konstruktorban inicializálok. Mindhárom UserControl feliratkozik változásra, csak hogy lásd, több helyen is használható.

    Feliratkozás

    FájlAdatai.xaml UserControl feliratkozik a FájlLista.xaml UserControl üzenet fogadására, és amikor üzenet jön beállítja a modellt.

    MessagingCenter.Subscribe<FájlLista, FájlAdataiModell>(this, "fájl_adatai_modell_módosult", (fájlLista, fájl) => { FájlSzűrőModell.Fájl = fájl; });

    FájlLista.xaml UserControl feliratkozik a FájlSzűrő.xaml UserControl üzenet fogadására, és amikor üzenet jön beállítja a modellt.

    MessagingCenter.Subscribe<FájlSzűrő, FájlListaModell>(this, "fájl_lista_modell_módosult", (fájlSzűrő, fájlListaModell) => { FájlListaModell = fájlListaModell; });

    FájlSzűrő.xaml UserControl feliratkozik a FájlLista.xaml UserControl üzenet fogadására, és amikor üzenet jön beállítja a modellt.

    MessagingCenter.Subscribe<FájlLista, FájlAdataiModell>(this, "fájl_adatai_modell_módosult", (fájlLista, fájl) => { FájlSzűrőModell.Fájl = fájl; });

    Küldés

    FájlSzűrő.xaml UserControl szűrés után elküldi a FájlListaModell-t a MessagingCenter-rel.

    MessagingCenter.Send(this, "fájl_lista_modell_módosult", System.IO.Directory.GetFiles(".", FájlSzűrőModell.FájlNévSzűrő1).KészítsFájlGyűjteményt());

    FájlLista.xaml UserControl fájl név kiválasztásnál elküldi a FájlAdataiModell-t a MessagingCenter-rel.

    MessagingCenter.Send(this, "fájl_adatai_modell_módosult", (FájlAdataiModell)(sender as ListBox).SelectedItem);

    Nincs szükség arra, hogy összekapcsold UI szinten az alkalmazást. A küldés és feliratkozás mutatja, a küldő UserControl is közlekedik, így azokon is tudsz változtatni, ha szeretnél. De bármit küldhetsz, többet is, végtelen helyre.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Köszönöm! Megnéztem ezt is.
    Nem tudom, jól értem-e: amennyi modell osztályunk van, annyi UserControlt használunk, és (egy egy ablakos megoldásnál) a MainWindowba mint héjba töltjük bele ezeket? Így minden nézet elemnek a hozzá tartozó modell osztály a DataContextje?
    Mutasd a teljes hozzászólást!
  • Szia, igen. A DataContext a FrameworkElement property-je, minden osztály ami ebből származik, arra igen így van.
    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