játékfejlesztés.hu
FórumGarázsprojectekCikkekSegédletekJf.hu versenyekKapcsolatokEgyebek
Legaktívabb fórumozók:
Asylum:    5455
FZoli:    4892
Kuz:    4455
gaborlabor:    4449
kicsy:    4304
TPG:    3402
monostoria:    3284
DMG:    3172
HomeGnome:    2919
Matzi:    2521

Pretender:    2498
szeki:    2440
Seeting:    2306
Geri:    2189
Orphy:    1893
Joga:    1791
Bacce:    1783
MaNiAc:    1735
ddbwo:    1625
syam:    1491
Korábbi postok
> 1 < [2] [3] [4] [5] [6] [7] [8] [9] [10] [15] [20] [25] [30] [35] [40] [45] [46]
itamas - Tag | 80 hsz       Online status #211633   2017.10.23 14:21 GMT+1 óra  
Igazad van, tényleg alaposabban át kell böngésznem a leírásokat, könyveket - az elejére is koncentrálva. Eddig csak azt kerestem bennük, hogy egy C# program szerkezete hogyan is épül fel, tehát hogy milyen változót hova írva benne milyen hatást érhetünk el, és mely rész mije a kódnak.
De köszönöm, hogy rávezettél a megoldásra: a lista létrehozását a public MainForm() fölé írtam és így már működött!
   
Instalok - Tag | 545 hsz       Online status #211632   2017.10.23 11:01 GMT+1 óra  
Így továbbra sem fog semmire sem menni. Ne a mostani problémádat akard megoldani a könyvvel, hanem tanuld meg az alapokat, mert láthatóan hiányoznak. Először szerintem próbáld megérteni, megtanulni az alapokat. Mi az hogy változó, osztály, milyen viszonyban állnak. Mi az a függvény, hogyan kell egyet készíteni és meghívni, mik azok, hogy visszatérési érték, paraméterek, stb. Ezek után jöhetnek az objektum-orientált dolgok, mint például öröklődés, példányosítás, dinamikus típuskonverzió (fú de utálom ezt magyarul leírni), stb-stb.

Konkrétan válaszolva:
Gondolj bele, hogy az "ujjatekos" változódat miért látod a többi helyen? Azért, mert class member, tehát nem függvényen belül lett deklarálva, hanem az osztályon belül. Tehát akkor mit kell tenni a játékosok listájával?

Fontos megtanulni, hogy mi a példány, egy adott osztályon, ha végzel valamilyen módosítást, akkor az az összes példányra, vagy csak egyre hat, stb. Rövid példa:
Kód:
class Valami
{
    // ezek látszanak az adott osztály nem-statikus függvényeiben
    int valtozo1;
    List<int> valtozo2;
    bool valtozo3;
   
    // a statikus változók nem példányhoz tartoznak, hanem minden példányhoz "közös"
    static float valtozo4;
   
    void Fuggveny1()
    {
        valtozo1 = 10;
        valtozo2 = new List<int>();
        valtozo3 = true;
       
        // nem statikus függvény módosíthatja a statikus változókat
        valtozo4 = 3.1415f;
    }
   
    static void Fuggveny2()
    {
        // statikus függvény nem módosíthatja a nem statikus változókat
        valtozo1 = 10; // hiba
        valtozo2 = new List<int>(); // hiba
        valtozo3 = true; // hiba
       
        valtozo4 = 3.1415f; // ok
    }
}

   
itamas - Tag | 80 hsz       Online status #211630   2017.10.22 15:23 GMT+1 óra  
C#-os e-könyvem van kettő is: az, amit belinkeltél és Illés Zoltán: Programozás C# nyelven c. könyve. Tegnap meg most ezeket böngésztem, de még nem tudtam kihámozni belőlük azt a logikát, hogy a MainForm() függvényen kívülre hogy lehet kivezetni a programot. Mert addig világos, hogy annak a konstruktorában hoztam létre a téglalapot, de hogy utána ezzel hol és mit kezdhetek, annál megállt a tudományom. GameMaker-en "edződött" agyam kicsit nehezen áll ennek a nyelvnek a logikájára; ott pl. olyan kényelmes volt instance_destroy()-ozni...
Szerk.:
De azért haladtam és már csak egy kérdésem maradt: hogy a következő kódban a jatekosok változó (vagy listaazonosító, vagy minek nevezzem) hol deklarálandó, hogy a Rajzol() függvény foreach ciklusa felismerje?
Kód:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace valami
{
public class jatekos
{
public int xhely;
public int yhely;
public int szel;
public int mag;
public jatekos()
{
szel=50;
mag=50;
}
}

public partial class MainForm : Form
{
jatekos ujjatekos;
public MainForm()
{
InitializeComponent();

List<jatekos> jatekosok=new List<jatekos>();
Random vsz=new Random();
for (int i=0;i<=9;i++)
{
jatekosok.Add(new jatekos() {xhely=vsz.Next(1,200),yhely=vsz.Next(1,200)});
}
Paint += new PaintEventHandler(Rajzol);
}

void Rajzol(object sender, PaintEventArgs e)
{
foreach (jatekos ujjatekos in jatekosok)
{
e.Graphics.FillRectangle(Brushes.BlueViolet,new Rectangle(ujjatekos.xhely,ujjatekos.yhely,ujjatekos.szel,ujjatekos.mag));
}
}
}

}

Ezt a hozzászólást itamas módosította (2017.10.22 17:17 GMT+1 óra, 50 nap)
   
Instalok - Tag | 545 hsz       Online status #211628   2017.10.21 18:09 GMT+1 óra  
Esetleg ez a könyv?
[url]https://devportal.hu/download/E-bookok/csharp%20jegyzet/C%23%20programozas%20lepesrol%20lepesre%20-%20Reiter%20Istvan%20(frissitett%20tartalommal%202012.10.15).pdf[/url]

   
itamas - Tag | 80 hsz       Online status #211626   2017.10.20 18:18 GMT+1 óra  
Hát igen, lehet, hogy amolyan "hűbeleBalázs" módon fogtam a C#-ozásba Egy könyvem van róla, Trey Nash: C# 2008 - Könnyen is lehet! című kötete, de ahogy lapozgattam, ez nem kezdőknek szól és elég száraz is, úgyhogy megpróbálok a világhálóról szemezgetni, tanulgatni, mert tényleg hiányosak az alapok.
   
Instalok - Tag | 545 hsz       Online status #211625   2017.10.20 18:10 GMT+1 óra  
Nem bántásból mondom, de szerintem fogj egy C# programozás könyvet, és előbb tanuld meg az alapokat, mert így sehova sem fogsz jutni.

Válaszolva a konkrét kérdéseidre:
- Egy osztályban definiálhatsz függvényeket is, amik "valamit csinálnak", ahogy azt a lenti példakódban is láthattad

A hibák:
- hiányzik a "new" a Rectangle elől
- az ujjatekos-t a MainForm konstruktorában hoztad létre, és az csak az adott függvényen belül létezik, a függvény végén meg is szűnik, ezért nem láthatod máshol. Legyen belőle class member, akkor minden (nem statikus) függvényben látni fogod.

