You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求Xamarin.Forms+Realm数据仓库、UI绑定示例及仓库模式实现资源

Hey Sebastien, totally get where you're coming from—Realm's .NET docs can feel a bit sparse when you're trying to implement patterns like the Repository pattern, especially with Xamarin.Forms. Let me walk you through a practical, clean example that balances flexibility (so swapping out Realm later is a breeze) and plays nice with Realm's unique features.


Core Repository Interface

First, define a generic repository interface that abstracts all basic data operations. This is the key to keeping your code decoupled from Realm—later, you can just implement this interface with a different provider (like SQLite or EF Core) without touching your ViewModels.

using System.Collections.Generic;
using System.Threading.Tasks;

public interface IRepository<T> where T : class
{
    Task<T> GetByIdAsync(string id);
    Task<IEnumerable<T>> GetAllAsync();
    Task AddAsync(T entity);
    Task UpdateAsync(T entity);
    Task DeleteAsync(T entity);
}
Realm-Specific Repository Implementation

Now create a Realm-specific implementation of this interface. Since Realm objects inherit from RealmObject, we'll add that constraint to ensure we're only working with Realm entities. We'll handle Realm's write transactions and thread safety here too.

using Realms;
using System.Collections.Generic;
using System.Threading.Tasks;

public class RealmRepository<T> : IRepository<T> where T : RealmObject
{
    private readonly Realm _realm;

    public RealmRepository()
    {
        // Initialize Realm with default configuration (pass a custom one if needed)
        _realm = Realm.GetInstance();
    }

    public async Task<T> GetByIdAsync(string id)
    {
        // Wrap in Task.Run to avoid blocking the UI thread
        return await Task.Run(() => _realm.Find<T>(id));
    }

    public async Task<IEnumerable<T>> GetAllAsync()
    {
        // Freeze results to make them thread-safe for UI thread access
        return await Task.Run(() => _realm.All<T>().Freeze().ToList());
    }

    public async Task AddAsync(T entity)
    {
        // Use Realm's write transaction for safe inserts/upserts
        await _realm.WriteAsync(realm =>
        {
            realm.Add(entity, update: true); // update: true handles upserts
        });
    }

    public async Task UpdateAsync(T entity)
    {
        // Realm tracks changes to managed objects automatically—just wrap in a write transaction
        await _realm.WriteAsync(_ => { });
        // For detached objects, reattach with update: true:
        // _realm.Add(entity, update: true);
    }

    public async Task DeleteAsync(T entity)
    {
        await _realm.WriteAsync(realm =>
        {
            realm.Remove(entity);
        });
    }
}
Using the Repository in Xamarin.Forms ViewModels

Now you can use this repository in your ViewModels without any direct dependency on Realm. This makes your ViewModels testable and easy to refactor later.

First, define a Realm entity (your model):

using Realms;

public class TodoItem : RealmObject
{
    [PrimaryKey]
    public string Id { get; set; } = Guid.NewGuid().ToString();
    public string Title { get; set; }
    public bool IsCompleted { get; set; }
}

Then, in your ViewModel:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Xamarin.Forms;

public class TodoViewModel : INotifyPropertyChanged
{
    private readonly IRepository<TodoItem> _todoRepository;
    private ObservableCollection<TodoItem> _todoItems;

    public ObservableCollection<TodoItem> TodoItems
    {
        get => _todoItems;
        set
        {
            _todoItems = value;
            OnPropertyChanged();
        }
    }

    public ICommand LoadTodoItemsCommand { get; }
    public ICommand AddTodoCommand { get; }

    public TodoViewModel()
    {
        // Inject the repository here (use DI for better practice!)
        _todoRepository = new RealmRepository<TodoItem>();
        
        LoadTodoItemsCommand = new Command(async () => await LoadTodoItems());
        AddTodoCommand = new Command(async () => await AddNewTodo());
    }

    private async Task LoadTodoItems()
    {
        var items = await _todoRepository.GetAllAsync();
        TodoItems = new ObservableCollection<TodoItem>(items);
    }

    private async Task AddNewTodo()
    {
        var newTodo = new TodoItem { Title = "New Todo Item" };
        await _todoRepository.AddAsync(newTodo);
        await LoadTodoItems(); // Refresh the list
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
Key Tips for Working with Realm + Repository Pattern
  • Dependency Injection: Instead of newing up RealmRepository<T> directly in ViewModels, use Xamarin.Forms' built-in DI or a library like Autofac. Register IRepository<T> with RealmRepository<T> so you can swap implementations in one place.
  • Thread Safety: Realm objects are tied to the thread they were created on. Use Freeze() on query results if you're passing them to the UI thread, or initialize Realm on the background thread for heavy operations.
  • Extend the Interface: Add Realm-specific query methods to your interface if you need advanced filtering. For example:
    Task<IEnumerable<T>> GetByQueryAsync(Func<IQueryable<T>, IQueryable<T>> query);
    
    Then implement it in RealmRepository<T>:
    public async Task<IEnumerable<T>> GetByQueryAsync(Func<IQueryable<T>, IQueryable<T>> query)
    {
        return await Task.Run(() => query(_realm.All<T>()).Freeze().ToList());
    }
    

This setup keeps your code clean, testable, and flexible—exactly what you're looking for!


内容的提问来源于stack exchange,提问作者Sebastien Delaherche

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:36:00