OneWayToSource mengikat dari properti hanya-baca di XAML

88

Saya mencoba mengikat ke Readonlyproperti dengan OneWayToSourcemode as, tetapi tampaknya ini tidak dapat dilakukan di XAML:

<controls:FlagThingy IsModified="{Binding FlagIsModified, 
                                          ElementName=container, 
                                          Mode=OneWayToSource}" />

Saya mendapat:

Properti 'FlagThingy.IsModified' tidak dapat disetel karena tidak memiliki pengakses kumpulan yang dapat diakses.

IsModifiedadalah readonly DependencyPropertypada FlagThingy. Saya ingin mengikat nilai itu ke FlagIsModifiedproperti di penampung.

Untuk lebih jelasnya:

FlagThingy.IsModified --> container.FlagIsModified
------ READONLY -----     ----- READWRITE --------

Apakah ini mungkin hanya dengan menggunakan XAML?


Pembaruan: Ya, saya memperbaiki kasus ini dengan mengatur pengikatan pada wadah dan bukan pada FlagThingy. Tapi saya masih ingin tahu apakah ini mungkin.

Inferis
sumber
Tapi bagaimana Anda bisa menetapkan nilai ke properti hanya baca?
idursun
3
Tidak boleh. Itu juga bukan apa yang saya coba capai. Saya mencoba mendapatkan FROM properti readonly IsModifiedke properti readwrite FlagIsModified.
Inferis
Pertanyaan bagus. Solusi Anda hanya berfungsi jika penampung adalah DependencyObject dan FlagIsModified adalah DependencyProperty.
Josh G
10
Pertanyaan bagus, namun saya gagal memahami jawaban yang diterima. Saya akan menghargai jika beberapa guru WPF dapat mencerahkan saya lagi - Apakah ini bug atau per desain?
Oskar
@Oskar menurut ini itu bug. tidak ada perbaikan yang terlihat.
pengguna1151923

Jawaban:

46

Beberapa hasil penelitian untuk OneWayToSource ...

Pilihan 1.