Viszont így tényleg nem sokra fogsz menni, meg kell tanulnod az alapokat:
- változó (azok típusai)
- függvény
- osztály + interfész
- láthatóság
- öröklődés
- statikusság
- konstans
- stb.stb.

   
itamas - Tag | 80 hsz       Online status #211624   2017.10.20 18:03 GMT+1 óra  
Próbálkozok, próbálkozok, de egyvalamit nem értek és leírást sem találok róla sehol: addig rendben, hogy a public class-sal létrehozok egy osztályt mondjuk jatekos néven (ez rajzolná majd ki a téglalapot a maga helyére). Belül feltöltöm ezt adatokkal és létrehozom a változókat. Gondolom itt mást, pl. kirajzolást nem lehet csinálni(?).
Aztán a public MainForm()-ban esetleg még hozzárendelek ezen osztály változóihoz adatokat.
És innen jön nekem a titok, hogy ezen változókat hogyan használhatom fel máshol egy téglalap kirajzolásához. Itt a kódom:
Kód:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace valami
{
public class jatekos
{
public int xhely=10;
public int yhely=10;
public int szel;
public int mag;
}
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();

jatekos ujjatekos=new jatekos();
ujjatekos.szel=50;
ujjatekos.mag=50;
Paint += new PaintEventHandler(Rajzol);
KeyDown += new KeyEventHandler(gombnyomas);
}
void Rajzol(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(Brushes.BlueViolet,Rectangle(ujjatekos.xhely,ujjatekos.yhely,ujjatekos.szel,ujjatekos.mag));
}

void gombnyomas(object sender, KeyEventArgs e)
{
if (e.KeyCode==Keys.Enter)
{
ujjatekos.Dispose();
}
}
}
}

Erre azokat a hibákat írja ki, hogy "A(z) „System.Drawing.Rectangle” egy „típus” konstruktor, de „változó” konstruktorként használva. (CS011" meg hogy "Az "ujjatekos" név nem szerepel ebben a környezetben".
Hogyan lehet megjavítani a programomat?
És még arra vagyok kíváncsi, hogy a "sender" és az "e" paraméterek mit jelentenek a függvényekben? A C# teszi oda magától, de mire hivatkozik ezekkel?
   
itamas - Tag | 80 hsz       Online status #211623   2017.10.20 16:07 GMT+1 óra  
Valamikor mintha próbálkoztam volna a Visual Studioval is, de ha jól emlékszem, sokmindent kellett volna még telepítgetni mellé, meg akkor még nem is Windows10-em volt. Erre a SharpDevelop-ra Google kereséssel találtam rá és azért is tetszett, mert van telepítést nem igénylő változata (csak kitömöríted és kész). Ez is igényel .NET keretrendszert (gondolom a Visual Studionak is az kellett), de nem kéri futtatáskor, bizonyára már benne van a Win10-ben, én nem tudom.
A példakódot nagyon köszönöm; átnézem és próbálom értelmezni.
   
Instalok - Tag | 545 hsz       Online status #211622   2017.10.19 19:53 GMT+1 óra  
Van valami különösebb oka, hogy nem Visual Studiot használsz?

A C# egy managelt nyelv, tipikusan nem akarsz azzal foglalkozni, hogy mikor szabadul fel a memória, ezért általánosságban nem akarod a Dispose()-t sem meghívni. Simán tarts fent egy listát az élő objektumokról, azokon végigiterálsz (for/foreach), és kirajzolod.

Csináltam egy nagyon egyszerű, lebutított példakódot.

Kód:
interface IGraphicsDevice
{
    void DrawRectangle(Rectangle rect);
}

// az az osztály, ami ki tud rajzolni dolgokat
class GraphicsDevice : IGraphicsDevice
{
    public void DrawRectangle(Rectangle rect)
    {
        // ...
    }
}

interface IDrawable
{
    void Draw(IGraphicsDevice device);
}

// az az osztály, ami egy kirajzolandó téglalapot reprezentál
class DrawableRect : IDrawable
{
    Rectangle rect;

    public void Draw(IGraphicsDevice device)
    {
        device.DrawRectangle(rect);
    }
}

// az az osztály, ami egy objektumot reprezentál
// vannak komponensei, amik az adott működését biztosítják
class GameObject
{
    // komponensek...
    public IDrawable Drawable
    {
        get;
        set;
    }
   
    // ezt hívja meg a GameObjectManager - ha nincs drawable komponens megadva, akkor "nem csinál semmit"
    // ennél vannak szebb/jobb megoldások, de kis projektre jól működik
    public void Draw(IGraphicsDevice device)
    {       
        if (Drawable != null)
            Drawable.Draw(device);
    }
}

// végül az az osztály, ami az egészet karban tartja
class GameObjectManager
{
    IGraphicsDevice graphicsDevice;
   
    // az élő objektumok listája
    IList<GameObject> gameObjects;
   
    public GameObjectManager(IGraphicsDevice graphicsDevice)
    {
        this.graphicsDevice = graphicsDevice;
    }
   
    // új objektum elkészítése
    GameObject CreateGO()
    {
        var res = new GameObject();
        // hozzáadjuk az elő objektumok listájához
        gameObjects.Add(res);
        return res;
    }
   
    void DestroyGO(GameObject go)
    {
        // ez itt több sebből is vérzik:
        // 1) nem hívhatod ezt, ha éppen az adott listán iterálsz
        // 2) ha egy adott objektumra kétszer meghívod, akkor kétszer akarod a listából eltávolítani ugyan azt az elemet
       
        gameObjects.Remove(go);
       
        // jobb megoldás lehet, ha egy flaggel jelzed, hogy eltávolítani szeretnéd az objektumot
        // majd minden egyes update elején/végén a megjelölt elemeket kitörlöd a listából
        // ez megoldja mindkét fentebbi problémát, de az egyszerűség kedvéért most így csináltam
    }
   
    void Draw()
    {
        // kirajzoljuk az összes élő objektumot
        foreach (var next in gameObjects)
            next.Draw(graphicsDevice);
    }
}

   
itamas - Tag | 80 hsz       Online status #211621   2017.10.19 16:20 GMT+1 óra  
Igen, én is arra gondolok, hogy osztályként (class) kéne meghatározni a jatekos-t is, aminek a példánya kirajzolja a téglalapot és akkor erre az osztályra talán(?) használható a Dispose(). De egy általam létrehozott osztályban hogyan tudok kirajzolni valamit?
Meg ez a hülye SharpDevelop is tisztára meg van most bolondulva: megnyitom a programomat és egy teljesen más kód köszön vissza vagy meg sem jelenik a kódszerkesztő képernyő. Ezután egy teljesen újat kezdtem, beillesztettem a kódomat, mert megvolt máshol is, erre a téglalap irányítása teljesen összezavarodott lett (ha a jobbra nyilat nyomom balra megy, stb.), pedig nem változtattam rajta semmit. Valaki fenn nagyon nem akarja, hogy értsek a C#-hoz...
   
Parallax - Tag | 591 hsz       Online status #211619   2017.10.19 07:31 GMT+1 óra  
itamas: A .NET memória kezelése eléggé összetett.

Először is a Dispose arra való, hogyha az objektumhoz hozzátartozik unmanaged erőforrás, vagy olyan managed, ami tartalmaz unmaged erőforrást (és így tovább) akkor ezzel a metódussal direktben, mint C++ nál lehet ezt az unmanaged v hibrid elemet törölni.
Ha Dispose pattern-t használsz, akkor legkésőbb a "desktruktor", (ami amúgy C#-ban nincs is, de lényegét tekintve ahhoz hasonló véglegesítő hívás GC által pluszban) lefutásakor törölhetőek a kézzel törölni kívánt elemek.

Kód:
class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   
   // Public implementation of Dispose pattern callable by consumers.
   public void Dispose()
   {
      Dispose(true);
      GC.SuppressFinalize(this);           
   }
   
   // Protected implementation of Dispose pattern.
   protected virtual void Dispose(bool disposing)
   {
      if (disposed)
         return;
     
      if (disposing)
      {
         // Free any other managed objects here.
         //
      }
     
      // Free any unmanaged objects here.
      //
      disposed = true;
   }

   ~BaseClass()
   {
      Dispose(false);
   }
}


