简体   繁体   中英

Writing back a dependency property value to the view model in two-way binding

I'm implementing a wpf control that provides some common binding between xaml and Google Maps running in a web browser. Currently, the bindings are one-way and are working fine.

What I need to do next is write back a value to the view model when two-way binding is specified. The property I'm starting with is the Google Map's zoom. When it's changed in the browser I can run js on the page that calls back to my C# code with the new zoom level.

What's the correct way to offer this new value to the DP such thas it will update the view model's zoom level if a two-way binding was selected?

My current code for the the zoom level DP:

#region ZoomProperty

    //Called from the web page
    private JSValue MapZoom_OnMapZoomChanged(JSValue[] arguments) {
        string zoom = arguments[0];

        //where do I set the zoom so that the view model bound property is updated?
        return null;
    }

public static readonly DependencyProperty ZoomProperty =
    DependencyProperty.Register("Zoom", typeof(string), typeof(GoogleMap), new FrameworkPropertyMetadata(string.Empty, OnZoomPropertyChanged), OnZoomPropertyValidate);

public string Zoom {
    get { return (string)GetValue(ZoomProperty); }
    set { SetValue(ZoomProperty, value); }
}

private static bool OnZoomPropertyValidate(object value) {
    return value is string;
}

private static void OnZoomPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) {
    GoogleMap control = source as GoogleMap;
    control.SetZoom(e.NewValue.ToString());
}

private string zoom;
public void SetZoom(string value) {
    if (!googleMapPageReady) {
        zoom = value;
        return;
    }

    webControl.ExecuteJavascript(string.Format("setZoom({0})", zoom));
}

#endregion

Unless I'm overlooking something, you just need to do:

private JSValue MapZoom_OnMapZoomChanged(JSValue[] arguments)
{
    string newZoom= arguments[0];
    this.Zoom = newZoom; // here
    return null;
}

The dependency property pattern is setup so that from the outside you can just treat Zoom as a normal c# property (setter and getter). If you look at the setter for that property it calls SetValue() , which is on the DependencyObject base class and does the magic to notify the binding engine of the change (also see: Register() )

Update

A simple way to prevent the change from sending the update to the map when the map was the one providing the change in the first place:

private bool IsMapUpdateSuppressed = false;

private JSValue MapZoom_OnMapZoomChanged(JSValue[] arguments)
{
    string newZoom= arguments[0];
    this.IsMapUpdateSuppressed = true;
    this.Zoom = newZoom;
    this.IsMapUpdateSuppressed = false;
    return null;
}

private static void OnZoomPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
    GoogleMap control = source as GoogleMap;
    if (!control.IsMapUpdateSuppressed)
    {
        control.SetZoom(e.NewValue.ToString());
    }
}

This allows the DP value to change, process, and notify the binding engine as usual, but just prevents the call to SetZoom

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM