Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 滚动至UWP列表视图中的新项目_C#_.net_Xaml_Uwp_Windows Community Toolkit - Fatal编程技术网

C# 滚动至UWP列表视图中的新项目

C# 滚动至UWP列表视图中的新项目,c#,.net,xaml,uwp,windows-community-toolkit,C#,.net,Xaml,Uwp,Windows Community Toolkit,我正在使用包含消息的ListView创建聊天应用程序。发送/接收新消息时,ListView应滚动至新消息 我使用的是MVVM,所以ListView看起来像 <ScrollViewer> <ItemsControl Source="{Binding Messages}" /> </ScrollViewer> 我怎么做 编辑:我试图在周年纪念更新之前的版本中实现这一点,创建一个行为。这就是我到目前为止所做的: public class FocusLa

我正在使用包含消息的ListView创建聊天应用程序。发送/接收新消息时,ListView应滚动至新消息

我使用的是MVVM,所以ListView看起来像

<ScrollViewer>
    <ItemsControl Source="{Binding Messages}" />
</ScrollViewer>

我怎么做

编辑:我试图在周年纪念更新之前的版本中实现这一点,创建一个行为。这就是我到目前为止所做的:

public class FocusLastBehavior : Behavior<ItemsControl>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Items.VectorChanged += ItemsOnVectorChanged;
    }

    private void ItemsOnVectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs @event)
    {
        var scroll = VisualTreeExtensions.FindVisualAscendant<ScrollViewer>(AssociatedObject);
        if (scroll == null)
        {
            return;
        }

        var last = AssociatedObject.Items.LastOrDefault();

        if (last == null)
        {
            return;
        }

        var container = AssociatedObject.ContainerFromItem(last);


        ScrollToElement(scroll, (UIElement)container);
    }

    private static void ScrollToElement(ScrollViewer scrollViewer, UIElement element,
        bool isVerticalScrolling = true, bool smoothScrolling = true, float? zoomFactor = null)
    {
        var transform = element.TransformToVisual((UIElement)scrollViewer.Content);
        var position = transform.TransformPoint(new Point(0, 0));

        if (isVerticalScrolling)
        {
            scrollViewer.ChangeView(null, position.Y, zoomFactor, !smoothScrolling);
        }
        else
        {
            scrollViewer.ChangeView(position.X, null, zoomFactor, !smoothScrolling);
        }
    }
}
公共类焦点lastBehavior:Behavior
{
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.Items.VectorChanged+=ItemsOnVectorChanged;
}
私有无效项SonVectorChanged(IObservableVector发送方,IVectorChangedVentArgs@event)
{
var scroll=VisualTreeExtensions.findVisualascentant(关联对象);
如果(滚动==null)
{
返回;
}
var last=AssociatedObject.Items.LastOrDefault();
if(last==null)
{
返回;
}
var container=AssociatedObject.ContainerFromItem(最后一个);
ScrollToElement(滚动,(UIElement)容器);
}
私有静态无效ScrollToElement(ScrollViewer ScrollViewer、UIElement元素、,
bool isVerticalScrolling=true,bool smoothScrolling=true,float?zoomFactor=null)
{
var transform=element.TransformToVisual((UIElement)scrollViewer.Content);
变量位置=transform.TransformPoint(新点(0,0));
如果(垂直滚动)
{
scrollViewer.ChangeView(null,position.Y,zoomFactor,!smoothScrolling);
}
其他的
{
scrollViewer.ChangeView(位置.X,null,zoomFactor,!smoothScrolling);
}
}
}
该代码使用来自的VisualTreeExtensions

但是,调用TransformPoint后的位置始终返回
{0,0}


我做错了什么?

这里vm.newmessageItem是新消息。我用它来获取要滚动的listviewitem

   if (listview != null)
    {
    listview.UpdateLayout();
    listview.ScrollIntoView(vm.newmessageItem);
     var listViewItem = (FrameworkElement)listview.ContainerFromItem(vm.newmessageItem);
        while (listViewItem == null)
        {
        await Task.Delay(1);
        listViewItem = (FrameworkElement)listview.ContainerFromItem(vm.newmessageItem);
        }
        ScrollViewer scroll = Utility.FindFirstElementInVisualTree<ScrollViewer>(listview);

        var topLeft =
        listViewItem .TransformToVisual(listview)                                         .TransformPoint(new Point()).Y;
         var lvih = listViewItem.ActualHeight;
        var lvh = listview.ActualHeight;
         var desiredTopLeft = (lvh - lvih) ;

        var currentOffset = scroll.VerticalOffset;
         var desiredOffset = currentOffset + desiredTopLeft;
        listview.UpdateLayout();
        scroll.ChangeView(null, desiredOffset,null);
        scroll.UpdateLayout();
    }
