C# 如何从ViewModel更新视图

C# 如何从ViewModel更新视图,c#,xaml,mvvm,listbox,C#,Xaml,Mvvm,Listbox,我有一个viewmodelProductsViewModel,其中一个方法将新产品添加到它存储的ProductList。我目前有一个列表框绑定到产品列表。我添加了一个新产品,方法是将一个按钮绑定到一个简单的命令,该命令调用viewmodel上的相关方法 当视图模型无法与视图“对话”时,如何修改视图以选择已添加到列表框中的新产品,并向下滚动到新项目 编辑 注意,我不希望每次向列表框中添加新项目时自动选择最后一个项目,因为这样会在我将项目导入到列表框时选择最后一个项目,这是我想要避免的。在ViewM

我有一个viewmodel
ProductsViewModel
,其中一个方法将新产品添加到它存储的
ProductList
。我目前有一个
列表框
绑定到
产品列表
。我添加了一个新产品,方法是将一个按钮绑定到一个简单的
命令
,该命令调用viewmodel上的相关方法

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

编辑
注意,我不希望每次向列表框中添加新项目时自动选择最后一个项目,因为这样会在我将项目导入到列表框时选择最后一个项目,这是我想要避免的。

在ViewModel“SelectedProduct”中创建一个属性(显然,需要更改raise属性。将新产品添加到ProductList后,还需要使用此新产品更新SelectedProduct。
在视图中,将列表框的SelectedItem绑定到CurrentProduct。

在ViewModel“SelectedProduct”中创建一个属性(显然,它将需要引发属性更改。将新产品添加到产品列表后,也可以使用此新产品更新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);
    }
}
正如您所看到的,我已经通过混合行为实现了这一点,如果您愿意,您当然可以通过常规的附加行为来实现,但我在这里保持简单:

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);
    }

}
公共类ListBoxScrollBehavior:Behavior
{
公共ListBoxScrollHandler ScrollHandler
{
获取{return(ListBoxScrollHandler)GetValue(ScrollHandlerProperty);}
set{SetValue(ScrollHandlerProperty,value);}
}
公共静态只读DependencyProperty ScrollHandlerProperty=
DependencyProperty.Register(“ScrollHandler”),typeof(ListBoxScrollHandler),
typeof(ListBoxScrollBehavior),新的PropertyMetadata(null,OnScrollHandlerChanged));
受保护的覆盖无效附加()
{
base.onatached();
}
附加时受保护的覆盖无效()
{
base.OnDetaching();
}
CrollHandlerChanged上的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var行为=d作为ListBoxScrollBehavior;
if(行为==null)
返回;
var oldHandler=e.OldValue作为ListBoxScrollHandler;
if(oldHandler!=null)
oldHandler.ScrollEvent-=behavior.ScrollTo;
var newHandler=e.NewValue作为ListBoxScrollHandler;
if(newHandler!=null)
newHandler.ScrollEvent+=behavior.ScrollTo;
}
公共无效滚动到(对象项)
{
this.AssociatedObject.ScrollIntoView(项目);
}
}
因此,我们的行为包含一个“ScrollHandler”依赖属性,我们可以绑定到视图模型并通过调用listbox的ScrollIntoView方法进行响应。之后,只需创建一个视图模型,该模型提供此属性以及初始化列表项的代码和一个命令处理程序,该命令处理程序响应按钮按下并调用其scroll处理程序的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());
    }
}
public类MainViewModel:ViewModelBase
{
私有ObservableCollection_MyItems=新ObservableCollection();
公共可观测集合MyItems
{
获取{返回此。\u MyItems;}
设置{this._MyItems=value;RaisePropertyChanged();}
}
私有字符串_SelectedItem;
公共字符串SelectedItem
{
获取{返回此。\u SelectedItem;}
设置{this._SelectedItem=value;RaisePropertyChanged();}
}
公共ICommand scroll命令{get{returnnewrelaycommand(OnScroll);}
私有void OnScroll(字符串项)
{
this.ScrollHandler.ScrollTo(项目);
}
私有ListBoxScrollHandler _ScrollHandler=新ListBoxScrollHandler();
公共ListBoxScrollHandler ScrollHandler
{
获取{返回此。\u ScrollHandler;}
设置{this.\u ScrollHandler=value;RaisePropertyChanged();}
}
公共主视图模型()
{
对于(int i=0;i<1000;i++)
this.MyItems.Add(i.ToString());
}
}

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

一般来说,实现这一点的最佳方法是使用行为。实现可能取决于您的特定需求,但我在这里提供的是一个通用示例,演示如何使视图模型触发列表框滚动到您选择的特定项目

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

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

    public void ScrollTo(object item)
    {
        if (this.ScrollEvent != null)
            this.ScrollEvent(item);
    }
}
正如您所看到的,我已经通过混合行为实现了这一点,如果您愿意,您当然可以通过常规的附加行为来实现,但我在这里保持简单:

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);
    }

}
公共类ListBoxScrollBehavior:Behavior
{
公共ListBoxScrollHandler ScrollHandler
{
获取{return(ListBoxScrollHandler)GetValue(ScrollHandlerProperty);}
set{SetValue(ScrollHandlerProperty,value);}
}
公共静态只读DependencyProperty ScrollHandlerProperty=
DependencyProperty.Register(“ScrollH