คำตอบ How to transform string to binding?

  • domenica 29 aprile 2012 23:42
     
      Contiene codice

    I am writing a custom control which allows the user to use a collection of items of an unknown type as an items source.

    My control contains an AutoCompleteBox.  For that AutoCompleteBox, I need to be able to specify which column in the items source is to be used as in the dropdown of displayed values.  This is roughly the equivilant of DisplayMemberPath of a combobox.

    My control exposes two dependency properties: DisplayMemberPath and ValueMemberPath.  ValueMemberPath is used to set the property of the same name on the AutoCompleteBox.  I do this in the OnApplyTemplate method. 

    DisplayMemberPath is also the name of a column that should be used in a binding.  The value of the column of this name should be displayed in the TextBlock named DisplayTextBlock.  However I don't know how to set the binding for this in xaml (see the ??? in the xaml below).

    The TextBlock that is used to display items in the AutoCompleteBox dropdown exists inside a DataTemplate.  Therefore I am unable to to use GetTemplateChild to find it. 

    <Style TargetType="{x:Type local:EntitySelector}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:EntitySelector}">
                        <StackPanel Orientation="Horizontal" DataContext="{Binding RelativeSource={RelativeSource AncestorType=Control}}">
                            <toolkit:AutoCompleteBox
                                Name="IDSelector"
                                Width="{TemplateBinding Width}"
                                ItemsSource="{TemplateBinding ItemsSource}"
                                
                                >
                                <toolkit:AutoCompleteBox.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock x:Name="DisplayTextBlock" Text="{Binding ?????????????????}" ></TextBlock>
                                    </DataTemplate>
                                </toolkit:AutoCompleteBox.ItemTemplate>
                            </toolkit:AutoCompleteBox>
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    public class EntitySelector : Control
        {
    
            public System.Collections.IEnumerable ItemsSource
            {
                get { return (System.Collections.IEnumerable)GetValue(ItemsSourceProperty); }
                set { SetValue(ItemsSourceProperty, value); }
            }
    
            public static readonly DependencyProperty ItemsSourceProperty =
                DependencyProperty.Register("ItemsSource", typeof(System.Collections.IEnumerable), typeof(EntitySelector), new UIPropertyMetadata(null));
    
    
            public string DisplayMemberPath
            {
                get { return (string)GetValue(DisplayMemberPathProperty); }
                set { SetValue(DisplayMemberPathProperty, value); }
            }
    
            public static readonly DependencyProperty DisplayMemberPathProperty =
                DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(EntitySelector), new UIPropertyMetadata(null));
    
    
            public string ValueMemberPath
            {
                get { return (string)GetValue(ValueMemberPathProperty); }
                set { SetValue(ValueMemberPathProperty, value); }
            }
    
            public static readonly DependencyProperty ValueMemberPathProperty =
                DependencyProperty.Register("ValueMemberPath", typeof(string), typeof(EntitySelector), new UIPropertyMetadata(null));
    
    
            public delegate void PopulatingHandler(int columnIndex, string searchText);
    
            public event PopulatingHandler Populating;
    
            
            static EntitySelector()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(EntitySelector), new FrameworkPropertyMetadata(typeof(EntitySelector)));
            }
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
                AutoCompleteBox box = GetTemplateChild("IDSelector") as AutoCompleteBox;
                box.ValueMemberPath = ValueMemberPath;
                box.Populating +=new PopulatingEventHandler(EntitySelector_Populating);
                box.SelectionChanged += new SelectionChangedEventHandler(EntitySelector_SelectionChanged);
                box.TextChanged += new RoutedEventHandler(box_TextChanged);
                
                
                // Cant find DisplayTextBlock and set the binding here because it is in a datatemplate
                
            }
    
            void box_TextChanged(object sender, RoutedEventArgs e)
            {
                AutoCompleteBox box = sender as AutoCompleteBox;
            }
    
            private void EntitySelector_Populating(object sender, PopulatingEventArgs e)
            {
                Populating(0, e.Parameter);
            }
    
            private void EntitySelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                
            }
    
    
        }

