揭露内部控制属性的WPF绑定 [英] Exposing inner Control properties for binding in WPF

查看:137
本文介绍了揭露内部控制属性的WPF绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

:我想出如何做到这一点我自己。我张贴,希望这将节省别人使用Google几天我的解决方案。如果你是一个WPF大师,请看看我的解决方案,让我知道,如果有一个更好/更优雅/更有效地做到这一点的方式。特别是,我很感兴趣,知道什么,我不知道......这是怎么解决要拧我的道路?真正的问题归结为揭露内部控制的属性。

问题:
我创造了一些code自动生成WPF为XML文件中的数据绑定GUI。我有一个XSD文件,可以帮助我确定节点类型等简单的键/值的元素很容易。

Problem: I am creating some code to auto-generate a data-bound GUI in WPF for an XML file. I have an xsd file that can help me determine the node types, etc. Simple Key/Value elements are easy.

当我分析这个元素:

<Key>value</Key>

我可以创造一个新的KeyValueControl,并设置的DataContext 此元素。该键值被定义为一个用户控件,只是上有一些简单的绑定。这对于任何简单的XElement的伟大工程。

I can create a new 'KeyValueControl' and set the DataContext to this element. The KeyValue is defined as a UserControl and just has some simple bindings on it. It works great for any simple XElement.

此控件中的XAML看起来是这样的:

The XAML inside this control looks like this:

<Label Content={Binding Path=Name} /> 
<TextBox Text={Binding Path=Value} />

其结果是,具有与元件的名称和与该我可以编辑值的文本框的标签的线。

The result is a line that has a label with the element name and a text box with the value that I can edit.

现在,有次,我需要显示查找值而不是实际值。我想创造一个'KeyValueComboBox类似上述KeyValueControl,但能够指定(基于文件中的信息)的的ItemsSource,显示和值路径。在名称和值的绑定将是相同KeyValueControl。

Now, there are times where I need to display lookup values instead of the actual value. I would like to create a 'KeyValueComboBox' similar to the above KeyValueControl but be able to specify (based on information in the file) the ItemsSource, Display and Value paths. The 'Name' and 'Value' bindings would be the same as the KeyValueControl.

我不知道,如果一个标准用户控件可以解决这个问题,或者如果我需要从选择继承。

I don't know if a standard user control can handle this, or if I need to inherit from Selector.

在控件的XAML会是这个样子:

The XAML in the control would look something like this:

<Label Content={Binding Path=Name} /> 
<ComboBox SelectedValue={Binding Path=Value}
          ItemsSource={Binding [BOUND TO THE ItemsSource PROPERTY OF THIS CUSTOM CONTROL]
          DisplayMemberPath={Binding [BOUND TO THE DisplayMemberPath OF THIS CUSTOM CONTROL]
          SelectedValuePath={Binding [BOUND TO THE SelectedValuePath OF THIS CUSTOM CONTROL]/>

在我的code,然后,我会做这样的事情(假设这个节点是一个东西,需要显示的内容的列表,以便用户可以选择的ID:

In my code, I would then do something like this (assuming that this node is a 'Thing' and needs to display a list of Things so the user can select the ID:

var myBoundComboBox = new KeyValueComboBox();
myBoundComboBox.ItemsSource = getThingsList();
myBoundComboBox.DisplayMemberPath = "ThingName";
myBoundComboBox.ValueMemberPath = "ThingID"
myBoundComboBox.DataContext = thisXElement;
...
myStackPanel.Children.Add(myBoundComboBox)

所以我的问题是:

So my questions are:

1)我应该继承控制或选择我的KeyValueComboBox?

1) Should I inherit my KeyValueComboBox from Control or Selector?

2)如果我要从控制继承,我怎么露出内组合框的ItemsSource时,的DisplayMemberPath和ValueMemberPath绑定?

2) If I should inherit from Control, how do I expose the inner Combo Box's ItemsSource, DisplayMemberPath, and ValueMemberPath for binding?

3)如果我需要从选择继承,有人可以提供如何我可能会与开始的一个小例子?同样,我是新来WPF这么一个好的,简单的例子将真正帮助,如果这是我需要走的道路。

3) If I need to inherit from Selector, can someone provide a small example of how I might get started with that? Again, I'm new to WPF so a nice, simple example would really help if that's the road I need to take.

推荐答案

我结束了盘算如何如何做到这一点我自己。我在这里张贴的答案,以便其他人可以看到有效的解决方案,也许一个WPF大师会通过,并告诉我一个更好/更优雅的方式来做到这一点。

I ended up figuring how how to do this on my own. I'm posting the answer here so that others can see a solution that works, and maybe a WPF guru will come by and show me a better/more elegant way to do this.

所以,答案最终被#2。露出内部特性原来是正确的答案。设置它实际上是pretty容易。一旦你知道该怎么做。有(我能找到),这不是很多完整的例子,所以希望这个人会帮助别人是运行到这个问题。

