Ya, saya pernah melakukan ini dengan properti ActualWidth
dan ActualHeight
, yang keduanya hanya dapat dibaca. Saya membuat perilaku terlampir yang memiliki ObservedWidth
dan ObservedHeight
melampirkan properti. Ia juga memiliki Observe
properti yang digunakan untuk melakukan hook-up awal. Penggunaannya terlihat seperti ini:
<UserControl ...
SizeObserver.Observe="True"
SizeObserver.ObservedWidth="{Binding Width, Mode=OneWayToSource}"
SizeObserver.ObservedHeight="{Binding Height, Mode=OneWayToSource}"
Jadi model tampilan memiliki Width
dan Height
properti yang selalu sinkron dengan ObservedWidth
danObservedHeight
melekat sifat. The Observe
properti hanya menempel pada SizeChanged
acara dari FrameworkElement
. Di pegangan, itu memperbarui ObservedWidth
dan ObservedHeight
propertinya. Ergo, yang Width
dan Height
dari model tampilan selalu sinkron dengan ActualWidth
dan ActualHeight
dari UserControl
.
Mungkin bukan solusi yang tepat (saya setuju - DP hanya-baca harus mendukung OneWayToSource
binding), tetapi berfungsi dan menjunjung tinggi pola MVVM. Jelas, ObservedWidth
dan ObservedHeight
DP tidak hanya bisa dibaca.
PEMBARUAN: berikut ini kode yang menerapkan fungsionalitas yang dijelaskan di atas:
public static class SizeObserver
{
public static readonly DependencyProperty ObserveProperty = DependencyProperty.RegisterAttached(
"Observe",
typeof(bool),
typeof(SizeObserver),
new FrameworkPropertyMetadata(OnObserveChanged));
public static readonly DependencyProperty ObservedWidthProperty = DependencyProperty.RegisterAttached(
"ObservedWidth",
typeof(double),
typeof(SizeObserver));
public static readonly DependencyProperty ObservedHeightProperty = DependencyProperty.RegisterAttached(
"ObservedHeight",
typeof(double),
typeof(SizeObserver));
public static bool GetObserve(FrameworkElement frameworkElement)
{
frameworkElement.AssertNotNull("frameworkElement");
return (bool)frameworkElement.GetValue(ObserveProperty);
}
public static void SetObserve(FrameworkElement frameworkElement, bool observe)
{
frameworkElement.AssertNotNull("frameworkElement");
frameworkElement.SetValue(ObserveProperty, observe);
}
public static double GetObservedWidth(FrameworkElement frameworkElement)
{
frameworkElement.AssertNotNull("frameworkElement");
return (double)frameworkElement.GetValue(ObservedWidthProperty);
}
public static void SetObservedWidth(FrameworkElement frameworkElement, double observedWidth)
{
frameworkElement.AssertNotNull("frameworkElement");
frameworkElement.SetValue(ObservedWidthProperty, observedWidth);
}
public static double GetObservedHeight(FrameworkElement frameworkElement)
{
frameworkElement.AssertNotNull("frameworkElement");
return (double)frameworkElement.GetValue(ObservedHeightProperty);
}
public static void SetObservedHeight(FrameworkElement frameworkElement, double observedHeight)
{
frameworkElement.AssertNotNull("frameworkElement");
frameworkElement.SetValue(ObservedHeightProperty, observedHeight);
}
private static void OnObserveChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var frameworkElement = (FrameworkElement)dependencyObject;
if ((bool)e.NewValue)
{
frameworkElement.SizeChanged += OnFrameworkElementSizeChanged;
UpdateObservedSizesForFrameworkElement(frameworkElement);
}
else
{
frameworkElement.SizeChanged -= OnFrameworkElementSizeChanged;
}
}
private static void OnFrameworkElementSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateObservedSizesForFrameworkElement((FrameworkElement)sender);
}
private static void UpdateObservedSizesForFrameworkElement(FrameworkElement frameworkElement)
{
// WPF 4.0 onwards
frameworkElement.SetCurrentValue(ObservedWidthProperty, frameworkElement.ActualWidth);
frameworkElement.SetCurrentValue(ObservedHeightProperty, frameworkElement.ActualHeight);
// WPF 3.5 and prior
////SetObservedWidth(frameworkElement, frameworkElement.ActualWidth);
////SetObservedHeight(frameworkElement, frameworkElement.ActualHeight);
}
}
Size
properti, menggabungkan Tinggi dan Lebar. Approx. 50% lebih sedikit kode.ActualSize
properti di dalamnyaFrameworkElement
. Jika Anda ingin mengikat langsung properti terlampir, Anda harus membuat dua properti yang akan diikatActualWidth
danActualHeight
masing - masing.Saya menggunakan solusi universal yang tidak hanya berfungsi dengan ActualWidth dan ActualHeight, tetapi juga dengan data apa pun yang dapat Anda ikat setidaknya dalam mode membaca.
Markupnya terlihat seperti ini, asalkan ViewportWidth dan ViewportHeight adalah properti model tampilan
Berikut ini kode sumber untuk elemen khusus
sumber
Target
properti tersebut harus dibuat dapat ditulisi meskipun tidak boleh diubah dari luar: - /Jika ada orang lain yang tertarik, saya membuat perkiraan solusi Kent di sini:
Jangan ragu untuk menggunakannya di aplikasi Anda. Ini bekerja dengan baik. (Terima kasih Kent!)
sumber
Berikut adalah solusi lain untuk "bug" ini yang saya tulis di blog:
Pengikatan OneWayToSource untuk Properti Ketergantungan ReadOnly
Ia bekerja dengan menggunakan dua Properti Ketergantungan, Pendengar dan Cermin. Pemroses mengikat OneWay ke TargetProperty dan di PropertyChangedCallback, pemroses memperbarui properti Mirror yang mengikat OneWayToSource ke apa pun yang ditentukan di Binding. Saya menyebutnya
PushBinding
dan dapat disetel pada Properti Ketergantungan hanya-baca seperti iniUnduh Proyek Demo Disini .
Ini berisi kode sumber dan penggunaan sampel singkat, atau kunjungi blog WPF saya jika Anda tertarik dengan detail implementasi.
Satu catatan terakhir, sejak .NET 4.0 kami bahkan lebih jauh dari dukungan bawaan untuk ini, karena Pengikatan OneWayToSource membaca nilai kembali dari Sumber setelah memperbaruinya
sumber
Saya suka solusi Dmitry Tashkinov! Namun itu menabrak VS saya dalam mode desain. Itu sebabnya saya menambahkan baris ke metode OnSourceChanged:
sumber
Saya pikir itu bisa dilakukan sedikit lebih sederhana:
xaml:
cs:
sumber