繁体   English   中英

如何从ViewModel更新视图

[英]How to update the View from a ViewModel

我有一个viewmodel ProductsViewModel ,其中一种方法将新产品添加到它存储的ProductList中。 我目前有一个ListBox绑定到ProductList 我通过将按钮绑定到一个简单的Command来添加新产品,该Command调用了viewmodel上的相关方法。

当视图模型无法与视图“对话”时,如何修改视图以选择已添加到ListBox的新产品并向下滚动到新项目?

编辑

请注意,我不希望每次将新项目添加到列表框中时都自动选择最后一个项目,因为当我将项目导入到要避免的列表框中时,它将选择最后一个项目。

在ViewModel'SelectedProduct'中创建一个属性(显然,它需要提高属性。在将新产品添加到ProductList之后,还要使用此新产品更新SelectedProduct。在视图中,将ListBox的SelectedItem绑定到CurrentProduct。

通常,实现此目标的最佳方法是行为。 该实现可能取决于您的特定要求,但是我将在此处提供一个通用示例,该示例演示如何使视图模型触发ListBox滚动到您选择的特定项目。

首先,您需要一种从视图模型到视图的通信方式,您不能直接绑定到XAML中的事件,而是可以将事件封装在包装器中并绑定到该包装器:

public class ListBoxScrollHandler
{
    public event Action<object> ScrollEvent;

    public void ScrollTo(object item)
    {
        if (this.ScrollEvent != null)
            this.ScrollEvent(item);
    }
}

该类包含一个我们的行为可以绑定到的事件,以及一个我们的视图模型可以调用的ScrollTo方法。 对于该视图,我们只需要创建一个简单的列表框,用数字(实际上是字符串)填充这个列表框,并使用一个按钮强制我们滚动到内容为“ 500”的元素:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition />
    </Grid.RowDefinitions>

    <Button Content="Scroll to 500" HorizontalAlignment="Left" VerticalAlignment="Top" Command="{Binding ScrollCommand}" CommandParameter="500" />
    <ListBox Grid.Row="1" ItemsSource="{Binding MyItems}" SelectedItem="{Binding CurrentItem}" ScrollViewer.VerticalScrollBarVisibility="Visible">
        <i:Interaction.Behaviors>
            <behaviors:ListBoxScrollBehavior ScrollHandler="{Binding ScrollHandler}" />
        </i:Interaction.Behaviors>
    </ListBox>
</Grid>

如您所见,我已经通过Blend行为实现了这一点,当然,您可以根据需要使用常规的附加行为来完成此操作,但是我在这里保持简单:

public class ListBoxScrollBehavior : Behavior<ListBox>
{
    public ListBoxScrollHandler ScrollHandler
    {
        get { return (ListBoxScrollHandler)GetValue(ScrollHandlerProperty); }
        set { SetValue(ScrollHandlerProperty, value); }
    }

    public static readonly DependencyProperty ScrollHandlerProperty =
        DependencyProperty.Register("ScrollHandler", typeof(ListBoxScrollHandler),
        typeof(ListBoxScrollBehavior), new PropertyMetadata(null, OnScrollHandlerChanged));

    protected override void OnAttached()
    {
        base.OnAttached();
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
    }

    private static void OnScrollHandlerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behavior = d as ListBoxScrollBehavior;
        if (behavior == null)
            return;

        var oldHandler = e.OldValue as ListBoxScrollHandler;
        if (oldHandler != null)
            oldHandler.ScrollEvent -= behavior.ScrollTo;

        var newHandler = e.NewValue as ListBoxScrollHandler;
        if (newHandler != null)
            newHandler.ScrollEvent += behavior.ScrollTo;
    }

    public void ScrollTo(object item)
    {
        this.AssociatedObject.ScrollIntoView(item);
    }

}

因此,我们的行为包含一个“ ScrollHandler”依赖项属性,可以将其绑定到我们的视图模型,并通过调用列表框的ScrollIntoView方法进行响应。 之后,只需创建一个视图模型即可,该视图模型提供此属性以及用于初始化列表项的代码以及一个响应按钮按下并调用其滚动处理程序的ScrollTo方法的命令处理程序:

public class MainViewModel : ViewModelBase
{
    private ObservableCollection<string> _MyItems = new ObservableCollection<string>();
    public ObservableCollection<string> MyItems
    {
        get { return this._MyItems; }
        set { this._MyItems = value; RaisePropertyChanged(); }
    }

    private string _SelectedItem;
    public string SelectedItem
    {
        get { return this._SelectedItem; }
        set { this._SelectedItem = value; RaisePropertyChanged(); }
    }

    public ICommand ScrollCommand { get { return new RelayCommand<string>(OnScroll); } }
    private void OnScroll(string item)
    {
        this.ScrollHandler.ScrollTo(item);
    }

    private ListBoxScrollHandler _ScrollHandler = new ListBoxScrollHandler();
    public ListBoxScrollHandler ScrollHandler
    {
        get { return this._ScrollHandler;}
        set { this._ScrollHandler = value; RaisePropertyChanged(); }
    }

    public MainViewModel()
    {
        for (int i = 0; i < 1000; i++)
            this.MyItems.Add(i.ToString());
    }
}

运行代码,单击按钮,列表框将向下滚动到包含“ 500”内容的元素。 显然,如果只需要此行为的子集(例如,滚动到当前选定的项目),则可以相应地修改此行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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