Wpf Quickstart kezdőknek

Wpf Quickstart kezdőknek
2013-03-28T13:28:18+01:00
2013-05-10T14:24:55+02:00
2022-10-23T19:10:31+02:00


  • Igazából csak ennyit szerettem volna.
    De ha már így feldobtad a labdát ám legyen :)
    Mutasd a teljes hozzászólást!
  • Szerintem ugyanarról beszéltek. a VM-ben történő adatmódosítás a controltemplate-ben lehet datatrigger és bindelhetsz.
    Mutasd a teljes hozzászólást!
  • Ennyi fért bele fél órába
    Elég sok mindenről lehetne írni.
    Remélhetőleg sokaknak segít átlépni azon a ponton, hogy a WPF-et ne csak deklaratív Winform-nak használják.

    De legyen, szép apránként.

    A továbbiakat csak akkor olvasd, ha a topic nyitó részét már érted.

    4. Command alap szintent.
    Hála a WPF szerkezetének az Event-eken keresztül történő kommunikáció jó része már a múlté. Természetesen a Command nem helyettesít minden eseményt, de használata lényegesen egyszerűbbé és szebbé teszi a kódot.
    Az alábbi minta az egyszerűségre törekszik. Ha elolvasod és érted a lényegét, akkor a neten számtalan leírást és példát találsz rá.

    A 3. pontban leírt gyűjtemény kerül kiegészítésre. Az oldal tetejére jerül egy gomb, aminek megnynomására a gyűjtemény végéhez hozzáadunk egy új int-et (jelen eseten a 100-as számot)
    A Commandhoz létre kell hozni egy új osztályt
    using System; using System.Windows.Input; namespace WpfApplication1 { class Command : ICommand { private readonly Action _executeMethod; public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public Command(Action action) { _executeMethod = action; } public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { _executeMethod.Invoke(); } } }

    A fenti kódban az ICommand által megkövetelt metódusok láthatók

    Kiemelve az egyes részeket
    Konstruktor paraméterként átadásra kerül egy metodus, amia gomb megnyomásakor meghívásra kerül.
    Ezt tároljuk: private readonly Action _executeMethod;

    public bool CanExecute(object parameter)
    Ez a metódus dönti el, hogy az adott Command lefuttatható-e
    Írd át False értékre.Látható, hogy a Button inaktív állapotba kerül

    public void Execute(object parameter)
    Lefuttatja a Command-nak átadott metódust


    A ViewModel az alábbiak szerint változik
    using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows.Input; namespace WpfApplication1 { public class ViewModel :INotifyPropertyChanged { private ObservableCollection<Model> _myModelCollection; public ObservableCollection<Model> MyModelCollection { get { return _myModelCollection; } set { _myModelCollection = value; OnPropertyChanged("MyModelCollection"); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } private ICommand _incrementcommand; public ICommand Incrementcommand { get { return _incrementcommand; } set { _incrementcommand = value; OnPropertyChanged("Incrementcommand"); } } public ViewModel() { MyModelCollection= new ObservableCollection<Model>(); for (int i = 0; i < 10; i++) { MyModelCollection.Add(new Model(i)); } Incrementcommand = new Command(AddNewItemToCollection); } private void AddNewItemToCollection() { MyModelCollection.Add(new Model(100)); } } }

    A Command deklarálása semmi újdonságot nem tartalmaz
    private ICommand _incrementcommand; public ICommand Incrementcommand { get { return _incrementcommand; } set { _incrementcommand = value; OnPropertyChanged("Incrementcommand"); } }

    A konstruktorban példányosításra kerül, paraméterként pedig a futtatandó metódus neve van átadva
    Incrementcommand = new Command(AddNewItemToCollection);

    A metódus, ami minden gombnyomásra lefuttatásra kerül hozzáad a listához egy új Modelt a 100-as értékkel:
    private void AddNewItemToCollection() { MyModelCollection.Add(new Model(100)); }


    A View XAML-be bekerül egy új button
    <Grid> <Grid.Resources> <DataTemplate x:Key="MyListTemplate" > <TextBlock Text="{Binding TextValue}" Height="15"/> </DataTemplate> </Grid.Resources> <ListBox Height="150" ItemsSource="{Binding MyModelCollection}" ItemTemplate="{StaticResource MyListTemplate}"> </ListBox> <Button VerticalAlignment="Top" Width="100" Height="20" Content="Add new item" Command="{Binding Incrementcommand}"/> </Grid>

    A button Command része a lényeg. A button ezen az adatkapcsoláson keresztül tudja, hogy milyen metódust kell meghívnia
    Command="{Binding Incrementcommand}

    Mutasd a teljes hozzászólást!
  • A GUI módosítgatása (pl. visibled, enabled stb) nem kódból szokásos, hanem a hkapcsolódó GUI-t "jelentő" ViewModel adat (tudod, amit a DataContex-hez kötsz) módosításával


    Vagy inkább triggerekkel - bár ez feladatfüggő.
    Mutasd a teljes hozzászólást!
  • Klassz összefoglaló. Lassan jöhet a saját blog.


    Mutasd a teljes hozzászólást!
  • Tetszik-tetszik. :)

    Teljesség igénye nélkül megjegyeznék még pár hasznos dolgot:
    1. ApartmentState : STA többszálú alkalmazás esetén
    2. Dispatcher.Invoke
    3. Multibinding
    4. ICommand az eventek helyett
    5. Converterek használata
    6. IDataErrorInfo a notifypropertyk mellé, ha a Binding TwoWay
    Mutasd a teljes hozzászólást!
  • Jó összefoglaló.

    Annyit még hozzátennék, mint durva alapinfót, hogy a WinForm-ról érkezőknek még két terület érdekes, ami ott rendszeresen visszatérő kérdés:

    -- A GUI módosítgatása (pl. visibled, enabled stb) nem kódból szokásos, hanem a hkapcsolódó GUI-t "jelentő" ViewModel adat (tudod, amit a DataContex-hez kötsz) módosításával. Szóval tipikusan nem csak az adatok, hanem az adatokból származó "státus" is az adatokból jön közvetlenül.
    -- A több szálról a GUI módosítása sem a GUI-hoz hozzáféréssel történik, hanem az előzőből következően a GUI-t "jelentő" ViewModel adat módosításával. A GUI elemek meg majd követik az adatváltozást. Az adatok szálbiztos használata meg kellően kifinomult.

    Biztos jön még majd számos "frappáns" különbség, de remélem ez is hozzájárult a szemlélet kialakításához.
    Mutasd a teljes hozzászólást!
  • Helló

    Ezt a pár sor azért írtam, mert a tudástárban számos lelkes WPF kezdő található, akiknek még nem sikerült elmélyedni a BINDING útvesztőjében.
    Remélem ezt elolvasva nagyobb rálátást kapnak az adatkötésre, és számos problémájuk megoldódik, illetve más szemléletre tesznek szert.

    Ezen írás kifejezetten kezdőknek szól

    1. A legegyszerűbb adatkötés
    public partial class MainWindow : Window { public int TextValue { get; set; } public MainWindow() { TextValue = 5; InitializeComponent(); DataContext = this; } } <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <TextBox Width="100" Height="20" Text="{Binding TextValue}"/> </Grid> </Window>

    Ebben a kódban a következő fontos részeket kell kiemelni:
    - public int TextValue { get; set; }. A Wpf Property-ken keresztül kommunikál. Az nem elég, ha egy változódat publikussá teszed.
    - DataContext= this; A DataContext határozza meg, hogy a XAML kód honnan veszi az adatokat.
    - Text="{Binding TextValue}" -- Binding segítségével meghatározzuk, hogy a DataContextben beállított osztályból a TextValue property értékét szeretnénk megjeleníteni.

    Mint látható, teljesen mindegy, hogy a TextValue típusa string, double vagy akár DateTime. A Wpf elvégzi helyettünk a konvertálást.

    ****************************************************************************************************

    2. A datacontext más osztályba kerül

    hozzunk létre egy új osztályt és ennek függvényében változtassuk meg azt amit eddig csináltunk
    public class ViewModel :INotifyPropertyChanged { private int _textValue; public int TextValue { get { return _textValue; } set { _textValue = value; OnPropertyChanged("TextValue"); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public ViewModel() { TextValue = 25; } } public partial class MainWindow : Window { private ViewModel _viewModel; public MainWindow() { InitializeComponent(); _viewModel = new ViewModel(); DataContext = _viewModel; } }

    Az első és legfontosabb, hogy a WPF az adatokat mostantól a _viewModel példányból veszi (DataContext = _viewModel;)
    Közelebbről megnézve a ViewModel osztályt, kapott egy Interface öröklést: INotifyPropertyChanged
    Mindez azért kell, hogy amennyiben bármely általunk létrehozott property megváltozik, a WPF értesüljön róla.
    az interface használatához kell: using System.ComponentModel;
    Az Interface megköveteli az alábbi esemény elhelyezését az osztályban
    public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); }

    Az esemény önmagában még semmit se ér, muszáj meghívni is.
    private int _textValue; public int TextValue { get { return _textValue; } set { _textValue = value; OnPropertyChanged("TextValue"); } }

    Mint látható, a property set tagjában az értékadás után meghívjuk az eseményt. Fontos,hogy paraméterként a property neve kerüljön átadásra (jelen esetben:TextValue)

    ****************************************************************************************************

    3. Gyűjtemények

    Hozzunk létre egy új osztály, és helyezzük át oda a meglévő adat deklarációt

    public class Model : INotifyPropertyChanged { private int _textValue; public int TextValue { get { return _textValue; } set { _textValue = value; OnPropertyChanged("TextValue"); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public Model(int value) { TextValue = value; } }

    A model osztály tartalmaz minden adat deklarációt, az adat létrehozását, annak ellenőrzését, stb.

    A ViewModel osztály ennek ismeretében változik
    public class ViewModel :INotifyPropertyChanged { private ObservableCollection<Model> _myModelCollection; public ObservableCollection<Model> MyModelCollection { get { return _myModelCollection; } set { _myModelCollection = value; OnPropertyChanged("MyModelCollection"); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public ViewModel() { MyModelCollection= new ObservableCollection<Model>(); for (int i = 0; i < 10; i++) { MyModelCollection.Add(new Model(i)); } } }

    Mint látható a Model osztály csak a ViewModel osztállyal van kapcsolatban.
    A ViewModel-ben van egy referencia a Model-re.
    Ez jelen pillanatban egy gyűjtemény (ObservableCollection) amely Model típusú elemeket tartalmaz.
    A konstruktorban a gyűjtemény feltöltésre kerül.

    Legvégül a XAML kódot kell megváltoztanti (XAML kód == View)

    <Grid> <Grid.Resources> <DataTemplate x:Key="MyListTemplate" > <TextBlock Text="{Binding TextValue}" Height="15"/> </DataTemplate> </Grid.Resources> <ListBox Height="150" ItemsSource="{Binding MyModelCollection}" ItemTemplate="{StaticResource MyListTemplate}"> </ListBox> </Grid>

    A XAML DataContext-je jelen pillanatban a _viewModel;
    A ViewModel tartalmaz egy gyűjteményt: MyModelCollection. A listbox ebből szedi az adatokat (ItemsSource="{Binding MyModelCollection}")
    Mindez automatikusan megtörténik.

    A Listboxban található ItemTemplate leírja, hogy egy ListBox Item hogy nézzen ki. Jelenleg mindössze egy TextBlock-ot tartalmaz.
    A ListBox a MyModelCollection gyűjteményből szedi az adatai,ami Model típusú.
    A Model-nek van egy property-je:TextValue
    Ez látható a TextBlock Text attribútumához kapcsolva (<TextBlock Text="{Binding TextValue}" Height="15"/>)



    Remélem segített a kezdőlökést megadni.
    Ha valahol elakadtál írj ide, igyekezni fogok válaszolni.
    Mindezek után a google-ban nézz utána a Model-View-ViewModel pattern-nek
    Ha úgy érzed érted, itt egy link
    Olvasd el a kérdést. Nézd meg a megoldást. Gondolkozz el rajta, miként lehetne adatkötéssel megoldani, ami méltóbb a WPF-hez.

    Sok sikert.
    D.
    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