Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.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# 如何在我的ViewModel层次结构中进行气泡式更改?_C#_Wpf_Mvvm - Fatal编程技术网

C# 如何在我的ViewModel层次结构中进行气泡式更改?

C# 如何在我的ViewModel层次结构中进行气泡式更改?,c#,wpf,mvvm,C#,Wpf,Mvvm,My MainView.xaml包含我的SmartForm视图: <Grid Margin="10"> <views:SmartForm/> </Grid> SmartForm视图加载ItemsControl <Grid Margin="10"> <ItemsControl ItemsSource="{Binding DataTypeViews}"/> </Grid> 这是Data

My MainView.xaml包含我的SmartForm视图:

<Grid Margin="10">
    <views:SmartForm/>
</Grid>

SmartForm视图加载ItemsControl

<Grid Margin="10">
    <ItemsControl
        ItemsSource="{Binding DataTypeViews}"/>
</Grid>

这是DataTypeView的可观察集合:

List<FormField> formFields = new List<FormField>();
formFields.Add(new FormField { IdCode = "firstName", Label = "First Name", Value = "Jim" });
formFields.Add(new FormField { IdCode = "lastName", Label = "Last Name", Value = "Smith" });
formFields.Add(new FormField { IdCode = "address1", Label = "Address 1", Value = "123 North Ashton Rd." });
formFields.Add(new FormField { IdCode = "address2", Label = "Address 2", Value = "Box 23434" });
formFields.Add(new FormField { IdCode = "city", Label = "City", Value = "New Haven" });
formFields.Add(new FormField { IdCode = "state", Label = "State", Value = "NM" });
formFields.Add(new FormField { IdCode = "zip", Label = "Zip Code", Value = "34234" });

foreach (FormField formField in formFields)
{
    DataTypeView dtv = new DataTypeView();
    DataTypeViewModel dtvm = new DataTypeViewModel(formField);
    dtv.DataContext = dtvm;
    DataTypeViews.Add(dtv);
}
List formFields=new List();
添加(新的FormField{IdCode=“firstName”,Label=“firstName”,Value=“Jim”});
添加(新的FormField{IdCode=“lastName”,Label=“lastName”,Value=“Smith”});
添加(新的FormField{IdCode=“address1”,Label=“Address 1”,Value=“123 North Ashton Rd.”);
添加(新的FormField{IdCode=“address2”,Label=“Address 2”,Value=“Box 23434”});
添加(newformfield{IdCode=“city”,Label=“city”,Value=“newhaven”});
添加(新的FormField{IdCode=“state”,Label=“state”,Value=“NM”});
添加(新的FormField{IdCode=“zip”,Label=“zip Code”,Value=“34234”});
foreach(FormField中的FormField FormField)
{
DataTypeView dtv=新的DataTypeView();
DataTypeViewModel dtvm=新的DataTypeViewModel(formField);
dtv.DataContext=dtvm;
DataTypeViews.Add(数字电视);
}
每个视图都显示构建表单的标签和文本框:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="90"/>
        <ColumnDefinition Width="400"/>
    </Grid.ColumnDefinitions>
    <StackPanel Orientation="Horizontal" Grid.Column="0">
        <TextBlock Text="{Binding Label}" FontSize="14"/>
        <TextBlock Text=": " FontSize="14"/>
    </StackPanel>
    <TextBox Grid.Column="1" Text="{Binding Value}" FontSize="12"/>
</Grid>

如何将DataTypeViewModel中发生的文本框更改冒泡到SmartFormViewModel中


或者换句话说:如果ViewModel A包含ViewModel B的集合,并且ViewModel B中发生了更改,我如何将更改冒泡到ViewModel A?

您可以让父VM连接到子VM上的PropertyChanged事件。这是一个PITA来跟踪那些被添加/删除的孩子,所以你可以考虑把你的孩子VMS存储在我的<代码> ITEM中。
public sealed class ItemObservableCollection<T> : ObservableCollection<T>
    where T : INotifyPropertyChanged
{
    public event EventHandler<ItemPropertyChangedEventArgs<T>> ItemPropertyChanged;

    protected override void InsertItem(int index, T item)
    {
        base.InsertItem(index, item);
        item.PropertyChanged += item_PropertyChanged;
    }

    protected override void RemoveItem(int index)
    {
        var item= this[index];
        base.RemoveItem(index);
        item.PropertyChanged -= item_PropertyChanged;
    }

    protected override void ClearItems()
    {
        foreach (var item in this)
        {
            item.PropertyChanged -= item_PropertyChanged;
        }

        base.ClearItems();
    }

    protected override void SetItem(int index, T item)
    {
        var oldItem = this[index];
        oldItem.PropertyChanged -= item_PropertyChanged;
        base.SetItem(index, item);
        item.PropertyChanged -= item_PropertyChanged;
    }

    private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        OnItemPropertyChanged((T)sender, e.PropertyName);
    }

    private void OnItemPropertyChanged(T item, string propertyName)
    {
        ItemPropertyChanged.Raise(this, new ItemPropertyChangedEventArgs<T>(item, propertyName));
    }
}