// Control definition
public partial class FlagThingy : UserControl
{
    public static readonly DependencyProperty IsModifiedProperty = 
            DependencyProperty.Register("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());
}
<controls:FlagThingy x:Name="_flagThingy" />
// Binding Code
Binding binding = new Binding();
binding.Path = new PropertyPath("FlagIsModified");
binding.ElementName = "container";
binding.Mode = BindingMode.OneWayToSource;
_flagThingy.SetBinding(FlagThingy.IsModifiedProperty, binding);

Pilihan 2

// Control definition
public partial class FlagThingy : UserControl
{
    public static readonly DependencyProperty IsModifiedProperty = 
            DependencyProperty.Register("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());

    public bool IsModified
    {
        get { return (bool)GetValue(IsModifiedProperty); }
        set { throw new Exception("An attempt ot modify Read-Only property"); }
    }
}
<controls:FlagThingy IsModified="{Binding Path=FlagIsModified, 
    ElementName=container, Mode=OneWayToSource}" />

Opsi # 3 (Properti ketergantungan hanya baca yang sebenarnya)

System.ArgumentException: Properti 'IsModified' tidak dapat terikat data.

// Control definition
public partial class FlagThingy : UserControl
{
    private static readonly DependencyPropertyKey IsModifiedKey =
        DependencyProperty.RegisterReadOnly("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());

    public static readonly DependencyProperty IsModifiedProperty = 
        IsModifiedKey.DependencyProperty;
}
<controls:FlagThingy x:Name="_flagThingy" />
// Binding Code
Same binding code...

Reflector memberikan jawabannya:

internal static BindingExpression CreateBindingExpression(DependencyObject d, DependencyProperty dp, Binding binding, BindingExpressionBase parent)
{
    FrameworkPropertyMetadata fwMetaData = dp.GetMetadata(d.DependencyObjectType) as FrameworkPropertyMetadata;
    if (((fwMetaData != null) && !fwMetaData.IsDataBindingAllowed) || dp.ReadOnly)
    {
        throw new ArgumentException(System.Windows.SR.Get(System.Windows.SRID.PropertyNotBindable, new object[] { dp.Name }), "dp");
    }
 ....
alex2k8.dll
sumber
30
Jadi itu bug, sebenarnya.
Inferis
Riset yang bagus. Jika Anda tidak membeberkannya dengan baik di sini, saya akan menempuh jalan yang sama dan menyakitkan itu. Setuju dengan @Inferis.
kevinarpe
1
Apakah ini bug? Mengapa pengikatan OneWayToSource tidak diizinkan dengan DependencyProperty hanya-baca?
Alex Hope O'Connor
Ini bukan bug. Itu dengan desain dan didokumentasikan dengan baik. Itu karena cara kerja mesin pengikat dalam hubungannya dengan sistem properti ketergantungan (target pengikatan harus berupa DependencyPropertyDP). DP hanya-baca hanya dapat dimodifikasi menggunakan yang terkait DependencyPropertyKey. Untuk mendaftarkan BindingExpressionmesin harus memanipulasi meta data DP target. Karena DependencyPropertyKeydianggap privat untuk menjamin perlindungan tulis publik, mesin harus mengabaikan kunci ini sehingga tidak dapat mendaftarkan pengikatan pada DP hanya-baca.
BionicCode
23

Ini adalah batasan WPF dan memang dirancang. Ini dilaporkan di Connect di sini:
OneWayToSource mengikat dari properti ketergantungan hanya-baca

Saya membuat solusi untuk secara dinamis dapat mendorong properti ketergantungan hanya-baca ke sumber bernama PushBindingyang saya blogkan di sini . Contoh di bawah ini melakukan OneWayToSourceBinding dari DP read-only ActualWidthdan ActualHeightke properti Width dan Height dariDataContext

<TextBlock Name="myTextBlock">
    <pb:PushBindingManager.PushBindings>
        <pb:PushBinding TargetProperty="ActualHeight" Path="Height"/>
        <pb:PushBinding TargetProperty="ActualWidth" Path="Width"/>
    </pb:PushBindingManager.PushBindings>
</TextBlock>

PushBindingbekerja dengan menggunakan dua Properti Ketergantungan, Pendengar dan Cermin. Listener terikat OneWayke TargetProperty dan di PropertyChangedCallbackdalamnya memperbarui properti Mirror yang terikat OneWayToSourceke apa pun yang ditentukan di Binding.

Proyek Demo dapat Diunduh Disini.
Ini berisi kode sumber dan penggunaan sampel singkat.

Fredrik Hedblad
sumber
Menarik! Saya datang dengan solusi serupa dan menyebutnya "Conduit" - Conduit memiliki dua properti ketergantungan sesuai desain Anda dan dua binding terpisah. Kasus penggunaan yang saya miliki adalah mengikat properti lama biasa ke properti lama biasa di XAML.
Daniel Paull
3
Saya melihat bahwa tautan MS Connect Anda tidak berfungsi lagi. Apakah ini berarti MS telah memperbaikinya di versi .NET yang lebih baru atau mereka baru saja menghapusnya?
Tiny
@Tiny Connect tampaknya akhirnya ditinggalkan, sayangnya. Itu terkait dengan di banyak tempat. Saya tidak berpikir itu secara khusus menyiratkan apa pun tentang apakah suatu masalah telah diperbaiki.
UuDdLrLrSs
5

Tulis ini:

Pemakaian:

<TextBox Text="{Binding Text}"
         p:OneWayToSource.Bind="{p:Paths From={x:Static Validation.HasErrorProperty},
                                         To=SomeDataContextProperty}" />

Kode:

using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

public static class OneWayToSource
{
    public static readonly DependencyProperty BindProperty = DependencyProperty.RegisterAttached(
        "Bind",
        typeof(ProxyBinding),
        typeof(OneWayToSource),
        new PropertyMetadata(default(Paths), OnBindChanged));

    public static void SetBind(this UIElement element, ProxyBinding value)
    {
        element.SetValue(BindProperty, value);
    }

