简体   繁体   中英

How to get a scrollviewer's scrollable height to update in an interaction request

EDIT: I discovered that it was in fact the items presenter in my items control within the scroll viewer that wasn't updating correctly rather than the scrollviewer. I added an answer to reflect this.

I have a simple set up for a custom view interaction request. The view contains a scroll viewer but the scroll viewers scrollable height doesn't update if the items control within it has an items source update. The relevant code is below.

Confirmation model:

public class ProfileImportConfirmation : Confirmation
{
    public ObservableCollection<ProfileAcceptPair> PossibleProfiles { get; set; } = new ObservableCollection<ProfileAcceptPair>();
    public ObservableCollection<Profile> ConfirmedProfiles { get; set; } = new ObservableCollection<Profile>();
}

ViewModel:

public class ProfileImportPopupViewModel : BindableBase, IInteractionRequestAware
{
    ProfileImportConfirmation _profileImportConfirmation;

    public InteractionRequest<Confirmation> YesNoConfirmationInteractionRequest { get; }

    public DelegateCommand AcceptCommand { get; set; }
    public DelegateCommand CancelCommand { get; set; }

    public ProfileImportPopupViewModel()
    {
        AcceptCommand = new DelegateCommand(Accept);
        CancelCommand = new DelegateCommand(Cancel);
        YesNoConfirmationInteractionRequest = new InteractionRequest<Confirmation>();
    }

    public INotification Notification
    {
        get { return _profileImportConfirmation; }
        set
        {
            if (value is ProfileImportConfirmation confirmation)
            {
                _profileImportConfirmation = confirmation;
                OnPropertyChanged(nameof(Notification));
            }
        }
    }

    public Action FinishInteraction { get; set; }

    void Cancel()
    {
        _profileImportConfirmation.Confirmed = false;
        FinishInteraction();
    }

    void Accept()
    {
        _profileImportConfirmation.Confirmed = true;
        _profileImportConfirmation.ConfirmedProfiles.Clear();
        _profileImportConfirmation.ConfirmedProfiles.AddRange(_profileImportConfirmation.PossibleProfiles.Where(p => p.Accepted).Select(p => p.Profile).ToList());
        if (_profileImportConfirmation.ConfirmedProfiles.Any(p => p.IsRootProfile))
            YesNoConfirmationInteractionRequest.Raise(
                new Confirmation
                {
                    Title = DisplayStrings.AreYouSureLabel,
                    Content = "Proceed?"
                },
                confirmed => FinishInteraction());
        else
        {
            FinishInteraction();
        }
    }
}

View:

<UserControl 
         MaxHeight="500"
         MinWidth="400"
         d:DataContext="{d:DesignInstance Type=viewModels:ProfileImportPopupViewModel, IsDesignTimeCreatable=False}"
         Loaded="ProfileImportPopup_OnLoaded">

<i:Interaction.Triggers>
    <mvvm:InteractionRequestTrigger SourceObject="{Binding YesNoConfirmationInteractionRequest, Mode=OneWay}">
        <mvvm:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource PopupWindow}" WindowStartupLocation="CenterOwner">
            <mvvm:PopupWindowAction.WindowContent>
                <popups:YesNoConfirmationPopup />
            </mvvm:PopupWindowAction.WindowContent>
        </mvvm:PopupWindowAction>
    </mvvm:InteractionRequestTrigger>
</i:Interaction.Triggers>

<Grid Margin="30, 0, 30, 30">
    <Grid.RowDefinitions>
        <RowDefinition Height="50"/>
        <RowDefinition Height="50"/> 
        <RowDefinition Height="*"/>
        <RowDefinition Height="40"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Label Grid.ColumnSpan="2" Content="{Binding Notification.Title}" HorizontalAlignment="Left" FontFamily="{StaticResource 'Brandon Grotesque Bold'}" FontSize="{StaticResource LargeFontSize}"/>

    <Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Content="{Binding Notification.Content}" HorizontalAlignment="Center" VerticalContentAlignment="Center" FontFamily="{StaticResource 'Brandon Grotesque Bold'}" FontSize="{StaticResource LargeFontSize}"/>

    <ScrollViewer x:Name="aoeu" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" CanContentScroll="True" VerticalScrollBarVisibility="Auto">
        <ItemsControl ItemsSource="{Binding Notification.PossibleProfiles}" Margin="0, 0, 30, 0">
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type models:ProfileAcceptPair}">
                    <CheckBox Style="{StaticResource RightAlignedCheckBox}" Content="{Binding Name}" IsChecked="{Binding Accepted}" HorizontalContentAlignment="Right"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>

    <Button Grid.Row="3" Grid.Column="0" HorizontalAlignment="Center" Content="{x:Static resources:DisplayStrings.CancelButton}" Style="{StaticResource ModalWindowButton}" Command="{Binding CancelCommand}" Margin="0" VerticalAlignment="Center"/>
    <Button Grid.Row="3" Grid.Column="1" Content="{x:Static resources:DisplayStrings.OKButton}" Style="{StaticResource ModalWindowButton}" Command="{Binding AcceptCommand}" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>

It seems the items source is updating fine and I can see the new item element hidden below the scroll viewer but I can't scroll down to it.

How can I get the scrollable height to update?

The problem wasn't with the scroll viewer. It was the items presenter from the items control inside the scroll viewer. It wasn't updating it's height on items changing.

My solution isn't ideal but it worked. I added a loaded event handler for the user control in the code behind. I then named the items control and using that found the items presenter child and called invalidate measure.

void Popup_OnLoaded(object sender, RoutedEventArgs e)
        {
            var itemsPresenter = (ItemsPresenter) FindChild(MyItemsControl, typeof(ItemsPresenter));
            itemsPresenter.InvalidateMeasure();
        }

public DependencyObject FindChild(DependencyObject o, Type childType)
            {
                DependencyObject foundChild = null;
                if (o != null)
                {
                    var childrenCount = VisualTreeHelper.GetChildrenCount(o);
                    for (var i = 0; i < childrenCount; i++)
                    {
                        var child = VisualTreeHelper.GetChild(o, i);
                        if (child.GetType() != childType)
                        {
                            foundChild = FindChild(child, childType);
                        }
                        else
                        {
                            foundChild = child;
                            break;
                        }
                    }
                }
                return foundChild;
            }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM