簡體   English   中英

更改附加屬性的綁定源

[英]Change Source of Binding for attached property

如果我在附加屬性中使用綁定擴展

<TextBlock local:MyBehavior.View="{Binding A}" /> <!-- or B -->

如何從該附加行為設置ViewModel的A (或B )屬性的值?

我不明白:

  1. 附加屬性使用哪種類型? Binding BindingBase BindingExpressionBase object
  2. 我應該立即設置值嗎? 我要等什么嗎? 我是否應該使用另一個依賴項屬性來設置其值,然后綁定到SomeProperty並在設置DataContext讓綁定完成該工作?

我的嘗試失敗 ,為方便起見,我在下面復制了它:

public class MyBehavior
{
    public static BindingBase GetView(DependencyObject obj) => (BindingBase)obj.GetValue(ViewProperty);
    public static void SetView(DependencyObject obj, BindingBase value) => obj.SetValue(ViewProperty, value);
    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.RegisterAttached("View", typeof(BindingBase), typeof(MyBehavior), new PropertyMetadata(null, (d, e) =>
        {
            var element = d as FrameworkElement;
            if (element == null)
                throw new ArgumentException("Only used with FrameworkElement");
            element.Loaded += (s, a) => GetView(element); // <<
        }));
}

我不確定在標記行設置綁定屬性給定值的操作:

public class ViewModel
{
    public object A { get; set; }
    public object B { get; set; }
}

附加屬性使用哪種類型?

與您在視圖模型中定義source屬性的類型相同,即object或附加屬性應存儲的任何類型的值。 類型取決於您打算在附加屬性中存儲的值的類型。

我應該立即設置值嗎

注冊依賴項屬性時,可以為其指定默認值。 引用類型(例如object)的默認值通常為null

public class MyBehavior
{
    public static object GetView(DependencyObject obj) => obj.GetValue(ViewProperty);
    public static void SetView(DependencyObject obj, object value) => obj.SetValue(ViewProperty, value);

    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.RegisterAttached("View", typeof(object), typeof(MyBehavior), 
            new PropertyMetadata(/*default value: */ null, new PropertyChangedCallback(OnPropertyChanged)));

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        //...
    }
}

當您綁定到視圖模型時,依賴屬性的值將像其他任何依賴屬性一樣自動設置,例如:

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }

    public object A { get; set; } = "value...";
}

MainWindow.xaml:

<TextBlock local:MyBehavior.View="{Binding A}" />

public class MyBehavior
{
    public static object GetView(DependencyObject obj) => obj.GetValue(ViewProperty);
    public static void SetView(DependencyObject obj, object value) => obj.SetValue(ViewProperty, value);

    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.RegisterAttached("View", typeof(object), typeof(MyBehavior), 
            new PropertyMetadata(/*default value: */ null, new PropertyChangedCallback(OnPropertyChanged)));

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        object theValue = GetView(d);
        MessageBox.Show(theValue.ToString());
    }
}

如果希望將視圖模型屬性設置為附加屬性的值,則應將綁定的模式設置為OneWayToSource

<TextBlock x:Name local:MyBehavior.View="{Binding A, Mode=OneWayToSource}" />

但是隨后是更新視圖模型的視圖:

public MainWindow()
{
    InitializeComponent();
    DataContext = this;

    MyBehavior.SetView(txt, "new value...");
}

附加的依賴項屬性本身就是可以在任何DependencyObject上設置的另一個依賴項屬性。

編輯:

該解決方案仍然需要代碼隱藏,我的意圖是通過附加行為來消除它。 有想法嗎? 注意element.Loaded(另請參閱我對@dymanoid的評論),想法是從附加行為中設置值,並且僅使用綁定來傳遞源(定義哪個屬性A或B應該獲得該值)。

然后,您可以簡單地將附加屬性設置為源屬性的名稱:

<TextBlock local:MyBehavior.View="A" />

...並使用反射在您附加的行為中設置此source屬性的值:

public class MyBehavior
{
    public static object GetView(DependencyObject obj) => obj.GetValue(ViewProperty);
    public static void SetView(DependencyObject obj, object value) => obj.SetValue(ViewProperty, value);

    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.RegisterAttached("View", typeof(object), typeof(MyBehavior), 
            new PropertyMetadata(/*default value: */ null, new PropertyChangedCallback(OnPropertyChanged)));

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var element = d as FrameworkElement;
        if (element == null)
            throw new ArgumentException("Only used with FrameworkElement");
        element.Loaded += (s, a) => 
        {
            string propertyName = GetView(element).ToString();
            if(element.DataContext != null)
            {
                System.Reflection.PropertyInfo pi = element.DataContext.GetType().GetProperty(propertyName);
                pi.SetValue(element.DataContext, "new value...");
            }
        };
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM