Jak już wspominałem w jednym z postów, bardzo odpowiada mi pełna separacja UI od reszty kodu jaką zapewnia wzorzec MVVM i doceniam w pełni jego zalety. Czasem jednak pojawia się klasyczne „g..no w szprychy” podczas jakieś prostej do wykonania w code-behind czynności.
Dzisiaj, podczas pracy nad desktopową aplikacją do robota pojawił się problem z bindigiem hasła z PasswordBox-a. O ile w przypadku TextBox-a nie ma z tym żadnego problemu, to w przypadku PasswordBox własność Password nie jest własnością zależną (DependencyProperty) więc zwykły binding nie wchodzi w grę.
Microsoft tłumaczy, że takie rozwiązanie podyktowane jest względami bezpieczeństwa. Jest to sensowne wytłumaczenie, ze względu na to, że własności zależne są zarządzane centralnie i w konsekwencji tego stają się one publiczne. W związku z tym faktem hasło trzymane jest w zmiennej typu SecureString. Niestety PasswordBox nie zezwala też na dostęp do tej zmiennej – a szkoda, bo binding mógłby być wtedy dużo prostszy przy zachowaniu hasła nadal w postaci zakodowanej.
Nie mniej jednak problem trzeba jakoś rozwiązać. Zacząłem poszukiwania i po przebrnięciu przez sporo propozycji (z ogromną ilością kodu – jak to zwykle w takich przypadkach w MVVM) znalazłem rozwiązanie satysfakcjonujące w tym blog poście.
Rozwiązanie polega na przygotowaniu dodatkowej klasy wspomagającej binding hasła za pomocą własności dołączanych. To rozwiązanie jest o tyle fajne, że klasę można z powodzeniem użyć w kolejnych projektach, a nie wymaga też ono dużo dodatkowego kodu Xaml.
Pełny kod klasy jest oczywiście dostępny w poście podlinkowanym powyżej, natomiast wykorzystanie jest bardzo proste:
<PasswordBox Name="NetworkPassword" controls:TextBoxHelper.Watermark="Network password" viewHelpers:PasswordBoxAssistant.BindPassword="true" viewHelpers:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Oczywiście w ViewModel-u trzeba utworzyć publiczną własność, którą będziemy bindować.