if(listview!=null)
{
UpdateLayout();
ScrollIntoView(vm.newmessageItem);
var listViewItem=(FrameworkElement)listview.ContainerFromItem(vm.newmessageItem);
while(listViewItem==null)
{
等待任务。延迟(1);
listViewItem=(FrameworkElement)listview.ContainerFromItem(vm.newmessageItem);
}
ScrollViewer scroll=Utility.findFirstElementVisualTree(listview);
左上角变量=
TransformToVisual(listview).TransformPoint(新点()).Y;
var lvih=listViewItem.ActualHeight;
var lvh=listview.ActualHeight;
var desiredTopLeft=(lvh-lvih);
var currentOffset=scroll.VerticalOffset;
var desiredOffset=当前偏移量+desiredTopLeft;
UpdateLayout();
scroll.ChangeView(null,desiredOffset,null);
scroll.UpdateLayout();
}

从Windows 10开始,您可以使用1607版。使用值
KeepLastItemInView
,这似乎是最适合这份工作的

MS UWP文档(2017-2-8)中有一个例子可以归结为以下XAML:

<ListView Source="{Binding Messages}">
   <ListView.ItemsPanel>
       <ItemsPanelTemplate>
           <ItemsStackPanel
               VerticalAlignment="Bottom"
               ItemsUpdatingScrollMode="KeepLastItemInView"
           />
       </ItemsPanelTemplate>
   </ListView.ItemsPanel>
</ListView>

这一行代码将自动转到您请求的列表中的项目。例如,如果您有一个聊天客户端,并且您的
ListView
中会填充每个条目。这将在列表底部显示最新条目。所以,用户不必每次都滚动到底部。此处设置为转到最后一项。在UWP应用程序中工作

MyListView?.ScrollIntoView(MyListView.Items[allMyItemsInList.Count - 1], ScrollIntoViewAlignment.Leading);

您是否获得要滚动到的listviewitem?不要在
ScrollViewer
中包装
ListView
,它可以自动滚动。要访问其内部
ScrollViewer
(例如,要调用其
ChangeView
方法以滚动到给定的像素偏移量),请使用
ListView.GetScrollViewer()
。您检查了吗?我不知道如何引入任务。在那里延迟。这看起来像是对meAlso的一种攻击,我认为访问ViewModel直接耦合逻辑太多,因此这种行为不会被重用。你能将你的代码发布到你收到消息的地方吗?如果你知道你可以编写一个逻辑来获取listview项,而无需访问VMModel,这是理想的解决方案,但不幸的是,我的项目必须以10586为目标。实施ItemsStackPanel是否可行?在我的案例中有哪些选项?不幸的是
项​更新​纸卷​模式
enum在版本10586及以下版本中没有
KeepLastItemInView
,因此您必须自己调用
ListView.ScrollIntoView
。在何处拨打此电话有多个选项。我可能会选择扩展
ListView
并在
onitmchanged
覆盖中调用它,类似于.Nice中讨论的WPF解决方案!顺便说一句,我已经切换到ItemsControl,因为我不需要ListView提供的所有选择跟踪功能。ItemsControl也适用吗?关于ScrollViewer,它是否会与ItemsControl而不是ListView冗余?谢谢当然,如果用
ItemsControl
替换
ListView
,您必须提供自己的滚动处理,并且
ScrollViewer
在这里完全有意义。您仍然可以覆盖
ItemsControl.onitemchanged
(我喜欢这种方法,因为它允许将UI控件代码与模型完全解耦),但是如果您这样做,您需要将
ScrollViewer
引用传递给该方法,或者在可视化树中查找它,然后滚动到底部。请,看看上面的编辑问题。我使用一个行为(为了可重用性)处理它,TransformPoint调用总是返回点0,0,因此它不起作用。
MyListView?.ScrollIntoView(MyListView.Items[allMyItemsInList.Count - 1], ScrollIntoViewAlignment.Leading);