Binding to custom control inside DataTemplate for ItemsControl

狂风中的少年 提交于 2019-11-26 08:37:29

问题


I have a problem with bindings for DataTemplate based on defined DataType in ItemsControl, when I want to bind to my custom user control.

For demonstration purposes, I\'ve created simple Item class example, where I have collection of items like this:

public class Item
{
    public string ItemNameToBeSureWhatPropertyIsBound { get; set; } 
}

In my ViewModel I create such collection, and expose it (with one item for comparison separately):

public class MainWindowViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Item> _items;
    private Item _exampleItem;

    public MainWindowViewModel()
    {
        Items = new ObservableCollection<Item>(new[] { new Item { ItemNameToBeSureWhatPropertyIsBound = \"Me\" }, new Item { ItemNameToBeSureWhatPropertyIsBound = \"MySelf\" }, new Item { ItemNameToBeSureWhatPropertyIsBound = \"Ich\" }, });
        ExampleItem = Items.LastOrDefault();
    }

    public ObservableCollection<Item> Items
    {
        get { return _items; }
        set { _items = value; OnPropertyChanged(); }
    }

    public Item ExampleItem
    {
        get { return _exampleItem; }
        set { _exampleItem = value; OnPropertyChanged();}
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

My custom user control is defined like this:

<UserControl x:Class=\"WpfDataTemplate.ItemRowUserControl\"
         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=\"40\" d:DesignWidth=\"300\"
         x:Name=\"ItemRowControl\" DataContext=\"{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}\">

    <Grid Background=\"Yellow\" Height=\"40\">
        <TextBlock Text=\"{Binding ItemName}\" Foreground=\"Black\"/>
    </Grid>
</UserControl>

...and it has one DependencyProperty in code behind:

public partial class ItemRowUserControl : UserControl
{
    public ItemRowUserControl()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty ItemNameProperty = DependencyProperty.Register(
        \"ItemName\", typeof (string), typeof (ItemRowUserControl), new PropertyMetadata(default(string)));

    public string ItemName
    {
        get { return (string) GetValue(ItemNameProperty); }
        set { SetValue(ItemNameProperty, value); }
    }
}

The problem is, when I try to bind to property of Item in DataTemplate for ItemsControl, which I\'m doing in MainWindow like this (note: I have dummy converter for debugging purposes only, returning value back, and nothing more):

<Window.DataContext>
    <my:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
    <my:MyDummyConverter x:Key=\"MyDummyConverter\" />
</Window.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height=\"50\" />
    </Grid.RowDefinitions>

    <ItemsControl Name=\"ItemsControl\" ItemsSource=\"{Binding Items}\" Grid.Row=\"0\" Background=\"Red\">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate DataType=\"{x:Type my:Item}\">
                <my:ItemRowUserControl ItemName=\"{Binding ItemNameToBeSureWhatPropertyIsBound, Converter={StaticResource MyDummyConverter}}\"  />
                <!--<Grid Background=\"Pink\">
                    <TextBlock Text=\"{Binding ItemNameToBeSureWhatPropertyIsBound, Converter={StaticResource MyDummyConverter}}\" Foreground=\"Black\" Height=\"30\" />
                </Grid>-->
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <Grid Grid.Row=\"1\">
        <my:ItemRowUserControl ItemName=\"{Binding DataContext.ExampleItem.ItemNameToBeSureWhatPropertyIsBound, ElementName=MyWindow, Converter={StaticResource MyDummyConverter}}\" />
    </Grid>
</Grid>

Now, in case I bind to my custom ItemRowUserControl, the value I get into converter (and I see the same in Debug Output) is ItemRowUserControl itself. But if I bind to commented out code, everything works fine. Why is that, and how can I have custom control for DataTemplate so that bindings (offered by intellisense) will work? On the side note: binding to my ItemRowUserControl in grid row 1 (at the bottom) works fine, so I guess control is set to work as expected?


回答1:


The problem is that you explicitly set the DataContext of your UserControl to itself:

DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}

Remove that assignment and write the ItemName binding like this:

<TextBlock Text="{Binding ItemName,
    RelativeSource={RelativeSource AncestorType=UserControl}}"/>

or like this

<TextBlock Text="{Binding ItemName, ElementName=ItemRowControl}"/>


来源:https://stackoverflow.com/questions/27834271/binding-to-custom-control-inside-datatemplate-for-itemscontrol

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!