我有使用Prism制作的非常简单的MVVM代码:
如何将模型对象(人或公司)从列表框的SelectedItem(IContact)传递到与DataTemplateSelector返回的视图相匹配的两个视图模型(人视图或公司视图模型)之一(人视图或CompanyView)?
谢谢!
有很多代码,但是非常简单:
我有以下Model类:
public interface IContact
{
string Address { get; set; }
}
public class Person : IContact
{
public string Address { get; set; }
}
public class Company : IContact
{
public string Address { get; set; }
}
我有以下ViewModel类:
public class ContactViewModel : Prism.Mvvm.BindableBase
{
private ObservableCollection<IContact> _contacts = new ObservableCollection<IContact>();
public ObservableCollection<IContact> Contacts
{
get { return _contacts; }
set { SetProperty(ref _contacts, value); }
}
}
public class PersonViewModel : Prism.Mvvm.BindableBase
{
private Person _person; // I want to set this from the ListBox's SelectedItem
public Person Person
{
get { return _person; }
set { SetProperty(ref _person, value); }
}
}
public class CompanyViewModel : Prism.Mvvm.BindableBase
{
private Company _company; // I want to set this from the ListBox's SelectedItem
public Company Company
{
get { return _company; }
set { SetProperty(ref _company, value); }
}
}
我有以下View类:
<UserControl x:Class="ContactView"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True" >
<UserControl.Resources>
<DataTemplate x:Key="PersonDataTemplate">
<local:PersonView>
// How can I pass the SelectedItem to the ViewModel of this UserControl?
</local:PersonView>
</DataTemplate>
<DataTemplate x:Key="CompanyDataTemplate">
<local:CompanyView>
// How can I pass the SelectedItem to the ViewModel of this UserControl?
</local:CompanyView>
</DataTemplate>
<dataTemplateSelectors:contactDataTemplateSelector x:Key="templateSelector"
PersonDataTemplate="{StaticResource PersonDataTemplate}"
CompanyDataTemplate="{StaticResource CompanyDataTemplate}"/>
</UserControl.Resources>
<Grid>
// RowDefinitions here
<ListBox ItemsSource="{Binding Contacts}" x:Name="myListBox">
// ItemTemplate here
</ListBox>
<ContentControl Grid.Row="1"
Content="{Binding ElementName=myListBox, Path=SelectedItem}"
ContentTemplateSelector="{StaticResource templateSelector}" />
</Grid>
</UserControl>
人员:
<UserControl x:Class="PersonView"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True" >
<Grid>
<TextBlock Text="{Binding Person.Address}" />
</Grid>
</UserControl>
公司:
<UserControl x:Class="CompanyView"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True" >
<Grid>
<TextBlock Text="{Binding Company.Address}" />
</Grid>
</UserControl>
这:
public class ContactDataTemplateSelector : DataTemplateSelector
{
public DataTemplate PersonDataTemplate { get; set; }
public DataTemplate CompanyDataTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is Person)
{
return PersonDataTemplate;
}
if (item is Company)
{
return CompanyDataTemplate;
}
}
}
答案 0 :(得分:1)
请勿在此处先使用视图(也称为ViewModelLocator
)。首先查看模型。
长版:
使Contacts
(列表框的项目来源)包含视图模型。然后直接将SelectedItem
绑定到内容控件。
列表框使用一个数据模板显示联系人,内容控件使用另一个。您甚至不需要选择器,只需在数据模板上设置DataType
。
当您已经准备好要显示的项目(即其视图模型)时,只需绑定并显示该项目即可。如果您想导航到应用程序中的屏幕(例如登录对话框),请使用ViewModelLocator
。基本上,这是没有准备好视图模型的解决方法。
答案 1 :(得分:0)
这个答案仅仅是因为Sagar Panwala问我是怎么做到的...
最后,我并没有完全按照我最初的想象去做。
我做了一些不同:
BindableBase
ViewModel:
public Dictionary<string, Dictionary<string, PositioningModuleSetting>>? SelectedSettings;
PositioningModuleSetting
类:
public class PositioningModuleSetting
{
public string Section { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public dynamic value = null!;
public string description = string.Empty;
public PositioningModuleRestart restart;
public Action<PositioningModuleSetting>? OnSettingChanged { get; set; }
public bool BoolValue
{
get { return value; }
set { this.value = value; OnSettingChanged?.Invoke(this); }
}
public double DoubleValue
{
get { return value; }
set { this.value = value; OnSettingChanged?.Invoke(this); }
}
public long LongValue
{
get { return value; }
set { this.value = value; OnSettingChanged?.Invoke(this); }
}
public string StringValue
{
get { return value; }
set { this.value = value; OnSettingChanged?.Invoke(this); }
}
public object ObjectValue
{
get { return value; }
set { this.value = value; OnSettingChanged?.Invoke(this); }
}
public void Initialize(string section, string name, Action<PositioningModuleSetting> onSettingChanged)
{
Section = section;
Name = name;
OnSettingChanged = onSettingChanged;
}
}
DataTemplateSelector
类:
public class SettingsDataTemplateSelector : DataTemplateSelector
{
public DataTemplate? DefaultDataTemplate { get; set; }
public DataTemplate? BoolDataTemplate { get; set; }
public DataTemplate? DoubleDataTemplate { get; set; }
public DataTemplate? LongDataTemplate { get; set; }
public DataTemplate? StringDataTemplate { get; set; }
public override DataTemplate? SelectTemplate(object item, DependencyObject container)
{
if (item is KeyValuePair<string, PositioningModuleSetting> pair)
{
return pair.Value.value switch
{
bool _ => BoolDataTemplate,
double _ => DoubleDataTemplate,
long _ => LongDataTemplate,
string _ => StringDataTemplate,
_ => DefaultDataTemplate
};
}
return DefaultDataTemplate;
}
}
UserControl
视图:
<UserControl.Resources>
<DataTemplate x:Key="DefaultDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock MinWidth="180" Text="{Binding Path=Key}" Style="{StaticResource LabelTextBlock}" FontSize="{StaticResource SmallestFontSize}" />
<TextBox MinWidth="240" Text="{Binding Path=Value.ObjectValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="{StaticResource SmallestFontSize}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="BoolDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock MinWidth="180" Text="{Binding Path=Key}" Style="{StaticResource LabelTextBlock}" FontSize="{StaticResource SmallestFontSize}" />
<CheckBox IsChecked="{Binding Path=Value.BoolValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DoubleDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock MinWidth="180" Text="{Binding Path=Key}" Style="{StaticResource LabelTextBlock}" FontSize="{StaticResource SmallestFontSize}" />
<TextBox MinWidth="240" Text="{Binding Path=Value.DoubleValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="{StaticResource SmallestFontSize}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="LongDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock MinWidth="180" Text="{Binding Path=Key}" Style="{StaticResource LabelTextBlock}" FontSize="{StaticResource SmallestFontSize}" />
<TextBox MinWidth="240" Text="{Binding Path=Value.LongValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="{StaticResource SmallestFontSize}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="StringDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock MinWidth="180" Text="{Binding Path=Key}" Style="{StaticResource LabelTextBlock}" FontSize="{StaticResource SmallestFontSize}" />
<TextBox MinWidth="240" Text="{Binding Path=Value.StringValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="{StaticResource SmallestFontSize}" />
</StackPanel>
</DataTemplate>
<dataTemplateSelectors:SettingsDataTemplateSelector x:Key="templateSelector"
DefaultDataTemplate="{StaticResource DefaultDataTemplate}"
BoolDataTemplate="{StaticResource BoolDataTemplate}"
DoubleDataTemplate="{StaticResource DoubleDataTemplate}"
LongDataTemplate="{StaticResource LongDataTemplate}"
StringDataTemplate="{StaticResource StringDataTemplate}" />
</UserControl.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Path=SelectedSettings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Key}" Style="{StaticResource LabelTextBlock}" />
<ItemsControl ItemsSource="{Binding Path=Value}" ItemTemplateSelector="{StaticResource templateSelector}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>