我确信这是一个非常常见的场景,我想知道MVVM开发人员如何解决这个问题。
我有一个按需实例化的ViewModel,并持续存在,直到用户明确删除。它根据需要将相应的View加载到UI上。 View可以卸载,它的ViewModel可能仍然存在于应用程序中。
在我的场景中,我在视图中有一个预设颜色的ListBox(通过将其ItemsSource设置为Xaml定义的SolidColorBrush的ObservableCollection)。
我将ListBox的SelectedItem属性绑定到ViewModel中的属性,以便在再次加载View时,SelectedItem正确显示ListBox中最后选择的项目,并且当用户选择不同的颜色时,VM将处理变化。
我的问题是,你如何设置默认值,在首次加载View时,将SolidColorBrush的ObservableCollection中的第三项说成ViewModel?
答案 0 :(得分:2)
通常我在构造函数中设置默认值,除非默认值可能需要一些时间才能加载,在这种情况下,我将调用一个方法在绑定属性的getter中设置它。
这样做的原因是为了简化维护。如果我正在寻找我设置默认值的位置,以便我可以查看或更改它,我检查的第一个位置是构造函数。它比滚动属性更容易找到,并且已知包含初始化逻辑。
MyViewModel()
{
// Set defaults
SelectedColor = Brushes.Red;
}
对于可能需要更长时间加载的属性,我使用在getter中调用的方法也是出于同样的原因。通常我的所有属性及其getter / setter都隐藏在一个区域中,我发现在我的类中找到一个名为LoadColors()
的方法比在巨大的属性列表中找到Colors
属性要容易得多有。此外,它是可重用的,所以如果我需要执行重置值这样的操作,那么在不重复代码的情况下这样做很容易。
ObservableCollection<SolidColorBrush> Colors
{
get
{
if (_colors == null)
LoadColors();
return _colors;
}
set { ... }
}
void LoadColors()
{
// Initialization logic here
}
您还可以使用绑定的FallbackValue在XAML中设置默认值,但是这通常只有在评估绑定时绑定的DataContext
不存在时才有意义
<!-- You may have to look up the exact syntax for Brushes.Red -->
<ListBox SelectedItem="{Binding SelectedColor, FallbackValue=Red}" />
最后但并非最不重要的是,您始终可以使用代码隐藏视图来执行特定于视图的逻辑,就像您的示例一样。例如,
void ComboBox_Loaded(object obj, EventArgs e)
{
if (MyComboBox.SelectedIndex == -1)
MyComboBox.SelectedIndex = 2;
}
答案 1 :(得分:1)
我相信您的错误在于您的实施。拥有MVVM的原因是要“分离关注点”。这使得您的视图只是一个实现,可以在需要时进行切换或更新。一旦你开始在你的视图中放入属于应用程序逻辑的东西,你就会走上维护头痛的道路,然后意大利面条代码可以很快发生。
有些人说,“不要在你的视图中放任何代码”,我同意99%的时间。我说“不要在你的视图中放置任何域/应用程序/业务逻辑。”
每当你试图将一些代码放入你的视图中时问问自己“如果我从WPF切换到另一个框架,我的应用程序是否仍然有效?”如果答案为否,则修改您的ViewModel以合并您尝试放在视图中的内容。
答案 2 :(得分:1)
首先阅读Jose如果你他的问题的回答是“是”,请回答
<Window x:Class="icube.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<ListBox Name="myLB" Margin="0,0,445,291"
SelectedItem="{Binding mySelectedItem, UpdateSourceTrigger=PropertyChanged}"
SelectedIndex="{Binding mySelectedIndex,Mode=OneTime}" >
<ListBox.ItemTemplate>
<!-- or what ever yourTemplate will be-->
<DataTemplate DataType="{x:Type SolidColorBrush}">
<Rectangle Width="20" Height="20" Fill="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
using System.Windows;
using System.Windows.Media;
using System.Collections.ObjectModel;
namespace icube
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var obcoll = new ObservableCollection<SolidColorBrush>();
obcoll.Add(Brushes.Red);
obcoll.Add(Brushes.Green);
obcoll.Add(Brushes.Yellow);
obcoll.Add(Brushes.Blue);
obcoll.Add(Brushes.Orange);
myLB.ItemsSource = obcoll;
DataContext = new myClass();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//importent if you want to see your selected Element
myLB.ScrollIntoView(myLB.SelectedItem);
}
}
}
public class myClass
{
private SolidColorBrush _mySelectedItem = new SolidColorBrush();
public SolidColorBrush mySelectedItem
{
get { return _mySelectedItem; }
set { _mySelectedItem = value; }
}
public int mySelectedIndex
{
get { return 4; }
}
}
您可以看到SelectedItem
设置的默认SelectedIndex
由OneTime
模式限制为mySelectedIndex
。我还在这里展示了如何让它进入IntoView
我将如何帮助某人。
答案 3 :(得分:0)
通常在MVVM中,应将ObBableCollection的SolidBrushColor定义为ViewModal中的属性。并且此属性应绑定到ListBox。现在,要设置默认值,您可以在ViewModal的构造函数
中使用它答案 4 :(得分:0)
如果绑定到SelectedItem的属性被声明为依赖项属性,那么您可以将依赖项属性的默认值设置为您想要的任何值。
public static readonly DependencyProperty SelectedColorProperty
= DependencyProperty.Register("SelectedColor", typeof(SolidBrushColor ),
typeof(<yourviewmodel>),
new UIPropertyMetadata(GetDefaultColor()));
Where GetDefaultColor() is a static method in your ViewModel,
which will return the required color from your ObservableCollection .