3

I want to access and change FlowDirection of the RelativePanel in each ListViewItem in its DataTemplate. I tried this exact method, had the same error: How do I access a control inside a XAML DataTemplate? I tried the solution given too, but I'm having

_Container = MyFlipView.ItemContainerGenerator.ContainerFromItem(item);

always return null, even if my item isn't null. I tried placing UpdateLayout() before it, in vain. I tried placing await

Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>{ } 

around it, but also in vain, always returning null. This is my code:

  <ListView x:Name="MessagesListView">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalAlignment" Value="Stretch"/>
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="data:Message">
                <RelativePanel x:Name="RelativeDataTemplate" Background="White" Margin="10,5,10,5" MaxHeight="115" MinHeight="115" MinWidth="400" HorizontalAlignment="Stretch">                        
                    <TextBlock x:Name="MessageToBlock" Text="{x:Bind MessageTo}" FontSize="14"  TextAlignment="DetectFromContent" Foreground="Black" FontWeight="SemiBold" RelativePanel.RightOf="ImageEllipse" Height="20" Margin="10,30,10,20"/>
                    <TextBlock x:Name="AgentNameBlock" Text="{x:Bind AgentName}" Padding="10,0" TextAlignment="DetectFromContent" RelativePanel.RightOf="ImageEllipse" RelativePanel.Below="MessageToBlock" FontSize="14" Foreground="#2d73b5" FontWeight="SemiBold" Height="20"/>
                    <TextBlock x:Name="MessageDateBlock" Text="{x:Bind MessageDate}" TextAlignment="Right" FontSize="14" Foreground="Black" RelativePanel.AlignVerticalCenterWith="MessageToBlock" RelativePanel.AlignRightWithPanel="True" Height="20" Margin="0,30,20,20"/>
                    <TextBlock x:Name="MessageYearBlock" Text="{x:Bind MessageYear}" TextAlignment="Right" FontSize="14" Foreground="#2d73b5" RelativePanel.AlignVerticalCenterWith="AgentNameBlock" RelativePanel.AlignRightWithPanel="True" Margin="0,0,20,0"/>
                </RelativePanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

foreach (var item in myListView.Items)
                {

                    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                    {
                        UpdateLayout();
                        myListView.ScrollIntoView(item);
                        var _Container = myListView.ItemContainerGenerator
                        .ContainerFromItem(item) as FrameworkElement;
                    var _Children = AllChildren(_Container);

                    var _RelativePanel = _Children
                        // only interested in RelativePanel
                        .OfType<RelativePanel>()
                        // only interested in RelativePanel
                        .First(x => x.Name.Equals("RelativeDataTemplate"));

                    // test & set color
                    _RelativePanel.FlowDirection = FlowDirection.RightToLeft;
                    });
                }

 public List<Control> AllChildren(DependencyObject parent)
        {
            var _List = new List<Control>();
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                var _Child = VisualTreeHelper.GetChild(parent, i);
                if (_Child is Control)
                    _List.Add(_Child as Control);
                _List.AddRange(AllChildren(_Child));
            }
            return _List;
        }

Any solution I didn't find yet?

Community
  • 1
  • 1
yalematta
  • 1,389
  • 1
  • 21
  • 36
  • Why you need to access to the `RelativePanel` in the DataTemplate? Do you want to know the DataContext of ListViewItem? – Grace Feng May 03 '16 at 08:09
  • No, I need to change the RelativePanel's FlowDirection to RightToLeft, making all the items in the ListView flip (as the language will change from English to Arabic). – yalematta May 03 '16 at 08:12
  • So for example there is a `CheckBox`, if this `CheckBox` is unchecked, it flows from left to right, and if this `CheckBox` is checked, it flows from right to left? There must be a trigger to make this change happen, otherwise you can directly define it in the xaml code, am I right? – Grace Feng May 03 '16 at 08:16
  • Yes, but you don't understand my question, I want to know when it should be changed, when do you want to trigger it. For example a Button click event, or using checkbox or other user settings. If you want to make it flows from right to left at first, you can just define it in the xaml code, there is no need to access it in the code behind. – Grace Feng May 03 '16 at 08:26
  • Yes, the trigger is set on a certain ComboBox Selection_Changed event where I'm using the foreach loop. – yalematta May 03 '16 at 08:29

1 Answers1

1

As we discussed, you used a ComboBox to choose the language(flow direction), so you can use Data binding and Converter to do this, for example:

<Page.Resources>
    <local:FlowDirectionConverter x:Key="cvt" />
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView x:Name="MessagesListView" ItemsSource="{x:Bind messagelist}">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalAlignment" Value="Stretch" />
                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:Message">
                <RelativePanel x:Name="RelativeDataTemplate" Background="White" Margin="10,5,10,5" MaxHeight="115" MinHeight="115" MinWidth="400" HorizontalAlignment="Stretch" FlowDirection="{Binding ElementName=comboBox, Path=SelectedItem,Converter={StaticResource cvt}}">
                    <TextBlock x:Name="MessageToBlock" Text="{x:Bind MessageTo}" FontSize="14"  TextAlignment="DetectFromContent" Foreground="Black" FontWeight="SemiBold"  Height="20" Margin="10,30,10,20" />
                    <TextBlock x:Name="AgentNameBlock" Text="{x:Bind AgentName}" Padding="10,0" TextAlignment="DetectFromContent"  RelativePanel.Below="MessageToBlock" FontSize="14" Foreground="#2d73b5" FontWeight="SemiBold" Height="20" />
                    <TextBlock x:Name="MessageDateBlock" Text="{x:Bind MessageDate}" TextAlignment="Right" FontSize="14" Foreground="Black" RelativePanel.AlignVerticalCenterWith="MessageToBlock" RelativePanel.AlignRightWithPanel="True" Height="20" Margin="0,30,20,20" />
                    <TextBlock x:Name="MessageYearBlock" Text="{x:Bind MessageYear}" TextAlignment="Right" FontSize="14" Foreground="#2d73b5" RelativePanel.AlignVerticalCenterWith="AgentNameBlock" RelativePanel.AlignRightWithPanel="True" Margin="0,0,20,0" />
                </RelativePanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

    <ComboBox x:Name="comboBox" VerticalAlignment="Bottom" ItemsSource="{x:Bind languagelist}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding language}" />
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
</Grid>

code behind:

public ObservableCollection<Message> messagelist;
public ObservableCollection<MyLanguage> languagelist = new ObservableCollection<MyLanguage>();

public MainPage()
{
    this.InitializeComponent();
    messagelist = new ObservableCollection<Message>();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    //add data to messagelist
    languagelist.Clear();
    languagelist.Add(new MyLanguage { language = "English" });
    languagelist.Add(new MyLanguage { language = "Arabic" });
}

MyLanguage class is quite simple:

public class MyLanguage
{
    public string language { get; set; }
}

and my converter is like this:

public class FlowDirectionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value != null)
        {
            var item = value as MyLanguage;
            if (item.language == "English")
                return FlowDirection.LeftToRight;
            else
                return FlowDirection.RightToLeft;
        }
        return FlowDirection.LeftToRight;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
Grace Feng
  • 16,564
  • 2
  • 22
  • 45