So, the answer ended up being #2. Exposing the inner properties turns out to be the right answer. Setting it up is actually pretty easy.. once you know how to do it. There aren't many complete examples of this (that I could find), so hopefully this one will help someone else that runs into this problem.

ComboBoxWithLabel.xaml.cs

在这个文件中最重要的事情是利用DependencyProperties的。请注意,所有我们正在做的,现在是刚刚露出属性(LabelContent和的ItemsSource)。在XAML将接线内部控制的属性,这些外部属性的照顾。

The important thing in this file is the use of DependencyProperties. Note that all we're doing right now is just exposing the properties (LabelContent and ItemsSource). The XAML will take care of wiring the internal control's properties to these external properties.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;

namespace BoundComboBoxExample
{
    /// <summary>
    /// Interaction logic for ComboBoxWithLabel.xaml
    /// </summary>
    public partial class ComboBoxWithLabel : UserControl
    {
        // Declare ItemsSource and Register as an Owner of ComboBox.ItemsSource
        // the ComboBoxWithLabel.xaml will bind the ComboBox.ItemsSource to this
        // property
        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
          ComboBox.ItemsSourceProperty.AddOwner(typeof(ComboBoxWithLabel));

        // Declare a new LabelContent property that can be bound as well
        // The ComboBoxWithLable.xaml will bind the Label's content to this
        public string LabelContent
        {
            get { return (string)GetValue(LabelContentProperty); }
            set { SetValue(LabelContentProperty, value); }
        }

        public static readonly DependencyProperty LabelContentProperty =
          DependencyProperty.Register("LabelContent", typeof(string), typeof(ComboBoxWithLabel));

        public ComboBoxWithLabel()
        {
            InitializeComponent();
        }
    }
}

ComboBoxWithLabel.xaml

在XAML是pretty简单,对标签和组合框的ItemsSource绑定除外。我发现,让这些绑定最简单的方法是正确的声明在cs文件属性(如上),然后使用VS2010设计师设置从属性窗格中的绑定源。从本质上讲,这是我所知道的一个内部控件的属性绑定到基控制的唯一途径。如果有更好的方式来做到这一点,请让我知道。

The Xaml is pretty straightforward, with the exception of the bindings on the Label and the ComboBox ItemsSource. I found that the easiest way to get these bindings right is to declare the properties in the .cs file (as above) and then use the VS2010 designer to setup the binding source from the properties pane. Essentially, this is the only way I know of to bind an inner control's properties to the base control. If there's a better way to do it, please let me know.

<UserControl x:Class="BoundComboBoxExample.ComboBoxWithLabel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="28" d:DesignWidth="453" xmlns:my="clr-namespace:BoundComboBoxExample">
    <Grid>
        <DockPanel LastChildFill="True">
            <!-- This will bind the Content property on the label to the 'LabelContent' 
                 property on this control-->
            <Label Content="{Binding Path=LabelContent, 
                             RelativeSource={RelativeSource FindAncestor, 
                                             AncestorType=my:ComboBoxWithLabel, 
                                             AncestorLevel=1}}" 
                   Width="100" 
                   HorizontalAlignment="Left"/>
            <!-- This will bind the ItemsSource of the ComboBox to this 
                 control's ItemsSource property -->
            <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, 
                                    AncestorType=my:ComboBoxWithLabel, 
                                    AncestorLevel=1}, 
                                    Path=ItemsSource}"></ComboBox>
            <!-- you can do the same thing with SelectedValuePath, 
                 DisplayMemberPath, etc, but this illustrates the technique -->
        </DockPanel>

    </Grid>
</UserControl>

MainWindow.xaml

使用此XAML中不感兴趣所有..这正是我想要的。您可以通过所有标准WPF技术设置的ItemsSource和LabelContent。

The XAML to use this is not interesting at all.. which is exactly what I wanted. You can set the ItemsSource and the LabelContent via all the standard WPF techniques.

<Window x:Class="BoundComboBoxExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="86" Width="464" xmlns:my="clr-namespace:BoundComboBoxExample"
        Loaded="Window_Loaded">
    <Window.Resources>
        <ObjectDataProvider x:Key="LookupValues" />
    </Window.Resources>
    <Grid>
        <my:ComboBoxWithLabel LabelContent="Foo"
                              ItemsSource="{Binding Source={StaticResource LookupValues}}"
                              HorizontalAlignment="Left" 
                              Margin="12,12,0,0" 
                              x:Name="comboBoxWithLabel1" 
                              VerticalAlignment="Top" 
                              Height="23" 
                              Width="418" />
    </Grid>
</Window>

出于全面考虑,这里是MainWindow.xaml.cs

For Completeness Sake, here is the MainWindow.xaml.cs

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ((ObjectDataProvider)FindResource("LookupValues")).ObjectInstance =
            (from i in Enumerable.Range(0, 5)
             select string.Format("Bar {0}", i)).ToArray();

    }
}

这篇关于揭露内部控制属性的WPF绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