简体   繁体   English

无法绑定到属于C#/ XAML应用程序中的WindowsFormsHost子对象的属性的解决方法?

[英]Workaround for inability to bind to a property that belongs to a WindowsFormsHost Child object in C#/XAML app?

I have a C# WPF 4.51 app. 我有一个C#WPF 4.51应用程序。 As far as I can tell, you can not bind to a property belonging to an object that is the child of a WPF WindowsFormsHost control. 据我所知,您不能绑定属于WPF WindowsFormsHost控件的子对象的属性。 (If I am wrong in this assumption please show me how to do it): (如果我在这个假设中错了,请告诉我该怎么做):

Bind with WindowsFormsHost 与WindowsFormsHost绑定

In my case, I have a page that contains a WindowsFormsHost control whose Child object is a ScintillaNET editor control: 在我的例子中,我有一个包含WindowsFormsHost控件的页面,其Child对象是ScintillaNET编辑器控件:

https://github.com/jacobslusser/ScintillaNET https://github.com/jacobslusser/ScintillaNET

    <WindowsFormsHost x:Name="wfhScintillaTest"
                      Width="625"
                      Height="489"
                      Margin="206,98,0,0"
                      HorizontalAlignment="Left"
                      VerticalAlignment="Top">
        <WindowsFormsHost.Child>
            <sci:Scintilla x:Name="scintillaCtl" />
        </WindowsFormsHost.Child>
    </WindowsFormsHost>

The child control works and displays fine. 子控件工作正常。 If it were a normal WPF control I would bind the Text property of the Scintilla editor control to some string property in my ViewModel , so that all I had to do to update the content of the Scintilla editor control is update that string property. 如果它是一个普通的WPF控件,我会将Scintilla编辑器控件的Text属性绑定到我的ViewModel中的某个字符串属性,这样我只需更新Scintilla编辑器控件的内容即可更新该字符串属性。

But since I can't bind to a property belonging to a WindowsFormsHost child object, I'm looking for a strategy/solution that not completely awkward or kludgy. 但由于我无法绑定属于WindowsFormsHost子对象的属性,我正在寻找一种不完全笨拙或笨拙的策略/解决方案。 Has anybody faced this scenario before and has a reasonable strategy that solves my binding/update problem? 以前是否有人遇到过这种情况并且有一个合理的策略来解决我的绑定/更新问题?

A simple approach here is you can create some dedicated class to contain just attached properties mapping to the properties from your winforms control. 这里一个简单的方法是,您可以创建一些专用类,以包含映射到winforms控件中的属性的附加属性。 In this case I just choose Text as the example. 在这种情况下,我只选择Text作为示例。 With this approach, you can still set Binding normally but the attached properties will be used on the WindowsFormsHost : 使用这种方法,您仍然可以正常设置Binding,但附加属性将在WindowsFormsHost

public static class WindowsFormsHostMap
{
    public static readonly DependencyProperty TextProperty
        = DependencyProperty.RegisterAttached("Text", typeof(string), typeof(WindowsFormsHostMap), new PropertyMetadata(propertyChanged));
    public static string GetText(WindowsFormsHost o)
    {
        return (string)o.GetValue(TextProperty);
    }
    public static void SetText(WindowsFormsHost o, string value)
    {
        o.SetValue(TextProperty, value);
    }
    static void propertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var t = (sender as WindowsFormsHost).Child as Scintilla;
        if(t != null) t.Text = Convert.ToString(e.NewValue);
    }
}

Usage in XAML : 在XAML中的用法

<WindowsFormsHost x:Name="wfhScintillaTest"
                  Width="625"
                  Height="489"
                  Margin="206,98,0,0"
                  HorizontalAlignment="Left"
                  VerticalAlignment="Top"
                  local:WindowsFormsHostMap.Text="{Binding yourTextProp}"
    >
    <WindowsFormsHost.Child>
        <sci:Scintilla x:Name="scintillaCtl"/>
    </WindowsFormsHost.Child>
</WindowsFormsHost>

The Child should of course be a Scintilla , otherwise you need to modify the code for the WindowsFormsHostMap . Child当然应该是Scintilla ,否则你需要修改WindowsFormsHostMap的代码。 Anyway this is just to show the idea, you can always tweak it to make it better. 无论如何,这只是为了展示这个想法,你总是可以调整它以使其更好。

Note the code above works just for 1 way binding (from view-model to your winforms control). 请注意,上面的代码仅适用于单向绑定(从视图模型到winforms控件)。 If you want the other way, you need to register some event handler for the control and update the value back to the attached property in that handler. 如果您想要另一种方式,则需要为控件注册一些事件处理程序,并将值更新回该处理程序中的附加属性。 It's quite complicated that way. 这种方式非常复杂。

You can only achieve a very, very limited binding with a Windows Forms control as they binding won't receive update notifications and may need to be explicitly polled to get the results via a custom RefreshValues() method or something that polls each piece of data. 您只能通过Windows窗体控件实现非常非常有限的绑定,因为绑定不会接收更新通知,并且可能需要显式轮询以通过自定义RefreshValues()方法或轮询每个数据的内容来获取结果。

But if all you need is to access the child control, you should do the binding in code: 但是,如果你只需要访问子控件,你应该在代码中进行绑定:

(WFH.Child as MyWinFormsControl).Text

If you intend to do a lot of binding, it might be easier to create a WPF wrapper object ( UserControl perhaps) that has all the properties you need as DependencyProperties and the underlying code each property would manually poll the WinForms control as if it were the backing field for the property. 如果你打算做很多绑定,可能更容易创建一个WPF包装器对象(也许是UserControl ),它具有你需要的所有属性作为DependencyProperties和底层代码,每个属性都会手动轮询WinForms控件,就好像它是该物业的支持领域。 It is a little complicated at first, but easier than manually polling each property. 它起初有点复杂,但比手动轮询每个属性更容易。

Create a dependecy object of type Windows Form Host. 创建Windows窗体主机类型的依赖对象。

using System.Windows.Forms.Integration;

namespace MainStartUp.DependencyObjects
{
    public class FormHostDependencyObject : WindowsFormsHost
    {
        public static readonly DependencyProperty ContentControlProperty =
            DependencyProperty.Register("ContentControl", typeof(System.Windows.Forms.Control), 
                typeof(FormHostDependencyObject),
                new PropertyMetadata(new System.Windows.Forms.Control(), PropertyChaged));       

        public static void SetContentControl(UIElement element, string value)
        {  
            element.SetValue(ContentControlProperty, value);          
        }

        public static string GetContentControl(UIElement element)
        {
            return (string)element.GetValue(ContentControlProperty);
        }

        private static void PropertyChaged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            ((FormHostDependencyObject)dependencyObject).Child = (System.Windows.Forms.Control)e.NewValue;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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