    [AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(UIElement))]
    public static ProxyBinding GetBind(this UIElement element)
    {
        return (ProxyBinding)element.GetValue(BindProperty);
    }

    private static void OnBindChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((ProxyBinding)e.OldValue)?.Dispose();
    }

    public class ProxyBinding : DependencyObject, IDisposable
    {
        private static readonly DependencyProperty SourceProxyProperty = DependencyProperty.Register(
            "SourceProxy",
            typeof(object),
            typeof(ProxyBinding),
            new PropertyMetadata(default(object), OnSourceProxyChanged));

        private static readonly DependencyProperty TargetProxyProperty = DependencyProperty.Register(
            "TargetProxy",
            typeof(object),
            typeof(ProxyBinding),
            new PropertyMetadata(default(object)));

        public ProxyBinding(DependencyObject source, DependencyProperty sourceProperty, string targetProperty)
        {
            var sourceBinding = new Binding
            {
                Path = new PropertyPath(sourceProperty),
                Source = source,
                Mode = BindingMode.OneWay,
            };

            BindingOperations.SetBinding(this, SourceProxyProperty, sourceBinding);

            var targetBinding = new Binding()
            {
                Path = new PropertyPath($"{nameof(FrameworkElement.DataContext)}.{targetProperty}"),
                Mode = BindingMode.OneWayToSource,
                Source = source
            };

            BindingOperations.SetBinding(this, TargetProxyProperty, targetBinding);
        }

        public void Dispose()
        {
            BindingOperations.ClearAllBindings(this);
        }

        private static void OnSourceProxyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.SetCurrentValue(TargetProxyProperty, e.NewValue);
        }
    }
}

[MarkupExtensionReturnType(typeof(OneWayToSource.ProxyBinding))]
public class Paths : MarkupExtension
{
    public DependencyProperty From { get; set; }

    public string To { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
        var targetObject = (UIElement)provideValueTarget.TargetObject;
        return new OneWayToSource.ProxyBinding(targetObject, this.From, this.To);
    }
}

Belum mengujinya dalam gaya dan template, tebak perlu casing khusus.

Johan Larsson
sumber
2

Berikut adalah solusi properti terlampir lainnya berdasarkan SizeObserver yang dirinci di sini Mendorong properti GUI hanya-baca kembali ke ViewModel

public static class MouseObserver
{
    public static readonly DependencyProperty ObserveProperty = DependencyProperty.RegisterAttached(
        "Observe",
        typeof(bool),
        typeof(MouseObserver),
        new FrameworkPropertyMetadata(OnObserveChanged));

    public static readonly DependencyProperty ObservedMouseOverProperty = DependencyProperty.RegisterAttached(
        "ObservedMouseOver",
        typeof(bool),
        typeof(MouseObserver));


    public static bool GetObserve(FrameworkElement frameworkElement)
    {
        return (bool)frameworkElement.GetValue(ObserveProperty);
    }

    public static void SetObserve(FrameworkElement frameworkElement, bool observe)
    {
        frameworkElement.SetValue(ObserveProperty, observe);
    }

    public static bool GetObservedMouseOver(FrameworkElement frameworkElement)
    {
        return (bool)frameworkElement.GetValue(ObservedMouseOverProperty);
    }

    public static void SetObservedMouseOver(FrameworkElement frameworkElement, bool observedMouseOver)
    {
        frameworkElement.SetValue(ObservedMouseOverProperty, observedMouseOver);
    }

