Potrzebuje dobrze zrozumieć zasadę tworzenia i stosowania DependencyProperty
. Zacząłem dostawać zadanka rekrutacyjne gdzie są aspekty które najprawdopodobniej wymagają zastosowania własności zależnych, po mojej obecnej implementacji kontakt z rekruterem się urywa i wyciągam wniosek że w moim rozwiązaniu zadania "dzieje się mocno źle" ;).
W swojej wprawce wyciągnąłem sobie parę przypadków gdzie chciałbym je zastosować a które do tej pory sprawiają mi sporo problemów w WPF MVVM (w code behind to proste rzeczy)
Generalnie zadania z tej wprawki zrobiłem sobie takie:
Pierwszy punkt zrobiłem tak jak niżej i działa, pytanie czy to na tym polega?
Tyle ma być nadmiarowości w stosunku do code behind, czy tak to się robi?
Tworze klasę opakowującą klasyczny Button i dodaje w niej dwie właściwości zależne:
Założyłem ze będę to realizował w ten sposób ze dodam właściwość do przycisku trzymającą referencje do okna rodzica, i druga właściwość Boolean
, której zmiana na true wywoła metodę Close()
na referencji okna trzymanej w tej drugiej właściwości. Kod poniżej.
public class BtnZad1 : Button
{
public static readonly DependencyProperty BooleanZamykajacyProperty;
public static readonly DependencyProperty OknoRodzicBtnZad1Property;
static BtnZad1()
{
BooleanZamykajacyProperty = DependencyProperty
.Register("ZamknijOkno",
typeof(bool),
typeof(BtnZad1),
new PropertyMetadata(false, OnKlikniecieDoZamkniecia));
OknoRodzicBtnZad1Property =
DependencyProperty.Register(
"OknoRodzicBtnZad1",
typeof(Window),
typeof(BtnZad1),
new PropertyMetadata(null));
}
public Window OknoRodzicBtnZad1
{
get { return (Window)GetValue(OknoRodzicBtnZad1Property); }
set { SetValue(OknoRodzicBtnZad1Property, value); }
}
public bool ZamknijOkno
{
get { return (bool)GetValue(BooleanZamykajacyProperty); }
set { SetValue(BooleanZamykajacyProperty, value); }
}
static void OnKlikniecieDoZamkniecia(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as BtnZad1).OnKlikniecieDoZamkniecia(e);
}
void OnKlikniecieDoZamkniecia(DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is true && OknoRodzicBtnZad1 != null)
OknoRodzicBtnZad1.Close();
}
}
w Swoim ViewModelu okna głównego wystawiam właściwość Boolean którą powiążę ze swoją nowo utworzoną własnością zależną ustawiam ja na początku na (nie ustawiaj jej, bo dałem i tak wartość domyślną podczas rejestracji false), no i dodaje w ViewModelu obsługę polecenia które podpinam do tego klawisza.true
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string nazwaWlasciwosci)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nazwaWlasciwosci));
}
public ViewModel()
{
}
#region 1.
private bool czyZamknac;
public bool CzyZamknac
{
get { return czyZamknac; }
set
{
czyZamknac = value;
OnPropertyChanged(nameof(CzyZamknac));
}
}
private ICommand klikniecieZamykajace;
public ICommand KlikniecieZamykajace
{
get
{
if (klikniecieZamykajace == null)
klikniecieZamykajace = new RelayCommand(Zamknij);
return klikniecieZamykajace;
}
}
private void Zamknij(object o)
{
//jakies dzialania konieczne do zrobienia przed zamknieciem
CzyZamknac = true;
}
}
a w XAMLu definiuje wiązania w tym przycisku tak:
<local:BtnZad1 Grid.Row="0" Grid.Column="1"
OknoRodzicBtnZad1="{Binding ElementName=OknoRodzic}"
Command="{Binding KlikniecieZamykajace}"
ZamknijOkno="{Binding CzyZamknac}"
Width="120"
Height="30"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock Text="Zamknij okno"/>
</local:BtnZad1>
Rozwiązanie działa czyli warunek spełniony, ale czy tak się robi?
W analogiczny sposób robię pkt.4.
Z pkt.2. czyli przechwytywaniem tego klawisza Esc to mgliście mi chodzi po głowie ze chyba trzeba rozszerzyć klasę okno, tam dodać właściwość zależną trzymającą klawisz Key.Escape
, potem powiązać to poprzez Converter z właściwością boolean
z ViewModelu i obsługą polecenia zrobić tak samo?
Pk.3 i 5 tak samo jak pkt.2 tyle ze rozszerzam klawy TextBox i PasswordBox?