Tutte le risposte

  • lunedì 30 aprile 2012 02:47
     
      Contiene codice

    Binding within a template/style is a little bit different than directly binding to a control.  However, the same concepts apply.  There must be a datacontext,  proper paths, and values.  In your case the "EntitySelector" type is the target that has a contenttemplate and a datatemplate.  Your static keystyle property then registers (with WPF Binding) what is in the Generic.xaml.  It knows that the markup in that xaml is bound to the content you have in the class above.

    The data template implies there is a collection of items that will be bound to the "EntitySelector".  So the path will be something like TheCollection.SomeValue.  So the collection iteself must contain properties to which the Template is applied.  In your example the DisplayMemberPath is just one string value, as is the ValueMemberPath.  This is okay if the Text field of the AutocompleteTextBox is bound to one or the other because there is only one value at a time there once a selection is made or the value is changed from typing etc.

    In the DataTemplating guide they show this code:

    <ListBox Width="400" Margin="10"
             ItemsSource="{Binding Source={StaticResource myTodoList}}">
       <ListBox.ItemTemplate>
         <DataTemplate>
           <StackPanel>
             <TextBlock Text="{Binding Path=TaskName}" />
             <TextBlock Text="{Binding Path=Description}"/>
             <TextBlock Text="{Binding Path=Priority}"/>
           </StackPanel>
         </DataTemplate>
       </ListBox.ItemTemplate>
     </ListBox>

    Which clearly shows an item source and within that collection it shows how the Text value paths are found. http://msdn.microsoft.com/en-us/library/ms742521.aspx  I do not see anywhere in the example where the ItemsSource is set or the CollectionViewSource which is a bit of a different type of binding.  I think to fix your binding question you have to set a collection that has properties in it which would be that paths of the TEXT property in your DataTemplate.

    <toolkit:AutoCompleteBox.ItemTemplate>

    If you want to hook up events to this control via styles you have to do it as a separate style.  I usually will put the triggers ahead of the Style template, just to remind myself that the Selection changed and or other events being bound are at a more global layer.  Look for XAML triggers and MULTI-Triggers to see how this is done for routed events. 

    WPF changed the paradigmn a bit concerning bindings to collections.  It doesn't focus on the controls, it focuses on the data.  A subtle but potential tripping point.  By putting in just one event handler for what you want, you are being forced to filter based on Data and not the control.

     


    JP Cowboy Coders Unite!


  • lunedì 30 aprile 2012 03:20
     
     

    Mr. Javaman II:  I don't think I did a very good job laying my question:

    In your response you show bindings for a todo list and you show bindings for what might be a Task class with properties named TaskName, Description and Priority. 

    My question asks "What if I don't know the name of the property that is to be bound to the TextBlock?"


    In my code I have string properties (ValueMemberPath and DisplayMemberPath) which I intend to use to obtain property names i.e. TaskName and Description.  If later I bind to a list of customers I might set ValueMemberPath to "CustomerID" and DisplayMemberPath to "CustomerName".

    So if I dont know the name of the property I am binding to a design time, what do I put for the binding in the TextBlock?


    Thanks for your response!


    Sam

  • lunedì 30 aprile 2012 13:10
     
      Contiene codice

    My question asks "What if I don't know the name of the property that is to be bound to the TextBlock?"

    Ok so I think the question is this: I have a DataTemplate with a control of which the binding is chosen at run time by the user, How do I bind that? 

    Try this:  "Always use properties page in designer for bindings, because it lays out the acceptable values and prevents you from guessing".  Intellisense works there too!  You can find a property from the other controls that will act as the binding.  So the trick is to do something like this:

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="69*" />
                <ColumnDefinition Width="209*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="33*" />
                <RowDefinition Height="228*" />
            </Grid.RowDefinitions>
            <ListBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:Shell, AncestorLevel=1}, Path=TheCollection}" SelectionChanged="ListBox_SelectionChanged" Grid.RowSpan="2" Grid.ColumnSpan="2">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBox Text="{Binding Path=Name}"></TextBox>
                            <Slider Value="{Binding Path=Progress}" Maximum="100" Width="100"></Slider>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
    
            <ComboBox x:Name="XCBUserSelect" Grid.Row="1" Grid.Column="0"  ></ComboBox>
        </Grid>

    The combox box is the selector. It controls the filter for the itemssource of the LISTBOX using LINQ or some other acceptable filer. You then need to add the appropriate controls in the Listbox you want to view and based on the filter either show or hide the controls you want/don't want. You can do this in either the Code-Behind OR you can do it in XAML using DataTriggers.

    How to get data and or container to the listbox...

    or this link.


    JP Cowboy Coders Unite!

  • lunedì 30 aprile 2012 13:11
     
     
    Once you have the template name, grab the control and change the binding.

    JP Cowboy Coders Unite!

  • lunedì 30 aprile 2012 13:13
     
     
    Changing Bindings at runtime

    JP Cowboy Coders Unite!

  • lunedì 30 aprile 2012 13:21
     
      Contiene codice

    And Finally, the datatemplateselector.

    http://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector.aspx

    So as you can see there are many ways to do this.  You'll be able to spot the best one for your project.

    Actually there's one more.  You can create controls that are injected into the datatemplate based on what is selected in combobox.  Those controls would just contain what you want. 

            <ListBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:Shell, AncestorLevel=1}, Path=TheCollection}" SelectionChanged="ListBox_SelectionChanged" Grid.RowSpan="2" Grid.ColumnSpan="2">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                      <ContentControl/>
                       
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

    The content control is controlled by the selector and allows you to inject a user control at runtime. The nice thing about this solution is that the Usercontol which has TextBoxes, Sliders, and what ever else you want only needs to specify the paths because of the inherited nature of Datacontext within WPF.


    JP Cowboy Coders Unite!


  • lunedì 30 aprile 2012 16:00
     
     

    >>>Try this:  "Always use properties page in designer for bindings, because it lays out the acceptable values and prevents you from >>>guessing".  Intellisense works there too!  '

    Haha thats funny :) 

    Here is my question, again.  If you have an answer why don't you write a bit of code to show it.   The DataTemplate below will be used in a control that will be bound to a List of type X (or type Y, or type Z, or... type whatever).  There are two string properties of X that will be displayed in the textboxes.  You don't know the names of these properties and in fact they will vary with each instance of the control that is used.   Please show how this will be done.  Note I am not asking how to choose between two or more datatemplates which have been previously defined.

    <DataTemplate>

       <TexBlock Text={}/>

       <TexBlock Text={}/>

    </DataTemplate>

  • lunedì 30 aprile 2012 16:36
     
     

    Ok let me start over: The problem is  // Cant find DisplayTextBlock and set the binding here because it is in a datatemplate
    You can find it using FindName but you will need the container holding the items to search from there.  If you attempt to FindName from root, they won't be found.

    http://blogs.msdn.com/b/wpfsdk/archive/2007/04/16/how-do-i-programmatically-interact-with-template-generated-elements-part-ii.aspx



    JP Cowboy Coders Unite!

  • lunedì 30 aprile 2012 18:50
     
     

    OK I think we are on the right track.  I tried to follow the article however the object I am working with (AutoCompleteBox) exposes
    no property named ItemContainerGenerator. 

    It looks like the objective of the article is to drill down to the DataTemplate of the control and find the child controls. 
    AutoCompleteBox has a ItemTemplate property that exposes the datatemplate:

    AutoCompleteBox box = GetTemplateChild("IDSelector") as AutoCompleteBox;
    TextBlock tb = box.ItemTemplate.FindName("DisplayTextBlock", box) as TextBlock;


    The last line above results in this error: {"This operation is valid only on elements that have this template applied."}

    Is there a different way??

    Thanks,

    Sam

  • martedì 1 maggio 2012 00:31
     
     
    Can you post a repro to SkyDrive for us? 
  • martedì 1 maggio 2012 02:45
     
     

    Hi

    I think if you want to get a reference to the TextBlock of your DataTemplate
    (actually all TextBlocks, plural) you need to wait until the box is populated
    and the ItemsContainerGenerator completes. They're not fully
    generated in OnApplyTemplate afaics.
    Then you can get references to all of the textblocks as described here
    How to: Find DataTemplate-Generated Elements

    A different approach could be to wrap each item of your ItemsSource into
    a wrapper that exposes the Property specified as "DisplayMemberPath"
    by always the same property , for example "DisplayMemberValue".
    Then you could bind the DataTemplate TextBlock "statically" to "Text="{Binding Path=DisplayMemberValue}"

    Whenever ItemsSource, DisplayMemberPath or DataContext changes
    you need to to create a new the wrapper collection.

    Inside the wrapper you could bind to the underlying Property specified
    as DisplayMemberPath using BindingsOperations.SetBinding etc,
    thus the DisplayMemberValue would also keep in sync with the "real" value.

    Chris




  • martedì 1 maggio 2012 03:30
     
     Con risposta Contiene codice
    such as

    in your ControlTemplate:

                                        <DataTemplate>
                                            <TextBlock x:Name="DisplayTextBlock"
                                                       Text="{Binding Path=DisplayValue}"
                                                       />
                                        </DataTemplate>

    In EntitySelector.cs
    add this code somewhere w/o changing existing code

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
            {
                base.OnPropertyChanged(e);
    
                if (e.Property == ItemsSourceProperty)
                {
                    if ((e.OldValue is IList<DisplayAdapter>))
                    {
                        foreach (DisplayAdapter adapter in (IList<DisplayAdapter>)e.OldValue)
                        {
                            BindingOperations.ClearAllBindings(adapter);
                        }
                    }
                    if (!(e.NewValue is IList<DisplayAdapter>))
                    {
                        UpdateItemsSource();
                    }
                }
                else if (e.Property == DisplayMemberPathProperty)
                {
                    UpdateItemsSource();
    
                }
                else if (e.Property == DataContextProperty)
                {
                    UpdateItemsSource();
                }
            }
    
            void UpdateItemsSource()
            {
                var items = ItemsSource;
                if (null != items && !string.IsNullOrWhiteSpace(DisplayMemberPath))
                {
                    var items2 = items.OfType<object>();
                    ItemsSource = new ObservableCollection<DisplayAdapter>(items2.Select(o => new DisplayAdapter(o, DisplayMemberPath)));
                }
            }
    

    finally add the adapter:
    class DisplayAdapter : FrameworkContentElement
        {
            public DisplayAdapter(object dataItem, string displayMemberPath)
            {
                if (dataItem == null) throw new ArgumentNullException("dataItem");
                if (string.IsNullOrWhiteSpace(displayMemberPath)) throw new ArgumentNullException("displayMemberPath");
    
                Binding binding = new Binding { Mode = BindingMode.OneWay, Source = dataItem, Path = new PropertyPath(displayMemberPath) };
                this.SetBinding(DisplayValueProperty, binding);
              
            }
            ~DisplayAdapter()
            {
                if (!Dispatcher.CheckAccess())
                {
                    Dispatcher.Invoke((Action)(() => BindingOperations.ClearAllBindings(this)));
                }
                else
                {
                    BindingOperations.ClearAllBindings(this);
                }
            }
    
            public static readonly DependencyProperty DisplayValueProperty =
                DependencyProperty.Register("DisplayValue", typeof(object), typeof(DisplayAdapter));
    
            public object DisplayValue
            {
                get { return GetValue(DisplayValueProperty); }
                set { SetValue(DisplayValueProperty, value); }
            }
        }
    Chris
  • martedì 1 maggio 2012 15:58
     
     

    Wow I really appreicate the help with this.  I didn't know it would be such a major effort (read:hack) to implement.  Chris, your solution looks good but I will have to modify it to allow for a ValueMember as well (like a combobox). 

    BTW, Since I have to copy from whatever type is supplied as an ItemsSource to DisplayAdapter, I might as well just define a type with two string properties for display and value and require that ItemsSource be a collection of that type.  So the bottom line appears to be that what I am trying to do cannot be done efficiently.

    Unfortunately I have a major deadline on Thursday and I have spent FAR too much time on this.  I will revisit it again shortly.  Thanks again!

  • martedì 1 maggio 2012 22:13
     
     

    Maybe it looks complicated but all it does
    is to introduce the level of indirection you need
    if your binding path is variable.

    As to ValueMemberPath. If it functions like
    SelectedValuePath /SelectedValue in normal selectors
    you don't need it in the adapter afaics,
    It only matters when an item is selected.
    Again you need to bind to some property of the
    SelectedItem.

    As to a differrent a/o easier approach.
    There are lots of different ways to go.

    You could simply generate a List of strings based on
    the ItemsSource and the DisplayMemberPath
    If you itemssource are strings you don't need a datatemplate at all.
    When a string gets selected you do the mapping String : DataItem
    in code behind (implies there's a 1:1 relation)

    With some luck you could also use a converter (that knows
    the DisplayMemberPath)

    You could also create your DataTemplate in codebehind
    and change it and its binding whenever DisplayMemberPath changes.


    You could also follow your first idea and kind of
    inject a binding(expression) to each textblock
    generated by the datatemplate.
    You'd need to drill into the internals of the
    AutoCompleteBox to get the ItemsControl
    that displayes the list,
    (I think its TemplatePartAttribute is "Selector")
    listen to its ItemsContainerGenerator.
    StatusChanged event and when status switches
    to "ContainersGenerated" get the presenting
    ListBoxItem find the TextBlock, bind its
    TextProperty to the dataitems property
    whose name equals DisplayMemberPath.
    Equally hackish proabaly
    Whatever you do, you need some reliable mechanism of
    plumbing.
    The basic problem is that Binding.Path is not istelf
    a DP so
    Text="{Binding Path={Binding DisplayMemberPath}}"
    is invalid.

    Chris




  • martedì 1 maggio 2012 22:48
     
     
    To cut a long story short....:
    The most easy solution would be to bind the DataTemplate
    as a DynamicResource.
    Whenever DisplayMemberPath changes create a
    new DataTemplate in CodeBehind and replace
    the previous resource.
    As for creating datatemplates in Codebhind see this post

    Chris
  • mercoledì 2 maggio 2012 02:31
     
     

    >>Text="{Binding Path={Binding DisplayMemberPath}}"

    LOL I actualy tried that.  It sure would make things easier if it worked!

  • mercoledì 2 maggio 2012 22:06
     
     
    Bah too easy, developers need to stay challenged.
  • mercoledì 2 maggio 2012 22:44
     
      Contiene codice

    The problem is  ""Cant find DisplayTextBlock and set the binding here because it is in a datatemplate"

    Try this example below, while not specifically for your situation, you call it by passing in the Datagrid.  It then will get the child objects in the Visual tree which can be cast into an objec instance.  You can then set the bindings there.  In the code below there was a DataGridColumn template with an image in it.  When the mouse over occurred on that column an invisible image was made visible.  The textblock was used to find the DataGridColumn based on the Header text.  So the current column was known too.

          private void FindImage(DependencyObject parent, Visibility visibility)
            {
                CurrentColumn = null;
                int count = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < count; i++)
                {
                    var child = VisualTreeHelper.GetChild(parent, i);
                    if (child.GetType().UnderlyingSystemType.Name == "Image")
                    {
                        Image img = child as Image;
                        img.Visibility = visibility;
                    }
                    if (child.GetType().UnderlyingSystemType.Name == "TextBlock")
                    {
                        TextBlock tb = child as TextBlock;
                        string TheColumnName = tb.Text;
                        var foundit = xdg.Columns.Where(p => p.Header.ToString() == TheColumnName);
                        foreach (DataGridColumn dgc in foundit)
                        {
                            CurrentColumn = dgc;
                        }
                    }
                }
            }


    JP Cowboy Coders Unite!

  • giovedì 3 maggio 2012 01:28
     
      Contiene codice

    How about this?

                 
    <StackPanel>        
        <StackPanel.Resources>
            <Style TargetType="{x:Type WpfApplication271:EntitySelector}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type WpfApplication271:EntitySelector}">
                            <Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=WpfApplication271:EntitySelector}}">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"></RowDefinition>
                                    <RowDefinition Height="Auto"></RowDefinition>
                                    <RowDefinition Height="Auto"></RowDefinition>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                                    <ColumnDefinition Width="*"></ColumnDefinition>
                                </Grid.ColumnDefinitions>
                                    
                                <ComboBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding Values}">
                                    <ComboBox.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel Orientation="Horizontal">                                                
                                                <TextBlock FontWeight="Bold" Text="{Binding Path=ValueMemberPath,RelativeSource={RelativeSource AncestorType=WpfApplication271:EntitySelector}}"></TextBlock>                                                
                                                <TextBlock Text="{Binding }"></TextBlock>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ComboBox.ItemTemplate>
                                </ComboBox>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </StackPanel.Resources>        
            
        <WpfApplication271:EntitySelector ItemsSource="{Binding MyItems}" ValueMemberPath="Name"></WpfApplication271:EntitySelector>
        <WpfApplication271:EntitySelector ItemsSource="{Binding MyItems}" ValueMemberPath="Key"></WpfApplication271:EntitySelector>                            
            
    </StackPanel>


    public partial class MainWindow : Window
    {
        private List<MyItemType> _myItems = new List<MyItemType>();
    
        public MainWindow()
        {
            InitializeComponent();
    
            _myItems.Add(new MyItemType() {Name = "Item 1", Key = 1});
            _myItems.Add(new MyItemType() {Name = "Item 2", Key = 2});
            _myItems.Add(new MyItemType() {Name = "Item 3", Key = 3});
    
            this.DataContext = this;
        }
    
    
        public List<MyItemType> MyItems
        {
            get { return _myItems; }
            set { _myItems = value; }
        }       
    }
    
    public class MyItemType
    {
        public string Name { get; set; }
        public int Key { get; set; }
    }
    
    public class EntitySelector : Control
    {
        public static object GetPropValue(object src, string propName)
        {
            return src.GetType().GetProperty(propName).GetValue(src, null);
        }
    
        public IList Values 
        {
            get 
            {
                List<object> result = new List<object>();
                foreach (var item in ItemsSource)
                {
                    object o = GetPropValue(item, ValueMemberPath);
                    result.Add(o);
                }
                return result;
            }
        }
    
        public System.Collections.IEnumerable ItemsSource
        {
            get { return (System.Collections.IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }
    
        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(System.Collections.IEnumerable), typeof(EntitySelector), new UIPropertyMetadata(null));
    
    
        public string DisplayMemberPath
        {
            get { return (string)GetValue(DisplayMemberPathProperty); }
            set { SetValue(DisplayMemberPathProperty, value); }
        }
    
        public static readonly DependencyProperty DisplayMemberPathProperty =
            DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(EntitySelector), new UIPropertyMetadata(null));
    
    
        public string ValueMemberPath
        {
            get { return (string)GetValue(ValueMemberPathProperty); }
            set { SetValue(ValueMemberPathProperty, value); }
        }
    
        public static readonly DependencyProperty ValueMemberPathProperty =
            DependencyProperty.Register("ValueMemberPath", typeof(string), typeof(EntitySelector), new UIPropertyMetadata(null));
    }

    Warm regards,

    Matt


    • Modificato Matt Searles giovedì 3 maggio 2012 01:29 Code formatting
    •  
  • giovedì 3 maggio 2012 01:47
     
      Contiene codice

    But I suspect for that binding you just need this...

    <TextBlock FontWeight="Bold" Text="{Binding Path=DisplayMemberPath,RelativeSource={RelativeSource AncestorType=WpfApplication271:EntitySelector}}"></TextBlock>                                                

    Matt

  • giovedì 3 maggio 2012 04:39
     
     
    That would return the name of the property not its value
  • giovedì 3 maggio 2012 23:57
     
      Contiene codice

    Apologies, it will indeed.

    That Binding is for  the name of the property, the ComboBox (to fill in for the AutoCompleteTextBox) in the ControlTemplate I posted displays the value in the second TextBlock 

    <TextBlock Text="{Binding }"></TextBlock>

    Matt