如何从ViewModel更新视图

时间:2016-01-14 21:20:57

标签: c# xaml mvvm listbox

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

如何修改视图以选择已添加到ListBox的新产品,并在视图模型无法通话时向下滚动到新项目&# 39;观点?

修改

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

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:0)

一般来说,实现这一目标的最佳方法是行为。实现可能取决于您的具体要求,但我在这里提供的是一个通用示例,说明如何使视图模型触发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”依赖项属性,我们可以将它们绑定到我们的视图模型,并通过调用listbox的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”内容的元素。显然,如果您只需要此行为的子集(例如滚动到当前选定的项目),则可以相应地修改此行为。