非WPF方法是在DataTypeViewModel上创建静态事件。这允许您在适当时(在属性设置程序或属性更改处理程序中)从DataTypeViewModel触发事件。当然,您还必须在SmartForm中注册事件的侦听器(要求SmartForm了解DataTypeViewModel类型)


或者,我认为您可以创建自己的自定义路由事件。

尽管Kent就在上面,但子视图模型中的所有更改并非都与属性有关,有些更改可能更具语义。在这种情况下,实现的变体可能是一个很好的选择

总之

  • 让所有子视图模型都知道一个“主处理程序对象”,它有一个处理各种更改事件的方法。根据更改的复杂性,可以通过事件或消息与该对象进行通信
  • 让这个主处理程序对象注册处理程序对象的集合,这些对象将处理更改事件,每个事件一个。它们可以按照原始模式进行链接,也可以注册到快速集合(如字典)中以提高性能
  • 使此处理程序对象向已注册的处理程序分派适当的更改
“主”处理程序不必是单例,它的注册表可以依赖于父视图模型本身


希望它足够清晰(很抱歉没有编写代码)

我通过将ViewModel本身向下传递到其中包含的ViewModels中解决了这个问题。

我认为您应该使用中介模式

基本上,它是一个静态类,允许ViewModels(或任何与此相关的类)相互通信并来回传递参数

基本上,ViewModel A开始侦听特定的消息类型(例如ViewModelB已更改),并且每当该事件发生时,ViewModelB仅通知正在侦听该消息类型的任何人,它还可以传递它想要的任何信息

这是调解人的骨架

public static class MyMediator
{
    public static void Register(Action<object> callback, string message);

    public static void NotifyColleagues(string message, object args);
}
然后必须声明如下函数:

void ProcessMessage(object args)
{
    //Do some important stuff here
}
只要ViewModel B想告诉ViewModel A,它就会调用它

MyMediator.NotifyColleagues("ViewModelBChanged",this);
中介类将负责调用viewModel A的回调函数。然后每个人都很高兴

我个人喜欢将这些字符串消息值放入这样的静态类中

static class MediatorMessages
{
    public static string ViewModelBChanged= "ViewModelBChanged";
}
因此,您可以执行以下操作(而不是上述操作):


如果这还不清楚,只需谷歌MVVM mediator,然后点击你心中的内容:)

哦。。。但这是野蛮的方式!
MyMediator.NotifyColleagues("ViewModelBChanged",this);
static class MediatorMessages
{
    public static string ViewModelBChanged= "ViewModelBChanged";
}
 MyMediator.Register(ProcessMessage,MediatorMessages.ViewModelBChanged)
 MyMediator.NotifyColleagues(MediatorMessages.ViewModelBChanged,this);