    private static void OnObserveChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var frameworkElement = (FrameworkElement)dependencyObject;
        if ((bool)e.NewValue)
        {
            frameworkElement.MouseEnter += OnFrameworkElementMouseOverChanged;
            frameworkElement.MouseLeave += OnFrameworkElementMouseOverChanged;
            UpdateObservedMouseOverForFrameworkElement(frameworkElement);
        }
        else
        {
            frameworkElement.MouseEnter -= OnFrameworkElementMouseOverChanged;
            frameworkElement.MouseLeave -= OnFrameworkElementMouseOverChanged;
        }
    }

    private static void OnFrameworkElementMouseOverChanged(object sender, MouseEventArgs e)
    {
        UpdateObservedMouseOverForFrameworkElement((FrameworkElement)sender);
    }

    private static void UpdateObservedMouseOverForFrameworkElement(FrameworkElement frameworkElement)
    {
        frameworkElement.SetCurrentValue(ObservedMouseOverProperty, frameworkElement.IsMouseOver);
    }
}

Deklarasikan properti terlampir dalam kontrol

<ListView ItemsSource="{Binding SomeGridItems}"                             
     ut:MouseObserver.Observe="True"
     ut:MouseObserver.ObservedMouseOver="{Binding IsMouseOverGrid, Mode=OneWayToSource}">    
jv_
sumber
1

Berikut adalah implementasi lain untuk mengikat ke Validation.HasError

public static class OneWayToSource
{
    public static readonly DependencyProperty BindingsProperty = DependencyProperty.RegisterAttached(
        "Bindings",
        typeof(OneWayToSourceBindings),
        typeof(OneWayToSource),
        new PropertyMetadata(default(OneWayToSourceBindings), OnBinidngsChanged));

    public static void SetBindings(this FrameworkElement element, OneWayToSourceBindings value)
    {
        element.SetValue(BindingsProperty, value);
    }

    [AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(FrameworkElement))]
    public static OneWayToSourceBindings GetBindings(this FrameworkElement element)
    {
        return (OneWayToSourceBindings)element.GetValue(BindingsProperty);
    }

    private static void OnBinidngsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((OneWayToSourceBindings)e.OldValue)?.ClearValue(OneWayToSourceBindings.ElementProperty);
        ((OneWayToSourceBindings)e.NewValue)?.SetValue(OneWayToSourceBindings.ElementProperty, d);
    }
}

public class OneWayToSourceBindings : FrameworkElement
{
    private static readonly PropertyPath DataContextPath = new PropertyPath(nameof(DataContext));
    private static readonly PropertyPath HasErrorPath = new PropertyPath($"({typeof(Validation).Name}.{Validation.HasErrorProperty.Name})");
    public static readonly DependencyProperty HasErrorProperty = DependencyProperty.Register(
        nameof(HasError),
        typeof(bool),
        typeof(OneWayToSourceBindings),
        new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    internal static readonly DependencyProperty ElementProperty = DependencyProperty.Register(
        "Element",
        typeof(UIElement),
        typeof(OneWayToSourceBindings),
        new PropertyMetadata(default(UIElement), OnElementChanged));

    private static readonly DependencyProperty HasErrorProxyProperty = DependencyProperty.RegisterAttached(
        "HasErrorProxy",
        typeof(bool),
        typeof(OneWayToSourceBindings),
        new PropertyMetadata(default(bool), OnHasErrorProxyChanged));

    public bool HasError
    {
        get { return (bool)this.GetValue(HasErrorProperty); }
        set { this.SetValue(HasErrorProperty, value); }
    }

    private static void OnHasErrorProxyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        d.SetCurrentValue(HasErrorProperty, e.NewValue);
    }

    private static void OnElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue == null)
        {
            BindingOperations.ClearBinding(d, DataContextProperty);
            BindingOperations.ClearBinding(d, HasErrorProxyProperty);
        }
        else
        {
            var dataContextBinding = new Binding
                                         {
                                             Path = DataContextPath,
                                             Mode = BindingMode.OneWay,
                                             Source = e.NewValue
                                         };
            BindingOperations.SetBinding(d, DataContextProperty, dataContextBinding);

            var hasErrorBinding = new Binding
                                      {
                                          Path = HasErrorPath,
                                          Mode = BindingMode.OneWay,
                                          Source = e.NewValue
                                      };
            BindingOperations.SetBinding(d, HasErrorProxyProperty, hasErrorBinding);
        }
    }
}

Penggunaan di xaml

