stacker flow stacker flow - 25 days ago 8
C# Question

Get Ancestor Source in Wpf

I am trying to get the ancestor ItemsControl.ItemTemplate source as my DataGrid source but i could not handle the case. I tried the following case in my xaml. But it did not work and datagrid is empty.

Here is my xaml:

<ItemsControl ItemsSource="{Binding Accounts}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander ExpandDirection="Down" FlowDirection=" RightToLeft">
<Expander.Header>
<DataGrid FlowDirection="LeftToRight"
ItemsSource="{RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemTemplate}}}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding UserName}" />
<DataGridTextColumn Binding="{Binding Password}" />
</DataGrid.Columns>
</DataGrid>
</Expander.Header>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>




Accounts property implementation is like:

public List<User> Accounts = new List<User>();
Accounts.Add(new User("userName1","password1"));
Accounts.Add(new User("userName2","password2"));


And my User.cs is like:

public class User : INotifyPropertyChanged
{
public string UserName{get; set;}
public string Password{get; set;}


public UserAccount(string userName, string password)
{
UserName = userName;
Password = password;
}
}

ASh ASh
Answer

Basically, this code doesn't create a binding

ItemsSource="{RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemTemplate}}}"

also ancestor type is incorrect.

try this Binding:

ItemsSource="{Binding Path=DataContext.Accounts, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"

or use ElementName:

<ItemsControl Name="LstAccounts" ItemsSource="{Binding Accounts}">

and

ItemsSource="{Binding Path=DataContext.Accounts, ElementName=LstAccounts}"

code above fixes binding, but produces unexpected results. here is a solution to show a single object in a DataGrid

for ItemSource binding I created a converter (my own older answer)

public class ItemsSourceConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // doesn't allow to add new rows in DataGrid
        return Enumerable.Repeat(value, 1).ToArray();            
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

and here is modified ItemsControl. Converter is stored in resources and used in ItemsSource binding. DataGrid autogenerates columns

<ItemsControl ItemsSource="{Binding Accounts}">
    <ItemsControl.Resources>
        <local:ItemsSourceConverter x:Key="Enumerator"/>
    </ItemsControl.Resources>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Expander ExpandDirection="Down" FlowDirection=" RightToLeft">
                <Expander.Header>
                    <DataGrid FlowDirection="LeftToRight" 
                              ItemsSource="{Binding ., Converter={StaticResource Enumerator}}"/>
                </Expander.Header>
            </Expander>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

here is a screenshot

it looks like this

Comments