Coder Social home page Coder Social logo

mrousavy / jellyfish Goto Github PK

View Code? Open in Web Editor NEW
20.0 4.0 3.0 1.26 MB

๐ŸŸ An incredibly lightweight and type safe MVVM library for .NET WPF, Silverlight, Xamarin and UWP

License: MIT License

C# 94.78% HTML 2.41% CSS 1.28% Vim Snippet 1.53%
jellyfish fish mvvm wpf library light csharp dotnet enum preferences

jellyfish's Introduction

Jellyfish

AppVeyor badge NuGet downloads badge
Buy Me a Coffee at ko-fi.com

๐ŸŸ

An incredibly light and type safe MVVM library for .NET WPF, Silverlight, Xamarin and UWP

Jellyfish is on NuGet:

PM> Install-Package Jellyfish

Make sure to also check out the Jellyfish Visual Studio Extension ๐Ÿ“ฆ!

Compared to other MVVM Frameworks like MVVM Light, Prism or Caliburn.Micro, this framework is

  • as light as possible
  • using modern best-practices
  • using modern code style
  • using little to no runtime reflection to be as fast as possible
  • exactly fitting my needs

Usage

For description, documentation and usage, please view the Jellyfish wiki ๐Ÿ“– or the Getting Started guide ๐Ÿ“–. For usage-example projects, please see Jellyfish.Demo or GameFinder.

๐Ÿ“ View Models

Every ViewModel needs to implement the ViewModel class:

public class LoginViewModel : ViewModel
{
    private User _user;
    public User User
    {
        get => _user;
        set => Set(ref _user, value);
    }
}

See View Models ๐Ÿ“–

โšก Commands

The RelayCommand is an ICommand implementation.

<Window ...>
    <Button Command="{Binding LoginCommand}" />
</Window>

Initialize the ICommand with a non-generic RelayCommand instance and the given action/callback:

ICommand LoginCommand = new RelayCommand(LoginAction, CanLogin);
// ...
void LoginAction(object parameter)
{ ... }
bool CanLogin(object parameter)
{ ... }

See Commands ๐Ÿ“–

๐Ÿ’‰ Dependency Injection

Provide dependencies for types using the IInjector

At app startup:

Injector.Register<IUser>(() => new User("John", "Smith"));
Injector.Register<IDatabaseService>(() => OpenDatabaseService(username, password));

Some ViewModel:

class LoginViewModel : ViewModel
{
    IUser User { get; set; }
    IDatabaseService _service;

    LoginViewModel()
    {
        this.Inject();
    }
}

See Dependency Injection ๐Ÿ“–

๐Ÿ’พ Enums

The enum binding source extension allows for better binding support on enums.

Just use the EnumBindingSource extension to bind an enum to any ItemsSource:

<ComboBox ItemsSource="{Binding Source={jellyfish:EnumBindingSource {x:Type local:Status}}}"
	  SelectedItem="{Binding SelectedStatus}" />

See Enums ๐Ÿ“–

โš™๏ธ Preferences

An abstract class definition for any application Preferences.

public class DemoPreferences : Preferences
{
    public int SomeInt { get; set; } = 400;
    public string SomeString { get; set; } = "test string";
    public bool SomeBool { get; set; } = false;

    public object SomeObject { get; set; } = new
    {
        Name = "Marc",
        IsValid = true
    };
}

See Preferences ๐Ÿ“–

๐Ÿ”” Feeds

The IFeed<T> allows notifying any subscribers in this feed about sudden changes within the application domain in realtime.

class CustomViewModel : INode<NotifyReason>
{
    public CustomViewModel
    {
        this.Subscribe();
    }

    public void MessageReceived(NotifyReason reason)
    { ... }
}

Feed.Notify(NotifyReason.RefreshView);

See Feeds ๐Ÿ“–

Results

With Jellyfish

public class LoginViewModel : ViewModel
{
    private User _user;
    public User User
    {
        get => _user;
        set => Set(ref _user, value);
    }
}

Without Jellyfish

public class LoginViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
          PropertyChangedEventHandler handler = PropertyChanged;
          if (handler != null)
          {
              handler(this, new PropertyChangedEventArgs(propertyName));
          }
    }

    private string _username;
    public string Username
    {
        get
	{
	    return _username;
	}
	set
	{
	    _username = value;
	    OnPropertyChanged("Username");
	}
    }
}

jellyfish's People

Contributors

imgbotapp avatar mrousavy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

jellyfish's Issues

Dependency Injection/Auto-wiring

Implement Dependency Injection for interfaces or other properties.

Example:

class LoginModel : Model
{
    [Autowired]
    IDatabase Database { get; }
}

Jellyfish should automatically find the IDatabase implementation (or it is pre-configured before initialization), and initialize the Database { get; } property with that instance. The IDatabase instance is either already initialized somewhere (๐Ÿ‘) or initialized by the default constructor (๐Ÿ‘Ž)

Example 2:

class LoginModel : Model
{
    IDatabase Database { get; }

    public LoginModel(IDatabase database)
    {
        Database = database;
    }
}

Re-eval CanExecute on RelayCommand

Automatically re-evaluate the RelayCommand::CanExecute(T t) function whenever the parameter t changes.

Before:

ICommand LoginCommand = new RelayCommand<MyObject>(LoginAction, CanExecute);
// ...
bool CanExecute(MyObject parameter)
{
    return parameter.SomeValue == true;
}
// ...
public T MyObject
{
    get => _myObject;
    set
    {
        Set(ref _myObject, value);
        LoginCommand.RaiseCanExecuteChanged(); // re-evaluate CanExecute(T)
    }
}

After:

ICommand LoginCommand = new RelayCommand<MyObject>(LoginAction, CanExecute);
// ...
bool CanExecute(MyObject parameter)
{
    return parameter.SomeValue == true;
}

Possible approaches:

  • Hook PropertyChanged if it's implementing INotifyPropertyChanged
  • Pass by reference

Allow easy DependencyProperty creation

Create Dependency Properties easily by either using Attributes or Wrapper classes:

Example:

[DependencyProperty]
public string Username { get; set; }

or

private string _username;
public string Username
{
    get => _username;
    set => SetDependencyProperty(ref _username, value);
}

Global message queue

Add a global message queue that will receive and foward messages from (view)-models to (view)-models.

Example:

LoginViewModel.cs

public class MainViewModel : Sender<T>, ...
{
    public void LoginAction()
    {
        // send message of type T to any other VM
        base.Send(new { User = this.User, Status = Status.LoggedIn });
    }
}

MainViewModel.cs

public class MainViewModel : Receiver<T>, ...
{
    public override void Receive(T message)
    {
        // received message of type T from another VM
    }
}

Receiver can optionally also handle whether the message gets removed from the global message queue or stays untouched.

This is especially useful for multi-view applications, where extra updates are needed upon some action.

Use case:

  • Application has an all-users window and a create-new-user window.
  • New user gets created
  • All-Users window gets updated with the newly created user

Use [Property] Attribute

Use [Property] Attribute (PropertyAttribute.cs) for overriding a property's getter and setter methods instead of having backing fields and using the ObservableObject::Set<T>(ref T t, T value) function.

Before:

private string _username;
public string Username
{
    get => _username;
    set => Set(ref _username, value);
}

After:

[Property]
public string Username { get; set; }

Pro:

  • Much cleaner code
  • More maintainable code (less backing field or get & set pollution)

Con:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.