<StackPanel>
    <TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}">
        <local:OneWayToSource.Bindings>
            <local:OneWayToSourceBindings HasError="{Binding HasError}" />
        </local:OneWayToSource.Bindings>
    </TextBox>
    <CheckBox IsChecked="{Binding HasError, Mode=OneWay}" />
</StackPanel>

Implementasi ini khusus untuk mengikat Validation.HasError

Johan Larsson
sumber
0

WPF tidak akan menggunakan penyetel properti CLR, tetapi tampaknya melakukan beberapa validasi aneh berdasarkan itu.

Mungkin dalam situasi Anda ini bisa baik-baik saja:

    public bool IsModified
    {
        get { return (bool)GetValue(IsModifiedProperty); }
        set { throw new Exception("An attempt ot modify Read-Only property"); }
    }
alex2k8.dll
sumber
1
Properti CLR tidak digunakan dalam kasus ini.
Inferis
Apakah yang Anda maksud Anda baru saja mendefinisikan DependencyProperty dan dapat menulis <kontrol: FlagThingy IsModified = "..." />? Bagi saya itu mengatakan: "Properti 'IsModified' tidak ada dalam namespace XML" jika saya tidak menambahkan properti CLR.
alex2k8
1
Saya percaya waktu desain menggunakan properti clr di mana runtime sebenarnya langsung menuju ke properti ketergantungan (jika itu adalah salah satu).
meandmycode
Properti CLR tidak diperlukan dalam kasus saya (saya tidak menggunakan IsModified dari kode), tetapi tetap ada (hanya dengan penyetel publik). Baik waktu desain maupun waktu proses berfungsi dengan baik hanya dengan registrasi properti ketergantungan.
Inferis
Pengikatan itu sendiri tidak menggunakan properti CLR, tetapi ketika Anda menentukan pengikatan di XAML, pengikatan itu harus diterjemahkan ke dalam kode. Saya kira pada tahap ini pengurai XAML melihat bahwa properti IsModified hanya-baca, dan melempar pengecualian (bahkan sebelum pengikatan dibuat).
alex2k8
0

Hmmm ... Saya tidak yakin saya setuju dengan salah satu solusi ini. Bagaimana dengan menentukan panggilan balik koersi dalam pendaftaran properti Anda yang mengabaikan perubahan eksternal? Misalnya, saya perlu menerapkan properti dependensi Posisi hanya-baca untuk mendapatkan posisi kontrol MediaElement di dalam kontrol pengguna. Begini cara saya melakukannya:

    public static readonly DependencyProperty PositionProperty = DependencyProperty.Register("Position", typeof(double), typeof(MediaViewer),
        new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, OnPositionChanged, OnPositionCoerce));

    private static void OnPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ctrl = d as MediaViewer;
    }

    private static object OnPositionCoerce(DependencyObject d, object value)
    {
        var ctrl = d as MediaViewer;
        var position = ctrl.MediaRenderer.Position.TotalSeconds;

        if (ctrl.MediaRenderer.NaturalDuration.HasTimeSpan == false)
            return 0d;
        else
            return Math.Min(position, ctrl.Duration);
    }

    public double Position
    {
        get { return (double)GetValue(PositionProperty); }
        set { SetValue(PositionProperty, value); }
    }

Dengan kata lain, abaikan saja perubahan dan kembalikan nilai yang didukung oleh anggota lain yang tidak memiliki pengubah publik. - Dalam contoh di atas, MediaRenderer sebenarnya adalah kontrol MediaElement pribadi.

Mario
sumber
Sayang sekali ini tidak berfungsi untuk properti kelas BCL yang telah ditentukan sebelumnya: - /
ATAU Pembuat Peta
0

Cara saya mengatasi batasan ini adalah dengan hanya mengekspos properti Binding di kelas saya, menjaga DependencyProperty tetap pribadi sama sekali. Saya menerapkan properti hanya-tulis "PropertyBindingToSource" (yang ini bukan DependencyProperty) yang dapat disetel ke nilai yang mengikat di xaml. Dalam penyetel untuk properti hanya-tulis ini saya memanggil BindingOperations.SetBinding untuk menautkan pengikatan ke DependencyProperty.

