-1

Let me preface this by saying that I am currently learning WPF and the MVVM pattern, so my question might be self answering to more experienced developers.

What I have is a simple login form with a Textbox for the name and a PasswordBox for the password. The namebox is bound to the model, while the passwordbox is sent to the command as an entire object(since you can't bind to its text property). Then a button that executes the login command. Now when the login works it is ok, but my problem is how to send return feedback of the command failing without breaking the mvvm pattern. For example changing the border color of the fields to red.

My initial instinct is to have a property of the model, which I will change on failure. However I want to learn the proper way to do it instead of hacking a solution myself (defeating the purpose of the whole thing).

Bonus questions: - Can you bind a property to a statement - for example String.isNullOrEmpty(model.name) ? - Should I entirely abandon the MVVM pattern for such a simple operation (while the rest of the project will still be using it) > - What is a good resource to learn about WPF and MVVM ?

Code of the form bellow:

<Controls:MetroWindow x:Class="Interface_WPF.View.LoginWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
    Title="Enter" Height="140" Width="285" WindowStartupLocation="CenterScreen" WindowStyle="None" AllowsTransparency="True" ResizeMode="NoResize">
<StackPanel>
    <Grid FocusManager.FocusedElement="{Binding ElementName=NameBox}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="200" />
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0" Grid.Column="0" Content="Name:"/>
        <Label Grid.Row="1" Grid.Column="0" Content="Password:"/>
        <TextBox Grid.Column="1" Grid.Row="0" Margin="3"
                 Name="NameBox" Text="{Binding Login.Name, UpdateSourceTrigger=PropertyChanged}"/>
        <PasswordBox Grid.Column="1" Grid.Row="1" Margin="3"
                 Name="PasswordBox"/>
    </Grid>
    <Button Command="{Binding LoginCheck}" 
            CommandParameter="{Binding ElementName=PasswordBox}" 
            Style="{DynamicResource SquareButtonStyle}" IsDefault="True" Width="100" HorizontalAlignment="Right" Margin="0,8,7.8,8" Content="Enter"/>
</StackPanel>

  • "Can you bind a property to a statement - for example String.isNullOrEmpty(model.name)"? No, but you can write a [DataTrigger](https://msdn.microsoft.com/en-us/library/system.windows.datatrigger(v=vs.110).aspx). You're probably on the right lines with [breaking MVVM for the password](http://stackoverflow.com/a/1493330/424129). I would probably give the viewmodel a `String LoginError` property, with XAML styling so that when that property is not empty, it appears in red text in a Label. – 15ee8f99-57ff-4f92-890c-b56153 Jul 29 '16 at 15:51
  • 1
    For feedback, search for "wpf validation". Since you aren't binding to a property, you'll probably want to implement `IDataErrorInfo`. You can also use the approach you suggest. You can't bind to a method, but you can certainly use validation to call a method and set validation status based on the result, or expose a property that is re-evaluated, calling some method, whenever a dependent property changes. Your question as asked is very broad, and doesn't present any specific programming _problem_ that can be addressed. Please narrow the question if you want a good answer. – Peter Duniho Jul 29 '16 at 16:26
  • 2
    @PeterDuniho Vague understanding of the matter results in vague questions. My bad. By the way your answer gave me an idea so thank you anyway :) – Georgi Gamzakov Jul 29 '16 at 18:50
  • To add to @EdPlunkett's comment: You can also use value converters in XAML in order to return types based on an input binding. For example, you could create a `StringIsNullOrWhiteSpaceToBooleanConverter` (or anything similar meaningful), and bind a `boolean` attached property to a control (e.g. `IsEnabled`) based on the original binding and attaching the converter. See http://wpftutorial.net/ValueConverters.html for a nice tutorial on how to use Converters in WPF. FYI Same rules can be applied for WinRT and also Silverlight – Geoff James Jul 29 '16 at 22:55
  • @GeorgiGamzakov Is there any reason you're not just binding your `PasswordBox`'s text to a `Password` property on your `LoginViewModel`? You will still be able to use the property in the same way when your `LoginCheck` command is fired. Also, with your current implementation, your ViewModel will need to know something about the UI in so much that it *has* to accept a `PasswordBox` element type as a Command Parameter - if you were to ever re-use the ViewModel in another view (only as an example), you're tied to having to use a `PasswordBox` with that view – Geoff James Jul 29 '16 at 23:02
  • 1
    @GeoffJames PasswordBox.Password isn't a dependency property. Can't bind it. PasswordBox.SecurePassword isn't one either. – 15ee8f99-57ff-4f92-890c-b56153 Jul 30 '16 at 01:40

1 Answers1

1

There's no rule in MVVM about not having any code in the code-behind - you just don't want BUSINESS LOGIC in the code-behind. This is something that many newcomers to MVVM don't quite realize and it causes many headaches. You can put as much view logic in the code-behind as you want to handle things like feedback MessageBoxes, etc..

Now when you want to give specific feedback you generally do something like have the view execute a function in the viewmodel that returns a boolean, and if it returns false then display a messagebox with the content of a property in the viewmodel that has specific error data. There's a few different ways people like to handle these things.

Always remember MVVM isn't a religion, it's a tool to be used and you can bend it here and there where it suits you if that's what you want to do - you decide what is too much breaking of the layers or not.

Yushatak
  • 741
  • 1
  • 5
  • 15
  • FWIW, a View shouldn't really have much code behind (for user controls its normal and required), not even view logic related. It's still "hackish", hard to test and reuse. There are better ways, interactivity behaviors and actions, i.e. Prism uses a `PopupWindowAction` to allow opening a view in a popup from either code or xaml, w/o code behind – Tseng Jul 29 '16 at 17:33