A jó hír, hogy neked ezzel most nem kell foglalkozni, mert managed objektumokat használsz, vagyis helyette az alábbiakat:
-ha struct-ot akarsz törölni, akkor minden olyan helyen, ahol van rá hivatkozás lecseréled egy másik üresre::
Kód:
teglalap = new Rectangle(0, 0, 0, 0);
//többi helyen is


-Ez gondolom nem megoldás, ezért inkább használj osztályt és azt "töröld" (ilyen nincs, csak megjelölheted törlésre *1), így elég ennyi:
Kód:
teglalap = null;
//többi helyen is


*1: A törlésre kijelölt elemek azonnali törlésére lehet a GC-t utasítani, de nem ajánlott bele avatkozni a működésébe direktben:
Kód:
GC.Collect();
GC.WaitForPendingFinalizers();


Röviden ennyi, ettől ez persze sokkal összetettebb.

   
Instalok - Tag | 545 hsz       Online status #211618   2017.10.19 07:02 GMT+1 óra  
Eleve például egy komponens alapú megoldás lenne a legjobb. Azt gondold végig, hogy mi a játékos?
- tudod irányítani (Input komponens)
- ki kell rajzolni valamit (Shape/Graphics/akármi komponens)
- tud ütközni (Collider komponens)
- stb.
Ilyen szempontból a játékos, a lövedék és az ellenfelek annyira nem is különböznek, csak más az Input komponensük. Tehát például kirajzoláskor a kirajzolást végző függvénynek mindegy, hogy éppen a játékost vagy valami mást rajzol.

Ezért jó lentről felfelé építkezni. Megcsinálod először azt az osztályt, ami ki tud rajzolni alakzatokat (ha nem akarsz mást, csak téglalapokat, akkor még könnyebb). Ezek után csinálod a fölé épülő rendszereket, például a SceneManager ami már "game object" szinten kezeli az objektumokat. Az, hogy egy ilyen "game object" (vagy Entity, akármi) hogyan épül fel, az már ennek (vagy még efölött álló rendszernek) a dolga. A rajzolásért felelős rendszernek ehhez semmi köze. Az csupán annyit tud, hogy alakzatokat/téglalapokat kirajzol.

   
Pixi - Tag | 206 hsz       Online status #211617   2017.10.19 01:18 GMT+1 óra  
Mi lenne akkor, ha a játékost meg a többi elemet is egy vagy több osztály írná le? Majd ezt az osztályt mikor példányosítod, egyből belepakolnád egy listába, majd ha törölni szeretnél valamit, akkor egész egyszerűen a lista egy adott indexű elemét törlöd csak. Ez működik abban az esetben is, ha csak egyetlen példányod van. Vagy csak azért így oldottad meg, mert most ismerkedsz a nyelvvel?

Mellesleg ha komolyabban szeretnél játékfejlesztéssel foglalkozni, akkor ajánlom a MonoGame framework -ot a továbbiakban.

   
Instalok - Tag | 545 hsz       Online status #211615   2017.10.18 17:13 GMT+1 óra  
Jobb megoldás lenne, ha például egységbe zárnád a dolgot, és például lenne egy Player osztályod, aminek van isAlive adattagja. Bár, ez sem a jó megoldás, de kis projekteknél megfelelő.

Amikor írsz fórumra egy olyan problémáról, amiben hibát kapsz, akkor javasolt a hibát is leírni. Egyébként, ha jól sejtem, akkor a Rectangle egy struct, ami viszont "érték típus", tehát nem lehet null. Gyanítom ez a hibaüzenet is, hogy null-ra szeretnél egy non-nullable dolgot állítani.

   
itamas - Tag | 80 hsz       Online status #211614   2017.10.18 16:48 GMT+1 óra  
Sziasztok!
Nemrég letöltöttem az ingyenes SharpDevelop fejlesztőkörnyezetet, hogy belekóstoljak a C# programozási nyelvbe én is. Kezdetnek valami egyszerű lövöldözős-féle "játékot" szeretnék csinálni vele, amiben a játékost egy nagyobbacska négyzet jelképezi és a többi kelléket (lövedékek, ellenségek) is kisebb-nagyobb síkidomok. Namármost a kirajzolás meg a mozgatás megvan, de az objektumok megsemmisítése még nem. Ezt hogyan kell? Utánaolvasva a Dispose() függvény a megoldás, de nem engedi a SharpDevelop sem azt, hogy a kirajzolt téglalap után tegyem a Dispose()-t, sem azt, hogy null értékkel tegyem egyenlővé és így a szemétgyűjtő kitarkarítsa.
Így rajzoltatom ki a játékos-négyzetet:

