【发布时间】:2015-07-21 08:45:41
【问题描述】:
我遇到过这种情况,我需要从ViewModel 访问View 中的控件。为了编写一个将ComboBox中的选定项目添加到列表中的方法。
我的问题是如何从ViewModel 访问View 控件?我应该遵循某种设计模式来允许这样做吗?
下面的方法编码在后面的View's 代码中,我知道如果遵循 MVVM 模式,这是不好的做法,因为涉及到紧密耦合。这就是为什么我打算将此方法移至ViewModel。
该方法的目的是从两个ComboBoxes中取出当前选中的项目并添加到一个Key/Value List中:
public void AddGradeSubjectChoiceToList()
{
string SelectedSubjectName = "null data";
int SelectedPoints = 01;
SelectedSubjectName = subjectCmbBx.SelectedItem.ToString();
try {
SelectedPoints = int.Parse(ordinaryGradeCmbBx.SelectedValue.ToString());
}
catch (Exception e)
{
//log error here..
}
List<StringKeyValue> SubjectPointKVTemp = new List<StringKeyValue>();
//Add selected pair to list
SubjectPointKVTemp.Add(new StringKeyValue { Key = SelectedSubjectName, Value = SelectedPoints });
SubjectPointKV = SubjectPointKVTemp;
}
MainPage 的 XAML 设置如下,有两个组合框,分别用于科目和成绩。 addGrade 按钮将调用该方法将所选对添加到列表中:
<Page x:Class="LC_Points.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:converter="using:LC_Points.Converter"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="using:LC_Points"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{Binding Source={StaticResource Locator}}"
mc:Ignorable="d">
<Page.Resources>
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<converter:BoolToNonVisibilityConverter x:Key="BoolToNonVisibilityConverter" />
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40*" />
<RowDefinition Height="20*" />
<RowDefinition Height="30*" />
<RowDefinition Height="30*" />
<RowDefinition Height="20*" />
<RowDefinition Height="20*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<ComboBox x:Name="subjectCmbBx"
Grid.Row="1"
Grid.ColumnSpan="2"
Width="174"
HorizontalAlignment="Left"
VerticalAlignment="Top"
DisplayMemberPath="Subject"
Header="Subjects"
ItemsSource="{Binding Subjects}"
PlaceholderText="Pick a subject" />
<ComboBox x:Name="ordinaryGradeCmbBx"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Width="170"
HorizontalAlignment="Right"
DisplayMemberPath="Key"
Header="Grades"
ItemsSource="{Binding OrdinaryGradePointKV}"
PlaceholderText="Pick a grade"
Visibility="{Binding IsHigherToggled,
Mode=TwoWay,
Converter={StaticResource BoolToNonVisibilityConverter}}" />
<Button x:Name="addGradeBtn"
Grid.Row="2"
HorizontalAlignment="Left"
Command="{Binding Path=AddGradeCommand}"
Content="Add Grade" />
<ToggleButton x:Name="ordinaryTglBtn"
Grid.Row="3"
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
Content="Ordinary"
IsChecked="{Binding IsOrdinaryToggled,
Mode=TwoWay}" />
</Grid>
</Page>
ViewModel 的精简实现如下供参考,在 cmets 中显示我如何平移以实现 AddGradeSubjectChoiceToList() 方法:
namespace LC_Points.ViewModel
{
public class MainViewModel : ViewModelBase
{
private ScoreModel _scoreModel;
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(ScoreModel GradeModel)
{
_scoreModel = GradeModel;
//call methods to initilise list data
GetSubjectTypes();
GetOrdinaryGradePairs();
}
public List<ScoreModel> Subjects { get; set; }
public List<StringKeyValue> OrdinaryGradePointKV { get; set; }
//ordinary toggle button bool
private bool _isOrdinaryToggled;
public bool IsOrdinaryToggled
{
get
{
return _isOrdinaryToggled;
}
set
{
_isOrdinaryToggled = value;
RaisePropertyChanged("IsOrdinaryToggled");
}
}
//Need to add same method from code behind to VM here
//but don't have access to the View's controlsMethod to store Subject and Grade from Combo Boxes
public void AddGradeSubjectChoiceToList()
{
}
//This Relay Command is tied to the button in the View, that will be used
//to call the AddGradeSubjectChoiceToList method
RelayCommand addGradeCommand;
public RelayCommand AddGradeCommand
{
get
{
if (addGradeCommand == null)
{
addGradeCommand = new RelayCommand(() =>
{
AddGradeSubjectChoiceToList
});
}
return addGradeCommand;
}
}
public class StringKeyValue
{
public string Key { get; set; }
public int Value { get; set; }
}
public void GetOrdinaryGradePairs()
{
List<StringKeyValue> ordinaryGradePointKVTemp = new List<StringKeyValue>();
ordinaryGradePointKVTemp.Add(new StringKeyValue { Key = "A1", Value = 60 });
ordinaryGradePointKVTemp.Add(new StringKeyValue { Key = "A2", Value = 50 });
ordinaryGradePointKVTemp.Add(new StringKeyValue { Key = "B1", Value = 45 });
ordinaryGradePointKVTemp.Add(new StringKeyValue { Key = "B2", Value = 40 });
ordinaryGradePointKVTemp.Add(new StringKeyValue { Key = "B3", Value = 35 });
ordinaryGradePointKVTemp.Add(new StringKeyValue { Key = "C1", Value = 30 });
ordinaryGradePointKVTemp.Add(new StringKeyValue { Key = "C2", Value = 25 });
ordinaryGradePointKVTemp.Add(new StringKeyValue { Key = "C3", Value = 20 });
OrdinaryGradePointKV = ordinaryGradePointKVTemp;
}
public void GetSubjectTypes()
{
List<ScoreModel> subjectList = new List<ScoreModel>();
// Adding Subjects to List
subjectList.Add(new ScoreModel { Subject = "Accounting" });
subjectList.Add(new ScoreModel { Subject = "Agricultural Economics" });
subjectList.Add(new ScoreModel { Subject = "Agricultural Science" });
subjectList.Add(new ScoreModel { Subject = "Ancient Greek" });
subjectList.Add(new ScoreModel { Subject = "Applied Math" });
subjectList.Add(new ScoreModel { Subject = "Arabic" });
subjectList.Add(new ScoreModel { Subject = "Art" });
subjectList.Add(new ScoreModel { Subject = "Artistic & Creative Group" });
subjectList.Add(new ScoreModel { Subject = "Biology" });
subjectList.Add(new ScoreModel { Subject = "Business" });
Subjects = subjectList;
}
}
}
【问题讨论】:
-
能否请您发布适当的 XAML 代码?
-
将上面的 XAML 添加到问题中。
-
您应该将每个组合框的
SelectedItem绑定到视图模型,而不是将视图模型耦合到视图。 -
该实现的任何代码示例? ^^
-
您不会将 UI 发送到 ViewModel。如果您想这样做,请继续并在代码隐藏中完成您的工作。如果您知道如何绑定到 ItemsSource 属性,则可以绑定到 SelectedItem 属性。相同的模式。
标签: c# design-patterns mvvm view viewmodel