Untuk contoh spesifik OP, akan terlihat seperti ini:

Implementasi FlatThingy:

public partial class FlatThingy : UserControl
{
    public FlatThingy()
    {
        InitializeComponent();
    }

    public Binding IsModifiedBindingToSource
    {
        set
        {
            if (value?.Mode != BindingMode.OneWayToSource)
            {
                throw new InvalidOperationException("IsModifiedBindingToSource must be set to a OneWayToSource binding");
            }

            BindingOperations.SetBinding(this, IsModifiedProperty, value);
        }
    }

    public bool IsModified
    {
        get { return (bool)GetValue(IsModifiedProperty); }
        private set { SetValue(IsModifiedProperty, value); }
    }

    private static readonly DependencyProperty IsModifiedProperty =
        DependencyProperty.Register("IsModified", typeof(bool), typeof(FlatThingy), new PropertyMetadata(false));

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        IsModified = !IsModified;
    }
}

Perhatikan bahwa objek DependencyProperty hanya baca statis bersifat privat. Dalam kontrol saya menambahkan tombol yang kliknya ditangani oleh Button_Click. Penggunaan kontrol FlatThingy di window.xaml saya:

<Window x:Class="ReadOnlyBinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ReadOnlyBinding"
    mc:Ignorable="d"
    DataContext="{x:Static local:ViewModel.Instance}"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>

    <TextBlock Text="{Binding FlagIsModified}" Grid.Row="0" />
    <local:FlatThingy IsModifiedBindingToSource="{Binding FlagIsModified, Mode=OneWayToSource}" Grid.Row="1" />
</Grid>

Perhatikan bahwa saya juga telah menerapkan ViewModel untuk mengikat yang tidak ditampilkan di sini. Ini mengekspos DependencyProperty bernama "FlagIsModified" seperti yang Anda dapat dari sumber di atas.

Ini berfungsi dengan baik, memungkinkan saya untuk mendorong informasi kembali ke ViewModel dari View dengan cara yang digabungkan secara longgar, dengan arah aliran informasi yang ditentukan secara eksplisit.

John Thoits
sumber
-1

Anda melakukan pengikatan ke arah yang salah sekarang. OneWayToSource akan mencoba dan memperbarui FlagIsModified pada penampung setiap kali IsModified berubah pada kontrol yang Anda buat. Anda menginginkan sebaliknya, yaitu membuat IsModified mengikat ke container.FlagIsModified. Untuk itu sebaiknya gunakan mode binding OneWay

<controls:FlagThingy IsModified="{Binding FlagIsModified, 
                                          ElementName=container, 
                                          Mode=OneWay}" />

Daftar lengkap anggota enumerasi: http://msdn.microsoft.com/en-us/library/system.windows.data.bindingmode.aspx

JaredPar
sumber
5
Tidak, saya ingin persis skenario yang Anda gambarkan yang tidak ingin saya lakukan. FlagThingy.IsModified -> container.FlagIsModified
Inferis
3
Ditandai karena penanya memiliki pertanyaan yang ambigus tampaknya terlalu berlebihan.
JaredPar
6
@ JaredPar: Saya tidak melihat apa yang meragukan tentang pertanyaan itu. Pertanyaannya menyatakan bahwa 1) ada properti ketergantungan hanya-baca IsIsModified, bahwa 2) OP ingin mendeklarasikan pengikatan pada properti itu di XAML dan bahwa 3) pengikatan seharusnya bekerja dalam OneWayToSourcemode. Solusi Anda tidak berfungsi secara praktis karena, seperti yang dijelaskan dalam pertanyaan, compiler tidak akan mengizinkan Anda mendeklarasikan pengikatan pada properti hanya-baca, dan tidak berfungsi secara konseptual karena IsModifiedbersifat hanya-baca dan karenanya nilainya tidak dapat diubah (dengan mengikat).
ATAU Mapper