Kód:
xhely=50;
yhely=50;
Rectangle teglalap;
public MainForm()
{

InitializeComponent();
Paint += new PaintEventHandler(Rajzol);
KeyDown += new KeyEventHandler(gombnyomas);
teglalap=new Rectangle(xhely,yhely,100,100);

void Rajzol(object sender, PaintEventArgs e)
{
teglalap.X=xhely;
teglalap.Y=yhely;
e.Graphics.FillRectangle(Brushes.BlueViolet,teglalap);
}


így meg törölném egy gombnyomásra:

Kód:
void gombnyomas(object sender, KeyEventArgs e)
{
if (e.KeyCode==Keys.Enter)
{
teglalap.Dispose(); //vagy teglalap=null; de ez is hibát ír ki!
}
}


Az a kérdésem tehát, hogy ez az objektumtörlés hogyan oldható meg a C#-ben, Windows alkalmazásban? Vagy osztályként (class) kéne megadnom a téglalapot és akkor használható a Dispose()? Ez utóbbi esetben hogy történik a kirajzolás megadása az osztályon belül?
   
Matzi - Szerkesztő | 2521 hsz       Online status #211386   2017.05.23 12:52 GMT+1 óra  
Szerintem nem feltétlenul a megoldásra gondolt, hanem arra hogy hogyan oldja meg kódból. Az már némileg trukkosebb, mert kell valamiféle reprezentáció az állapottérre, és azon kell optimalizálni egy legrovidebb utat.
If your game idea starts with the story it’s not a game idea.
Stories in games are optional.
   
FZoli - Szerkesztő | 4892 hsz       Online status #211385   2017.05.23 12:27 GMT+1 óra  
áhh elkéstem, írni akartam, hogy nem olyan nehéz, akár simán a lehetőségek próbálgatásával is fejben percek alatt megoldható a feladat.
   
Lord_Crusare - Törzstag | 1290 hsz       Online status #211384   2017.05.23 12:20 GMT+1 óra  
Először át megy az 1 és 2 perces ürge (ez eddig 2 perc). Az 1 perces visszajön, visszahozza a lámpát (ez 3 perc). Ezután átmegy az 5 és 10 perces ürge (13 perc), a 2 perces vissza hozza a lámpát (15 perc). Végül az 1 és 2 perces is átmegy, és ez így 17 perc.

   
djlord - Tag | 1 hsz       Online status #211383   2017.05.23 10:54 GMT+1 óra  
Valaki eltudná küldeni nekem ennek a feladatnak a megoldását mert nem tudom megcsinálni és szükségem lenne rá hogy megértsem a működési elvét az ilyen programoknak előre is nagyon köszönöm ha valaki szán rám időt .


Négy ember át akar jutni egy híd egyik oldaláról a másikra. A hídon egyszerre
legfeljebb két ember mehet át. Az első embernek egymagában 1 perc, a
másodiknak 2 perc, a harmadiknak 5 perc, a negyedik pedig 10 perc szükséges
a hídon való átkeléshez. Ha ketten mennek egyszerre, akkor mindketten a
lassabban haladó tempójában ballagnak. Az átkeléshez adott és szükséges
tovább´a egy elemlámpa, amelyet magunkkal visznek az átkelők. (L´ampa
nélkül nem lehet átmenni.) Hogyan jutnak át mind a négyen a túlsó oldalra
17 percen belül?

   
Instalok - Tag | 545 hsz       Online status #210850   2017.01.26 09:09 GMT+1 óra  
Áh, annyi kizárt, hogy lesz, ráadásul a linkelt megoldás tök jól működik, még a selection-t is kezeli magától. Köszi!

   
Parallax - Tag | 591 hsz       Online status #210849   2017.01.26 08:58 GMT+1 óra  
Mindenképpen az utóbbi, vagyis lekérdezni a teljes listát, majd azon LINQ-zni és a memóriában manipulálni, ha valami változik, csak azt menteni. Amíg nem milliós nagyságrendű adatokkal dolgozol ez járható út.

   
Instalok - Tag | 545 hsz       Online status #210847   2017.01.25 14:05 GMT+1 óra  
Közben sikerült végre (talán) összeraknom, haladtam is kicsit tovább. Most viszont felmerült egy olyan kérdés, amire nem egyértelmű a válasz.

Adott egy DataGrid, ami elemeket jelenít meg. Van felette egy TextBox, amivel filterezni lehet a megjelenített dolgokat (bizonyos propertyje alapján). A helyzet ugye az, hogy a ViewModel nem közvetlen Entityvel babrál, hanem egy Entityt "wrappelő" objektummal. Ezeket az objektumokat egy megfelelő osztályon keresztül tudom lekérdezni (és létrehozni), azonban minden egyes lekérdezéskor új objektumok jönnek létre.

Úgy gondoltam, hogy a filterezés az ennek az osztálynak a feladata, azaz meghívom egy függvényét, ami visszaad egy IEnumerable<T>-t annak megfelelően, hogy milyen elemeket talált a feltétel alapján.

Ezt azonban megtehetné a ViewModel is: van egy listája az összes elemről (amihez új elem hozzáadásakor Addolni is tud), amit a létrejöttekor kért le a fent említett osztálytól. Ha nincs filter, akkor ezt a listát (ObservableCollection) adja vissza, ha van filter, akkor pedig Linq Extension függvényekkel magának filterezi a listát, és azt adja vissza.

Az utóbbi hatékonyabbnak tűnik (nem jönnek létre új objektumok), viszont logikailag nem feltétlen a ViewModelhez tartozik.

szerk.:
Bár, az is lehet, hogy ez teljes egészében a View feladata marad, meg lehet így is csinálni:
http://stackoverflow.com/questions/13815607/find-a-record-in-wpf-datagrid-by-typing

Ezt a hozzászólást Instalok módosította (2017.01.25 14:56 GMT+1 óra, 321 nap)

   
Parallax - Tag | 591 hsz       Online status #210844   2017.01.25 07:43 GMT+1 óra  
Láttam én is olyan projektet, ahol nem volt model se, hanem a view-be voltak belehekkelve az entitás objektumok közvetlen kezelése. Be is bukott a projekt, mert egyre kuszább, átláthatatlanabb lett az egész, mert azt hitték így gyorsabban haladnak. Tehát hosszútávon kell egy jól felépített architektúra és a TDD-re se árt rászokni, sokat segít a még jobb felépítésben és nem utolsó sorban nem kell soha félni, hogy valami elromlik és ez időben megtérül.

   
Instalok - Tag | 545 hsz       Online status #210840   2017.01.24 12:29 GMT+1 óra  
Hehe, igen, láttam a Resharpert sokan használják, egyelőre megvagyok nélküle. Amúgy pont megtaláltam a data validationt is, legalábbis az IDataErrorInfo részt, de látom van pár lehetőség (legalábbis .NET 4.5-től felfelé).

Olvasgattam meg néztem videókat még kicsit a témában, és megint elbizonytalanodtam. A legtöbb helyen a modelt egyként definiálják az entityvel. De ahogy írtad is, az nem úgy logikus (és biztonságos), ha az a két dolog elkülönített? Arról nem is beszélve, hogy a legtöbb leírásban a tényleges Data Access hardcode-olt, sehol nem használtak igazán Dependency Injectiont. Tehát nem is volt ennyi absztrakciós szint.

Tehát adott egy XEntity osztály, ami a tárolt (pl. adatbázisban) adatot reprezentálja:
Kód:
class XEntity
{
    // database mappingek a generáláshoz...
    // public propertyk...
}

Van egy IRepository, ami vissza tud adni XEntity collectiont, meg mondjuk el tud tárolni egy újat. Ez csak azért létezik interfészként, hogy ne a model layer feladata legyen eldönteni, hogy milyen adattárolót akar használni (így pl. a Unity/Functional Test használhat mock adatokat is)
Kód:
interface IRepository
{
    IEnumerable<XEntity> XEntities { get; }
    void AddX(XEntity);
}

Ezt a megfelelő "data provider" (azaz pl. egy MS SQL-t használó library) implementálja.

Ezután adott egy X osztály is, ami a külvilággal való kommunikációhoz kell. Tulajdonképpen wrappeli az XEntity-t, kiegészítheti különböző propertykkel is (pl. az entity egy PersonEntity, aminek van FirstName és LastName adatmezője, akkor a Person tartalmazhat egy FullName propertyt is, ami viszont nyilvánvalóan nincs ténylegesen tárolva - azaz nem része az entitynek):
Kód:
class X
{
    // public propertyk...
}

(1) Első körben úgy oldottam meg, hogy ez az osztály implementálja az INotifyPropertyChanged interfészt, így lehet erre bind-olni (amivel azonban már inkább a ViewModel rétegbe húz). Elgondolkoztam azon is, hogy ettől el kellene vonatkoztatom, és minden egyes megjelenítendő egységhez külön ViewModel osztályt létrehozni, ahol vannak olyan propertyk, amik küldik a notificationt. Persze ez sok extra (és fölösleges) kódolás lenne.

Nyilván ha van egy X akkor van sok X, szóval van egy Xs (vagy XList, XGroup, akármi) osztály is. Itt van a következő probléma:

(2) Ezt az osztályt használom arra, hogy az XRepository-n keresztül adatokat lekérjen és módosítson (de X objektumok segítségével). Első körben ez is implementálja az INotifyPropertyChanged interfészt, de látszik, hogy ez logikailag nem stimmel. Ennek az osztálynak csak annyi lenne a dolga, hogy több X-et vissza tudjon adni különböző feltételek mellett (összes, top 10, bizonyos property alapján, stb.)

Ha itt minden tiszta lenne, akkor az adott alkalmazás feladata annyi lenne, hogy:
- Létrehozza a megfelelő IRepository objektumot (az alkalmazás döntsön, hogy milyen adattárolót használ)
- A megfelelő View megkapja a megfelelő ViewModel(eke)t DataContextként

   
Parallax - Tag | 591 hsz       Online status #210838   2017.01.24 07:41 GMT+1 óra  
A CanExecute csak akkor engedi a gombot, amikor már minden valid. Közben a controlokra szépen rá lehet kötni error providert, ami irkálás közben jelzi a hibákat, de addig nem tudsz menteni, amíg a CanExecute nem engedi: DataValidation

Még, ami hasznos (C++ hoz is cool) a ReSharper. Ez akár DLL-eket is behúz a projektbe, ha valami nem található, de a név alapján rájön honnan való. Ezzel elég precízen is be lehet tartani a kódolási szabályokat, sok mindent kijavít, ismeri a legújabb nyelvi szabályokat, xaml kódot, mindent. (Sajnos fizetős, de le lehet szedni krackelten.) Valaki úgy megy interjúra, hogy előre megkérdezi van e ReSharper licensz.

   
Instalok - Tag | 545 hsz       Online status #210837   2017.01.23 18:15 GMT+1 óra  
Közben csináltam commandokat is, működik a CanExecute is, csak annyi a gondom így az egésszel, hogy a User nem kap visszajelzést, hogy miért nem tud mondjuk egy új terméket hozzáadni az adatbázishoz.

Azon gondolkoztam, hogy lesz egy error text is, amit hozzábindolok egy propertyhez. Azt a propertyt pedig a textbox által setelt propertyben fogom módosítani, attól függően, hogy helyes-e az input.

Meg az is lehet, hogy az egész CanExecute részt kihagyom, és akkor validálok, amikor a user rányom a gombra, mert minden egyes betűnyomásra áttúrni az adatbázist nem biztos, hogy túl szerencsés, ha megfelelő mennyiségű adat van.

   
Instalok - Tag | 545 hsz       Online status #210836   2017.01.23 15:49 GMT+1 óra  
Most már nekem is, csak meg kellett oldanom, hogy a resources-ok között ott legyen a data context. Érdekesen meg kell csavarni, mert nálam úgy néz ki, hogy adott ugye a Repository, aki közvetlenül az adatokkal machinál, a ViewModelnek pedig kell egy Repository objektum. Viszont ez nincs hardcode-olva, azaz kívülről kapja meg (az alkalmazás dönti el, hogy milyen Repositoryt használ, ha adatbázis, akkor milyet, stb.) konstruktor paraméterként.

Megoldottam csúnyán egy static propertyvel:
Kód:
// App
m_Repository = GetDBRepository();
Services.Initialize(m_Repository);

// ProductsView
public class ProductsView : Products
{
    public ProductsView()
        : base(Services.Repository)
    {
    }
}

Így már használható XAML szinten is:
Kód:
    ...
    DataContext="{DynamicResource ProductsView}" ResizeMode="NoResize">
<Window.Resources>
    <v:ProductsView x:Key="ProductsView"/>
</Window.Resources>

A commandokkal egyelőre nem foglalkoztam, de ez egy elég jó kis step-by-step dolognak tűnik. Ráadásul ezekben a témákban az MSDN doksi is elég jó, amennyire olvasgattam.

Annyi volt a bajom egyelőre a commandokkal, hogy kell neki egy másik Assembly (talán a WindowsBase nem tudom), viszont a Model model assemblyt (amiben a ModelView layer is van, hiszen az szorosabban kapcsolódik oda, mint máshova) nem szeretném egyéb dependenciákkal beszemetelni.

szerk.:
Viszont most jöttem rá, hogy mivel egyébként is csináltam egy ProductsView osztályt a View assemblyn belül, így használhatok commandokat is, amik csak simán meghívják az ősosztály függvényeit.

Ja és köszi a segítséget, valamiért elég nehéz volt most a felfogásom.

   
Parallax - Tag | 591 hsz       Online status #210835   2017.01.23 15:30 GMT+1 óra  
Nekem VS15-el érzékel mindent, még a nyelvi resource-öket is. A commandozást is próbáld az is jó dolog és be lehet állítani, hogy a parancs milyen esetben teljesülhet, ha nem, akkor automatán letiltja a gombot.

   
Instalok - Tag | 545 hsz       Online status #210834   2017.01.23 13:35 GMT+1 óra  
Hehe, akkor lehet jobban ránézek a WPF-re, csak eléggé szokni kell. A Winforms-t már nagyjából ismertem, de sebaj.

Rájöttem közben, hogy nem is feltétlen muszáj külön XY tulajdonságú listát visszaadni a ViewModel-ből, mert használható a DisplayMemberPath attribútum, viszont maga az adathalmaz kisebb, ha csak külön elemeket kérek le.

Azóta próbálgattam kicsit ezt a WPF binding dolgot, és elég jónak tűnik, kvázi csak propertyket kell írnom. Cserébe nekem valamiért az XAML-nél nem érzékeli a lehetséges propertyket, így nagyon figyelnem kell, hogy pontosan legyenek beírva.

   
Parallax - Tag | 591 hsz       Online status #210833   2017.01.23 13:14 GMT+1 óra  
Winforms alá sehogy, ott egy elem tulajdonságait tudod kötni controlokhoz és ennyi, a többit le kell kódolni. .NET-ben a winforms olyan, mint C++ nál a Win API, már nem nagyon használja senki.

   
Instalok - Tag | 545 hsz       Online status #210832   2017.01.23 13:02 GMT+1 óra  
Azt hiszem kezdem kapisgálni (csináltam egy mini WFP alkalmazást, ami megoldja a lenti feladatot) Szóval a ViewModel olyan objektumokat ad vissza, amikhez lehet bindolni. Tehát, ha akarok egy olyan listát, ami csak a Product neveket adja vissza, akkor a ViewModelnek van egy olyan propertyje, hogy ObservableCollection<string> ProductNames. A Notify meg gondolom azért kell, hogy ha a ViewModel átbuherálja a listát, akkor a View értesüljön róla.

Így, mivel az ObservableCollection-höz van bindolva, akkor kap értesítést arról, ha az elemek változnak, meg akkor is, ha maga a collection változik.

Ez valóban nem hülyeség, és sok glue-kódtól megkíméli az embert. Már csak azt kell megnézni, hogy Winforms alá hogyan lehet megcsinálni (bár ez a WPF sem tűnik rossz dolognak).

   
Parallax - Tag | 591 hsz       Online status #210831   2017.01.23 12:12 GMT+1 óra  
Ha WPF-et használsz, akkor kb ennyi lenne:
ViewModel
Kód:
Product selectedProduct;
public Product SelectedProduct
{
    get { return selectedProduct; }
    set
    {
        selectedProduct = value;
        NotifyPropertyChanged("SelectedProduct");
    }
}

ObservableCollection<Product> products;
public ObservableCollection<Product> Products
{
    get { return products; }
    set
    {
        products = value;
        NotifyPropertyChanged("Products");
    }
}


View
Kód:
<ListBox
    ItemsSource="{Binding Products, Mode=TwoWay}"
    SelectedItem="{Binding SelectedProduct, Mode=TwoWay}"/>

<TextBox Text=
    "{Binding SelectedProduct.Name, Mode=TwoWay,
    UpdateSourceTrigger=PropertyChanged}"/>

   
