簡體   English   中英

使用MongoDB的WPF C#異步MVVM

[英]Asynchronous MVVM for WPF C# using MongoDB

所以我的情況是這樣的:我希望能夠使用MongoDB在我的WPF應用程序中使用MVVM。 我對MVVM非常陌生(我了解的很少),但是我對使用.NET和WPF有一定的經驗。

我有一個用於調用MongoDB集合的名稱空間,其中的Model組件作為一個名為“ User”的類存儲在該名稱空間中

模型(在單獨的命名空間中):

public class User
{
    [BsonElement("_id")]
    public ObjectId Id { get; set; }
    public string name { get; set; }
    // other methods listed here

    public async static Task<List<User>> getUserList()
    {
        // allows me to get a list of users
        var col = MongoDBServer<User>.openMongoDB("Users");
        var filter = Builders<User>.Filter.Exists("name");

        List<User> userList = await col.Find(filter).ToListAsync();

        return userList;
    }
}

我創建了一個非常基本的ViewModelBase(抽象ViewModelBase):

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

還有一個用於處理用戶列表的派生類(ViewModel):

public class UserListViewModel : ViewModelBase
{
    private User _user;
    private ObservableCollection<User> _userList;

    public User user
    {
        get { return _user; }
        set
        {
            _user = value;
            OnPropertyChanged("user");
        }
    }

    public ObservableCollection<User> userList
    {
        get { return _userList; }
        set
        {
            _userList = value;
            OnPropertyChanged("userList");
        }
    }

    public UserListViewModel()
    {
        user = new User();
        this.userList = new ObservableCollection<User>();

        // since MongoDB operations are asyncrhonous, the async method "getUserList()" is used to fill the observable collection
        getUserList().Wait();
    }

    public async Task getUserList()
    {
        var UserListRaw = await User.getUserList();
        this.userList = new ObservableCollection<User>(UserListRaw);
    }
}

視圖組件是帶有列表框的簡單窗口,如下所示(視圖):

<Window x:Class="UserManagementMVVM.UsersWindow"
    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:UserManagementMVVM"
    mc:Ignorable="d"
    Title="UsersWindow" Height="300" Width="300">
    <Window.Resources>
        <local:UserListViewModel x:Key="ViewModel"/>
        <!-- Receiving error for this XAML block saying "Object reference not set to instance of an object -->
    </Window.Resources>

    <Grid DataContext="{Binding ViewModel}">
        <ListBox Margin="5" ItemsSource="{Binding userList}"/>
    </Grid>
</Window>

App.Xaml及其背后的代碼以及View的背后代碼均保持不變。

當我運行該程序時,什么都沒有顯示(即:Window啟動,但是即使有數據,ListBox也為空)。 我將很快添加一些按鈕功能,這些功能將對MongoDB執行原子操作。

我已經嘗試了將近2個星期來為此制作自己的MVVM程序,但沒有成功。 任何幫助將不勝感激。

您沒有將getUserList()返回值放入變量中

我認為您的意思是執行以下操作

Task.Run(async ()=>this.userList = await getUserList());

這應該可以工作,您應該考慮是否要等待任務完成,而不是在任務之后放置.Wait()

您的另一個問題可能是您在上下文中綁定到ViewModel的方式,它應該使用StaticResource而不是綁定

像這樣:

<Grid DataContext="{StaticResource ViewModel}">
<Window x:Class="UserManagementMVVM.UsersWindow"
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:UserManagementMVVM"
mc:Ignorable="d"
Title="UsersWindow" Height="300" Width="300">
<Window.DataContext>
    <!--You have to set the DataContext -->
    <local:UserListViewModel x:Key="ViewModel"/>
</Window.DataContext>

<Grid>
    <ListBox Margin="5" ItemsSource="{Binding userList}"/>
</Grid>
</Window>

您必須設置DataContext權限。 我改變了你的XAML。 但是我更喜歡在Codebehind或app.xaml.cs中為Mainwindow設置DataContext。

例如:app.xaml.cs

 protected override void OnStartup(StartupEventArgs e)
 {
      var data = new MainWindowViewmodel();
      this.MainWindow = new MainWindow(data);
      this.MainWindow.Show();
 }

我的視圖的所有其他DataContext是通過ResourceDictionary中的DataTemplates完成的

 <DataTemplate DataType="{x:Type local:MyOtherViewmodel}">
    <local::MyOtherViewmodelView />
 </DataTemplate>

我要贊揚gilMishalblindmeis為我指明了正確的方向。 您的回答都對您有所幫助。 這是我更新的(和功能!)代碼:

App.xaml.cs進行了如下修改(貸記為blindmeis ):

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        UsersWindow window = new UsersWindow();
        var ViewModel = new UserListViewModel();
        window.DataContext = ViewModel;
        window.Show();
    }
}

ViewModel已更新:

public class UserListViewModel : ViewModelBase
{
    private User _user;
    private ObservableCollection<string> _userList; // changed from "User" class to string

    public User user
    {
        get { return _user; }
        set
        {
            _user = value;
            OnPropertyChanged("user");
        }
    }

    public ObservableCollection<string> userList
    {
        get { return _userList; }
        set
        {
            _userList = value;
            OnPropertyChanged("userList");
        }
    }

    public UserListViewModel()
    {
        userList = new ObservableCollection<string>();
        Task.Run(async () => this.userList = await getUserList()); // Credit to gilMishal
    }

    public async Task<ObservableCollection<string>> getUserList()
    {
        var UserListRaw = await User.getUserList();
        var userListOC = new ObservableCollection<string>();

        foreach (var doc in UserListRaw) // extracting the "name" property from each "User" object
        {
            userListOC.Add(doc.name);
        }

        return userListOC;
    }
}

和視圖:

<Window x:Class="UserManagementMVVM.UsersWindow"
        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:UserManagementMVVM"
        mc:Ignorable="d"
        Title="UsersWindow" Height="300" Width="300">
    <Window.Resources>
        <local:UserListViewModel x:Key="ViewModel"/>
    </Window.Resources>

    <Grid> <!-- data context removed from here, credit blindmeis -->
        <ListBox Margin="5" ItemsSource="{Binding userList}"/>
    </Grid>
</Window>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM