访问视图模型(ViewModel)从视图(View)的类中是否是不良实践?

huangapple go评论138阅读模式
英文:

Is it bad practice to access viewmodel from view's class?

问题

I am developing an app with .NET MAUI. For the desktop app, I am using each segment of the app for different data and such. I either had to use prism region navigation or try to do it with the built-in MAUI functions. I didn't use Prism, but the way I implemented the app meant that I often had to call viewmodel functions from view's class.

Is this bad? Right now, I can't think of another way, but if it is a critical problem, I will try to find another way before moving forward.

EDITED:

private async void DeleteButtonTapped(object sender, TappedEventArgs e)
{
    if (answer)
    {
        var bindingContext = BindingContext as AgentDetailsPageViewModel;
        await bindingContext.DeleteFromDatabase();
        var agentsViews = this.Parent as Grid;
        agentsViews.Remove(this);
        var parentBorder = agentsViews.Parent as Border;
        parentBorder.IsVisible = false;
        var parentGrid = parentBorder.Parent as Grid;
        var agentsBorder = parentGrid.Children[0] as Border;
        Grid.SetColumnSpan(agentsBorder, 2);
        var parentBindingContext = parentGrid.BindingContext as AgentsPageViewModel;
        parentBindingContext.Populate();
    }
}

For example, the code above is a situation where I am using the viewmodel in the view's class. I'm calling the delete database and populate methods from my viewmodel, but I'm not passing any data.

ObservableCollection<string> creditCardEntries = new ObservableCollection<string>();
foreach (var creditCardborderStack in creditCardbordersStack)
{
    var grid = creditCardborderStack.GetChildren<Grid>().FirstOrDefault();
    var entry = grid.GetChildren<Entry>().FirstOrDefault();
    if (entry.Text is not null)
    {
        if (entry.Text.ToCharArray()[4] != '-')
        {
            creditCardEntries.Add(Regex.Replace(entry.Text, @"(\w{4})(\w{4})(\w{4})(\w{4})", "$1-$2-$3-$4"));
        }
        else
        {
            creditCardEntries.Add(entry.Text);
        }
    }
}
var bindingContext = (AgentAddOrEditPageViewModel)BindingContext;
if (bindingContext.AgentCreditCardNumbers is not null)
{
    bindingContext.AgentCreditCardNumbers.Clear();
}
bindingContext.AgentCreditCardNumbers = creditCardEntries;
if (await bindingContext.AddToDatabase())
{
    CloseViewAfterInsertion();
}

This is another part of my code, and I'm very concerned about this part. Basically, the user can insert infinite credit card numbers. I could not figure out a way to bind them to the viewmodel because every time a user wants to add a new credit card, I create a textbox in the UI, and I could not generate the viewmodel property dynamically to bind it to the textbox.

Now, if you look at my code, you can see that I search through the UI to find the textboxes and get their values. I create a string collection and pass the string collection to my viewmodel. After that, I get values and insert them into my CreditCard class, and I do the insertion.

I personally think this is not good, but I cannot figure out another way, so if you guys have a suggestion that might salvage this situation, I will be very grateful.

英文:

I am developing an app with.NET MAUI. For the desktop app, I am using each segment of the app for different data and such. I either had to use prism region navigation or try to do it with the built-in MAUI functions. I didn't use Prism, but the way I implemented the app meant that I often had to call viewmodel functions from view's class.

Is this bad? Right now, I can't think of another way, but if it is a critical problem, I will try to find another way before moving forward.

EDITED:

private async void DeleteButtonTapped(object sender, TappedEventArgs e)
{
    if (answer)
    {
        var bindingContext =  BindingContext as AgentDetailsPageViewModel;
        await bindingContext.DeleteFromDatabase();
        var agentsViews = this.Parent as Grid;
        agentsViews.Remove(this);
        var parentBorder = agentsViews.Parent as Border;
        parentBorder.IsVisible = false;
        var parentGrid = parentBorder.Parent as Grid;
        var agentsBorder = parentGrid.Children[0] as Border;
        Grid.SetColumnSpan(agentsBorder, 2);
        var parentBindingContext = parentGrid.BindingContext as AgentsPageViewModel;
        parentBindingContext.Populate();
    }
}

for example the code above is a situation that i am using the viewmodel in view's class. i'm calling the delete database and populate from my viewmodel but i'm not passing any data.

ObservableCollection&lt;string&gt; creditCardEntries = new ObservableCollection&lt;string&gt;();
foreach (var creditCardborderStack in creditCardbordersStack)
{
    var grid = creditCardborderStack.GetChildren&lt;Grid&gt;().FirstOrDefault();
    var entry = grid.GetChildren&lt;Entry&gt;().FirstOrDefault();
    if (entry.Text is not null)
    {
        if (entry.Text.ToCharArray()[4] != &#39;-&#39;)
        {
            creditCardEntries.Add(Regex.Replace(entry.Text, @&quot;(\w{4})(\w{4})(\w{4})(\w{4})&quot;, @&quot;$1-$2-$3-$4&quot;));
        }
        else
        {
            creditCardEntries.Add(entry.Text);
        }
    }
}
var bindingContext = (AgentAddOrEditPageViewModel)BindingContext;
if (bindingContext.AgentCreditCardNumbers is not null)
{
    bindingContext.AgentCreditCardNumbers.Clear();
}
bindingContext.AgentCreditCardNumbers = creditCardEntries;
if (await bindingContext.AddToDatabase())
{
    CloseViewAfterInsertion();
}

this is another part of my code and i'm very concerned about this part. basically user can insert infinite credit card numbers. I could not figure out a way to bind them to the viewmodel because eveytime a user wants too add a new credit card i create a textbox in the ui and i could not generate the viewmodel property dynamically to bind it to the textbox.

now if you look at my code you can see that i search through the ui the find the textboxes and get their values. i create a string collection and pass the string collection to my viewmodel. after that i get values and i insert them my CreditCard Class and i do the insertion.

I personally think this is not good but i cannot figure out another way so if you guys have suggestion that might salvage this situation i will be very greatfull.

答案1

得分: 4

要确定是否不好,您需要与我们分享更多信息,可能是访问看起来可能不好的示例。

但一般来说:

在MVVM中,视图访问ViewModel,而ViewModel访问Model。

V -> VM -> M

因此,不,从ViewModel访问View(为其创建的View)不是不好的做法。

但:

视图和ViewModel通常应该配对使用。而且,ViewModel不应包含实际的业务逻辑,而只应抽象出(一个)视图需要显示的内容,并将函数和操作委托给模型。

所以:如果您要访问一个与该视图无关的ViewModel,甚至使用可重用的ViewModel作为“模型访问包装器”,因为它已经具有您需要操作或读取模型的正确方法,那么这将是非常不正确的。

英文:

To see if its bad, you would have to share more information with us, maybe an example of how the access looks like, that you think might be bad.

But generally spoken:

In MVVM, the View accesses the ViewModel, and the ViewModel accesses the Model

V -&gt; VM -&gt; M

So no, it is not a bad practice to access the ViewModel from the View for which the ViewModel was made.

but:

The View and the ViewModel usually belong together. And, the ViewModel should contain no real business logic, but only abstracts the things that the (one) View has to display, and delegate functions and manipulations down to the model.

So: If you would access a ViewModel that does not belong to that View, or even use reusable ViewModels as "model-acess-wrappers", because it already has the correct methods you need to manipulate or read the model, then it would be very wrong.

huangapple
  • 本文由 发表于 2023年8月10日 19:21:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76875258.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定