Instalok - Tag | 545 hsz       Online status #210830   2017.01.23 11:15 GMT+1 óra  
Na ja, ezt a binding dolgot még emésztenem kell. Ha saját magamnak kódolom le a controlok állítgatását, akkor tök jó, csak persze ennél lehet okosabban is. Esetleg tudnánk egy példát nézni? Úgy talán összeállna teljesen.

Tehát adott egy ProductEntity, ami a data layer része, ez kvázi egy adatbázis tábla 1:1 reprezentálása a kódban. Vannak mindenféle attribútumai, aminek segítségével lehet akár adatbázist is generálni.
Kód:
[Table(Name = "products")]
public sealed class ProductEntity
{
    [Column(Name = "id", IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false, DbType = "INT NOT NULL IDENTITY")]
    public Int32 Id
    {
        get;
        set;
    }
   
    // Name, Quantity hasonlóan
}

Van egy Data Repository is (szintén a data layer része), amely az implementációtól függően a megfelelő helyről tud Entity-ket visszaadni (adatbázis, file, memória, stb.) Például az adatbázis-implementáció egyszerűen lekéri a táblát a DataContext segítségével:
Kód:
public class DBRepository : IRepository
{
    [Database(Name = "Stock")]
    private class Context : DataContext
    {
        public Table<ProductEntity> Products
        {
            get { return base.GetTable<ProductEntity>(); }
        }

        public Context(IDbConnection p_Connection)
            : base(p_Connection)
        {
        }
    }
   
    // ...
   
    IEnumerable<ProductEntity> IRepository.Products
    {
        get { return m_DataContext.Products; }
    }
}

A következő réteg a "ViewModel", ahol már olyan objektumok vannak, amelyeket a View direktben olvashat-írhat. Ott van például a Product osztály, ami egyetlen ProductEntity megfeleltetése (természetesen nincs Id propertyje, csak Name és Quantity).
Ha jól sejtem ez az osztály implementálhatná például az INotifyPropertyChanged interfészt. Ezt egyelőre meg is tettem, van egy BindableBase osztály, így kevesebbet kell kódolni:
Kód:
public sealed class Product : BindableBase
{
    private string m_Name;
    private int m_Quantity;
   
    public string Name
    {
        get { return m_Name; }
        set { base.SetProperty(ref m_Name, value, "Name"); }
    }
   
    public int Quantity
    {
        get { return m_Quantity; }
        set { base.SetProperty(ref m_Quantity, value, "Quantity"); }
    }
}

Továbbá van egy Products nevű osztály is, ami paraméterként vár egy IRepository-t (ezt használja a tényleges adatok olvasására-írására).
Kód:
public sealed class Products
{
    private IRepository m_Repository;

    public Products(IRepository p_Repository)
    {
        m_Repository = p_Repository;
    }

Ezen keresztül tud a View commandokat kiadni (egyelőre egyszerűen függvényhívásokkal), mint pl. egy új Product hozzáadása. Az Add() függvény egy Product objektumból egy ProductEntity-t készít, és megkéri a Repository-t, hogy tárolja el. Előtte természetesen leellenőrzi, hogy van-e már ilyen nevű product (az error kezelés egyelőre csak dummy, nem tudom még hogy lesz).
Kód:
public bool Add(Product p_Product, Action<string> p_Error)
{
    bool productNameAlreadyTaken = m_Repository.Products.Any(p => (p.Name == p_Product.Name));
    if (productNameAlreadyTaken)
    {
        p_Error(string.Format("Product name "{0}" is already taken", p_Product.Name));
        return false;
    }

    ProductEntity entity = new ProductEntity()
    {
        Name = p_Product.Name,
        Quantity = p_Product.Quantity
    };

    m_Repository.AddProduct(entity);

    return true;
}

Hasonlóan megy a teljes lista lekérdezése is:
Kód:
public List<Product> GetAll()
{
    var result = m_Repository.Products.Select(p => new Product()
    {
        Name = p.Name,
        Quantity = p.Quantity
    });

    return result.ToList();
}

Na most tegyük fel, hogy szeretnék egy Form-on egy ListView controlt és (egyelőre csak) két labelt. A ListView kilistázná az összes product nevét, a két label pedig kiírná a kijelölt listaelem nevét és mennyiségét.
Ez az egyszerűbb eset, mert ez az egy irányú binding, de ha ez összeáll, akkor szerintem oda-vissza is menni fog.

Ha kézzel akarnám lekódolni, az valahogy így nézne ki a Form-on belül:
Kód:
private Products m_Products; // a fentebbi Products osztály
private IList<Product> m_ProductList; // az összes Product
private Product m_Product; // a "kijelölt" Product

private Product CurrProduct
{
    get { return m_Product; }
    set
    {
        m_Product = value;

        // notify
        if (m_Product != null)
        {
            lblNameValue.Text = m_Product.Name;
            lblQuantityValue.Text = m_Product.Quantity.ToString();
        }
        else
        {
            lblNameValue.Text = "";
            lblQuantityValue.Text = "";
        }
    }
}

public MainForm()
{
    InitializeComponent();

    m_Products = new Products(Services.Repository);
    m_ProductList = m_Products.GetAll();
   
    CurrProduct = m_ProductList[0];
}

   
Parallax - Tag | 591 hsz       Online status #210829   2017.01.23 09:56 GMT+1 óra  
A databinding lényege, ahogy írtad oda-vissza (WPF-ben ez állítható is) automatikus adatkapcsolat. Listára is működik például a fa struktúrámban kitörlök valamit és ez rá van kötve egy TreeView-re, akkor az látszik is, ehhez nem kell külön programozni semmit. Ahogy kiválasztok egy node-ot, a SelectedItem is automatikusan kiválasztódik és mutatja az adatait is. Az adat lehet szöveg, kép stb, szépen realtime szerkesztődik minden a memóriában és, ha kiadod a mentés parancsot, akkor a megfelelő adatok a megfelelő táblába mentődnek a Model-en keresztül ellenőrzötten.

   
Instalok - Tag | 545 hsz       Online status #210828   2017.01.23 08:16 GMT+1 óra  
Igen, kell is még néhány módosítás. Azóta aludtam rá egyet, és valószínűleg az lesz, hogy ez a Products osztály nem Entityket fog visszaadni, hanem megjelenítendő modelleket, mert, ahogy írtad is, entityket nem használunk közvetlenül. A biztonságosabb kód mellett a további előnye a különböző konverziók lesznek, illetve az olyan propertyk megléte, amelyek nem részei az entitynek egyébként.

Ezt az automatikus bindolást használják egyébként mindenfelé a kódban. Lehet én is fogom, de nekem könnyebb követni, ha ott van az a glue kód, és látom, hogy mi-mit-mikor-miért csinál. Persze a másik sem bonyolult, csak nekem új.

Ha jól értettem a bindingnak a lényege az, hogy a ViewModel egy propertyje és a View egy UI eleme össze van kapcsolva, így, ha a ViewModel valamiért változik (például egy action hatására), akkor a View UI eleme is automatikusan változik, és nem kell ismételten lekérnem az adatokat. Illetve gondolom fordítva is igaz, ha a UI elemet szerkesztem (mert az pl. egy textbox), akkor a ViewModel kap egy értesítést, hogy az adott property változott.

Egy-egy elemre ezt így könnyű elképzelni, de mi van a listás megjelenítéssel? Van valami ObservableCollection is (ahogy lentebb említetted is).

Nekiállok ezt elolvasni, hátha le van írva szépen:
[url]https://msdn.microsoft.com/en-us/library/ms743643(v=vs.110).aspx[/url]

   
Parallax - Tag | 591 hsz       Online status #210827   2017.01.23 07:06 GMT+1 óra  
Entitást közvetlenül nem használunk semmire, mert bármilyen manipuláció történik azt úgy veszi, hogy az az adatbázissal történik és valahol elsül egy SaveChanges(), főleg, ha globális is, akkor ki tudja mi lesz.

A másik, hogy a model direkt a felületekre van felkészítve, a listában kiválasztott elem hozzá van kötve egy propertyhez, ha a lista változik a lista is automatikusan változik, ha adott elem bármilyen propertyje változik az a felületen automatikusan megjelenik és vissza. Igazából ez a .NET (WPF, ASP.NET MVC) előnye, ezek a kötési automatizmusok.

   
Instalok - Tag | 545 hsz       Online status #210825   2017.01.22 14:07 GMT+1 óra  
Valami hasonlót találtam ki azóta:

Vannak Entity osztályok, amik 1:1 megfeleltetése egy táblának. LINQ mapping segítségével attribútumokkal könnyen leírható, így akár adatbázis is generálható (nem kell kézzel).
Kód:
[Table(Name = "products")]
public sealed class ProductEntity
{
    [Column(Name = "id", IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false,
            DbType = "INT NOT NULL IDENTITY")]
    public Int32 Id
    {
        get;
        set;
    }
   
    // ...


Az IDataProvider interfészt megvalósítja egy osztály, ami kvázi a táblák adatait szolgáltatja. Nem tud semmit, csak visszaadni egy IEnumerable<TEntity>-t, meg mondjuk van Add/Update/Remove függvénye is az adott típushoz. Egy ilyen megvalósítás például egy sql adatbázist használ (LINQ esetén nagyon kevés a kód, ott a DataContext meg a Table<T>, megoldanak mindent).
Kód:
public interface IDataProvider : IDisposable
{
    IEnumerable<ProductEntity> Products
    {
        get;
    }

    void AddProduct(ProductEntity p_Entity);
}


Továbbá van minden egyes logikai elemhez egy osztály, ami paraméterként vár egy IDataProvider-t, illetve az adott típushoz műveleteket definiál, ami vagy "beépített" típusokat, vagy Entity objektumokat ad vissza.
Kód:
public class Products
{
    public IEnumerable<ProductEntity> All()
    {
        return m_DataProvider.Products;
    }

    public bool Contains(int p_Id)
    {
        return m_DataProvider.Products.Any(p => (p.Id == p_Id));
    }
   
    // stb.
}


Ha nem akarnék további absztrakciós szintet, akkor a Products osztály használható lenne közvetlenül a View layer osztályaiban, azonban gyakran előfordulhat, hogy különféle konverziók, egyéb lekérdezések is kellenek, így tényleg érdemes lehet egy "ViewModel", vagy valami hasonló bevezetése.

Amin viszont elgondolkoztam, hogy lehet Entity szinten definiálni azt, hogy pl. egy Transaction nem egy ProductId-t ad vissza, hanem egy Product objektumot:
[url]https://msdn.microsoft.com/en-us/library/bb386950(v=vs.110).aspx[/url]

Ezt viszont megoldhatja a Products vagy Transactions osztály is, csak akkor kód szinten függőség alakul ki közöttük (meg kell kapniuk egymás referenciáját).

   
Parallax - Tag | 591 hsz       Online status #210824   2017.01.22 11:29 GMT+1 óra  
Instalok: Winforms, meg webforms az nem épp MVVM/MVC-re van kihegyezve, de persze plusz kódolással megolható a szemlélet.
Én valahogy így építeném fel az architektúrát:

Data: Adatbázist burkoló alrendszer pl.: Etity framework. 1-1 entitás osztály reprezentál 1-1 táblát. Szuboptimálisan hangzik, de minden lekérdezésnél létre kell hozni a kapcsolatot, utána pedig megszűntetni (dispose pattern). Ez desktop és főleg netes programnál így szokás különböző hibalehetőségek és egyebek miatt.

Model: Az entitások db független pehelysúlyú ábrázolása és különböző beépített lekérdezési lehetőségek, mint pl: authentikáció a User-nél. Ez arra jó, hogy a különböző felületek számára könnyen megjeleníthetőek és testreszabott műveleteket, konverziókat is tartalmazhatnak (serialization). Itt szokás külön egy és lista objektumokat definiálni: User, UserList, ahol a User lehet egy épp kiválaszott elem (NotificationObject), a lista (ObservableCollection) pedig a lekérdezett userek listája, amin műveleteket hajtunk végre és a végén mentés az adatbázisba.

ViewModel: Ez reprezentálja azt az adathalmazt (propertyk), és műveleteket (command pattern) amit a view/view-ek megjelenítenek. Itt nincs semmi platform specifikus dolog, és ide jöhet a validáció is (adott adat 1 és 100 közés eshet stb)

View: Ahogy írtad a view lenne egy buta felület, ami csak az adatok bevitelét, kiírását és bizonyos korlátok között manipulációkat végzi.

   
Instalok - Tag | 545 hsz       Online status #210823   2017.01.21 13:45 GMT+1 óra  
Az a feladat, hogy egy Windows Desktop (WinForms) alkalmazást kell készíteni, amivel egy adatbázist lehet vezérelni (módosítani, lekérdezni, semmi komoly).

A kérdésem arra irányulna, hogy WinForms esetén milyen megközelítést érdemes választani? Ami számomra fontos szempont:
- elkülönített business logic és presentation: később, ha kell, könnyedén lehessen írni egy webes megjelenítést is, ugyan azzal a backend kóddal.
- generikus data access layer: nem hardcode-olt SQL adatbázis-elérés, hanem ha kell, akkor lehessen mock adatokkal is dolgozni, vagy egyéb file-okból beolvasni (pl. xml).

Webfejlesztéskor megint más az egész, ott egy HTTP reqeust az új oldal betöltésekor megy, és kész, nincs permanens adat. Ott fekszik az MVC, ahol a requestet feldolgozza a controller, ha szükséges, nyit adatbáziskapcsolatot, lekéri/módosítja az adatokat, kiválasztja és létrehozza a view-t, majd végzett a munkával.

Desktop esetén pedig adott egy folyamatosan futó alkalmazás, ami maga a view. Valami olyasmit tudnék elképzelni, hogy adott egy Form, amely csak a megjelenítést végzi, tehát a "View". Adott egy logikai csoporthoz (pl. felhasználók kezeléséhez) tartozó "Controller", amin a View műveleteket hív, amely például visszaad egy objektumlistát lekérdezéskor. Maga a "Model" olyan osztályokból állna, amelyek az adatot reprezentálják, azaz kvázi egy adatbázis-tábla megfeleltetése.

Ez eddig szép és jó, de hiányzik a data-access, azaz, hogy mikor, kitől és hogyan kérem el az adatokat. Ez igazság szerint a controllerbe tartozik, hiszen a controlelr tudja, hogy milyen feltételekkel kell (pl.) lekérdezést végrehajtani. Még ha használok is valami általános dolgot (pl. LINQ esetén van DataContext), akkor is kérdéses, hogy kitől kapja meg ezt az objektumot, vagy magát a data source-ot (ami lehet sql connection, vagy file is). Overkill lenne minden egyes controller action esetén létrehozni egy új adatbáziskapcsolatot, majd a végén lezárni.

Milyen általános megközelítést lehetne használni desktop alkalmazás esetén?

   
Pixi - Tag | 206 hsz       Online status #208498   2015.10.19 13:52 GMT+1 óra  
Azt hogyan lehet megoldani, hogy az adott aplikáción kívülre is tudjunk utasítást küldeni az egérnek és a billentyűzetnek? Vagyis egér pozíció, gomblenyomás és billentyűzet gomblenyomás a cél, ezt kéne szimulálni programon kívül is. Az természetesen alap, hogy a háttérben futna egy program, ami magát ezt a funkciót biztosítja, ugyanis hálózaton keresztül kellene vezérelni mindezt. Vagyis egy adott üzenet biztosítaná kliens oldalon azt az eseményt, hogy éppen mit kell szimulálni. Ezt hogyan lehet megvalósítani, hogy ne csak az adott programon belül legyen érvényes?

szerk: Lényegében egy "Remote Desktop Controller" lenne a cél.

Ezt a hozzászólást Pixi módosította (2015.10.19 14:16 GMT+1 óra, 785 nap)

   
Parallax - Tag | 591 hsz       Online status #208099   2015.08.13 15:08 GMT+1 óra  
Idézet
Pixi :
Szerintetek hogyan legcélszerűbb egy telepítőt elkészíteni?

ClickOnce

   
Pixi - Tag | 206 hsz       Online status #208085   2015.08.11 13:10 GMT+1 óra  
Tunyu: Köszi, szerintem ez pont az amit én kerestem.

Matzi: Egyelőre úgy vagyok vele, hogy amit én magam is elkészíthetek, azt miért ne? Legalább ezzel is tanulhatok valami újat. Bár lehet, hogy tényleg kész megoldást fogok alkalmazni majd. Azt mondjuk nem tudom, hogy mi a gond azzal, ha mellékelve van pl. egy "software requirements" mappában a .net-es telepítő (offline, de akár online változata is), és ezen kívül lenne maga a .net-es program telepítő.exe + egy readme.txt. Vagy ezek szerint ez már a múlté, és egy laikus felhasználó ilyen környezetben nem tudja feltalálni magát? Mondjuk el tudom hinni sajnos. Azt amúgy nem is értem hogy lehet olyan telepítőt generálni, ami külön beavatkozás nélkül, vagy pedig automatikusan érzékeli és telepíti a gépre az aktuális .net verziót. Azt mondod, hogy van az a bizonyos adat file. Ha jól értelmezem, akkor ez még külön ott van a telepítő mellett ugye? És akkor akár egy darab nyers adat file-ba is bele tudom tenni az összes contentet + exe filet is, csak a telepítő programon belül pl. megmondom hogy x byte-tól y-ig ez egy "image1.png" a következő lépésben már egy exe file-t kel kiírni, stb.

   
Matzi - Szerkesztő | 2521 hsz       Online status #208084   2015.08.10 19:47 GMT+1 óra  
Idézet
Ha nem egy irányú lenne az SHA akkor csak azt használnám egyedül.
Az SHA nem titkosítás, hanem hash generálás. Annak a célja, hogy egy adatot átalakítson egy fix méretű másikká úgy, hogy kicsi legyen az ütközés esélye (két tetszőleges forrásból lehetőleg ne jöjjön ki ugyanaz a hash), de jelentősen csökkenjen méretben és ne lehessen visszafejteni. A titkosítás meg ugye nem akar elveszíteni adatot.

Pixi:
A legegyszerűbb, ha fogsz egy telepítő generáló programot, ami pont olyat csinál, mint bármelyik jelenleg is használt program telepítője. Biztos van ingyenes meg nyílt forráskódú is a neten.Az a baj, hogy ha külön akarod feltelepíttetni egy felhasználóval a .net-et, hogy ha még nincs a gépén, akkor jó eséllyel lövése sincs róla hogy mi az, és hogy előbb azt fel kellene tegye.
Mondjuk már a vistától felfelé a 3.0 az alap, de xp-n még külön fel kellett tenni. Szóval hacsak nem akarsz xpre is települni, akkor megírhatod .net-ben. Ilyenkor tipikusan van egy valamilyen adat file, akár lehet zip is, amit kicsomagolsz oda, ahová a user kéri, és esetleg telepítesz más programokat amik kellhetnek.
If your game idea starts with the story it’s not a game idea.
Stories in games are optional.
   
Tunyu - Tag | 448 hsz       Online status #208083   2015.08.10 15:32 GMT+1 óra  
Ha jól értem, akkor a válasz itt van.

   
Pixi - Tag | 206 hsz       Online status #208080   2015.08.10 10:34 GMT+1 óra  
Szerintetek hogyan legcélszerűbb egy telepítőt elkészíteni? Mennyire jó, ha maga a telepítő.exe egy komplet .NET-es alkalmazás? Valahogy úgy képzelem el, hogy van két fő file, az egyik a .net telepítő, amit a felhasználónak telepítenie kell 1x, ha az nincs a gépén, a másik maga a telepitő.exe, ami lehetne akár egy WinForm alkalmazás is (de végül is tökmind1 mi), és kisebb játékok esetén minden binárisan eltárolva ebben, tehát a kész projekt debug mappájában lévő anyagot betöltetném egy másik alkalmazásba, és ez íródna a tárolóra az előzőleg megadott útvonal szerint, ami már maga a telepítő.exe sajátos felépítésétől függ. A kérdés már csak az, hogyan oldják meg, hogy egy kész exe már magában tartalmazza nyersen az adatokat, tehát a különböző contenteket ne egy külső forrásból töltse be mindig, hanem már maga az exe része legyen? Mert ok, hogy program elindít, betölt minden adatot, de ezt ne kelljen külső forrásból töltögetnie. Úgy is kérdezhetném, hogy hogyan lehet a már lefordított aplikációt úgy debuggolni, hogy annak a része legyen a nyers adat? Gyanítom, hogy nem azt csinálják, hogy nyitnak minden egyes contetnek egy vagy több külön osztály.cs -t meg külön tömböt, és abba pakolgatják manuálisan byte-ok formájában a nyers adatokat. Vagy fölösleges ilyesmivel bajlódni, és bőven elég ma már egy kisebb játékot egy zip-be csomagolni, és úgy forgalmazni?

Ezt a hozzászólást Pixi módosította (2015.08.10 10:50 GMT+1 óra, 855 nap)

   
Tunyu - Tag | 448 hsz       Online status #208079   2015.08.09 16:49 GMT+1 óra  
Láttam én is hogy van újabb és fejlettebb az MD5-nél, de mivel már az SHA -1 is 40 karakteres kimeneti mérettel rendelkezik, az már nekem túl nagy, mert a 256 bites AES egy 32 karakteres kulcsot igényel.Az MD5 kulcs sehol nem lesz tárolva, azt majd a kliens oldal generálja a bejelentkezési adatból és küldi el a szervernek ahol ugyan ezzel a kulcsal vissza tudja fejteni és újra kódolni a játékos mentett adatait .Ha nem egy irányú lenne az SHA akkor csak azt használnám egyedül.

Ezt a hozzászólást Tunyu módosította (2015.08.09 17:56 GMT+1 óra, 855 nap)

   
Matzi - Szerkesztő | 2521 hsz       Online status #208078   2015.08.09 15:44 GMT+1 óra  
Ha ennyire fontos a biztonság, akkor használj mondjuk SHA-2-t vagy 3at, persze plusz só és bors.
Mondjuk kétszáz évre előre vetíteni gyakorlatilag lehetetlen. Lehet 50 év múlva beüzemelnek olyan kvantum processzorokat amik ezer bites titkosításokat reggeliznek. Általában annyi a cél, hogy az adatot több idő és pénz legyen feltörni, mint amennyit ér. Egy játék esetében ez nem feltétlenül nagy kitétel.
If your game idea starts with the story it’s not a game idea.
Stories in games are optional.
   
Tunyu - Tag | 448 hsz       Online status #208069   2015.08.07 21:29 GMT+1 óra  
Igen én is erre gondoltam hogy egy kis toldalékkal már egészen más hasht kapunk és az adatbázisban már nem valószínű hogy létezik olyan.
Csak egy játékot próbálok összehozni és annak a kliens és szerver oldali adatait próbálom a lehető legbiztonságosabb módon tárolni, hogy feltörés esetén se tudják visszafejteni az adatokat, vagy legalábbis 1-200 éven belül ne.

Na megoldottam, végül is jó ötlet volt az md5! A bejelentkezési adatból generálok egy sózott md5 hash-t és ezt használom fel a 256 bites kódoláshoz kulcsként.
A mentett adatok ezután így néznek ki:
Kód:
   ˙˙˙˙           Assembly-CSharp   RegData   ep      ,pMXNyuDfK7eriIPOuIvDkmIHp1E0ORWjs5/dDVNR/6E=   ZVsMJjj/MFbndyvC6POpPA==

Ezt a hozzászólást Tunyu módosította (2015.08.08 12:48 GMT+1 óra, 857 nap)

   
Matzi - Szerkesztő | 2521 hsz       Online status #208067   2015.08.07 20:23 GMT+1 óra  
Ezért szokták sózni borsozni, de felőlem használhatsz más hasht is. Csak példának mondtam. Ez csak akkor kell, ha félsz, hogy ellopják a szerverről a jelszó hasheket.
Játékot csinálsz, vagy valami biztonságkritikus rendszert?
If your game idea starts with the story it’s not a game idea.
Stories in games are optional.
   
Tunyu - Tag | 448 hsz       Online status #208063   2015.08.07 12:23 GMT+1 óra  
Az md5 már kicsit elavult ahogy így utánanéztem.Le is teszteltem, egy md5 generátorral lekódóltam néhány szót, az md5 decrypter meg 10 mp múlva már dobta a string értékét. Persze nem értelmes szavaknál már nem biztos hogy ilyen egyszerű,de sok ember még mindig értelmes szavakat használ jelszónak.

   
Korábbi postok
> 1 < [2] [3] [4] [5] [6] [7] [8] [9] [10] [15] [20] [25] [30] [35] [40] [45] [46]