使用MVVM在Silverlight中处理视图状态
我很想知道你们这些人是如何使用MVVM模式处理Silverlight应用程序中的视图状态的。 假设我有一个简单的搜索掩码,可以异步调用Web服务。 在搜索过程中,我想相应地更改gui: -禁用搜索按钮 -启用取消按钮 -等 使用wpf,我可以创建一个datatrigger,它绑定到viewmodel中的某些属性,然后对gui进行更改。 既然我在Silverlight中没有datatrigger,那么与datatrigger类似的最明智的实现方法是什么(如果可能的话,在一个地方使用简洁的代码)使用MVVM在Silverlight中处理视图状态,silverlight,mvvm,Silverlight,Mvvm,我很想知道你们这些人是如何使用MVVM模式处理Silverlight应用程序中的视图状态的。 假设我有一个简单的搜索掩码,可以异步调用Web服务。 在搜索过程中,我想相应地更改gui: -禁用搜索按钮 -启用取消按钮 -等 使用wpf,我可以创建一个datatrigger,它绑定到viewmodel中的某些属性,然后对gui进行更改。 既然我在Silverlight中没有datatrigger,那么与datatrigger类似的最明智的实现方法是什么(如果可能的话,在一个地方使用简洁的代码) (
()我的标准方法是从视图模型(通常是枚举)中公开“ViewState”属性。然后,视图绑定到属性,并使用visualstatemanager根据枚举切换到适当的可视状态 来自的DataStateSwitchBehavior是如何切换到可视状态的一个很好的示例 编辑以回应评论 首先,在处理VisualState时使用Blend(不应该强迫任何人手工编写那么多XAML)。我相信它甚至出现在所有(大多数?)MSDN订阅上 使用可视状态始于
您通常会将其添加到layoutroot
可视状态管理器由一组状态组组成,而状态组又由一组可视状态组成
这些组将相互排斥的状态组织起来,因为您可以在任何时候激活多个视觉状态,但每个组中只能有一个状态。标准模式是使用一个称为“正常”或“默认”的空状态来关闭其他状态。基本上是一个基态
在您的情况下,您将有一个“搜索”视觉状态,其中将包含一个故事板,该故事板将禁用各种按钮,激活繁忙的动画等。最简便的方法是使用Silverlight工具箱中的
总线指示器。当它遮罩应用它的整个区域时,所有按钮都会自动禁用
对于取消按钮,您必须编辑BusyIndicator
的模板,将其直接放置在加载动画旁边
然后,您只需将BusyIndicator的IsBusy
属性绑定到ViewModel中相应的属性,该属性在加载之前设置,并在加载完成后重置。我的解决方案与Graeme Bradbury的类似,但我不使用DataStateSwitchBehavior,因为如果我的X控件放在选项卡面板(或类似的东西)中当我在另一个选项卡上时,状态会发生变化,然后我会得到一个异常(“元素”未找到..)。引发异常是因为当我在另一个选项卡上时,我的X控件被卸载,并且找不到需要更新的元素
下面是我的工作:
在我的视图模型中,我有一个属性VisualState,它在状态更改时发送通知消息(我使用):
在我的视图代码中,我订阅了一个通知:
public partial class XControl : UserControl
{
private string visualState = XVisualStates.InitialState;
public XControl()
{
InitializeComponent();
//go to state when view is loaded
Loaded += (s, e) => ChangeState(); //every time a view is loaded go to current state
//change visual state when a notification is received
Messenger.Default.Register<XStateChangedMessage>(this,
state =>
{
visualState = state.CurrentState; //save current state
ChangeState();
});
}
void ChangeState()
{
try
{
VisualStateManager.GoToState(this, visualState, true); //will throw an exception if current view is unloaded
}
catch
{
//NOTE: supress 'element' not found errors if user navigated to another view and state changes
}
}
}
1) 您可以在视图模型中创建类似IsEnabledSearch的属性,并将其绑定到按钮的IsEnabled或Visibility属性(您将需要一个布尔到可见性转换器)。仅仅为此创建新的视觉状态不是很有效,因为您的按钮内部已经有各种视觉状态来支持此行为
2) Jounce mvvm框架有一个非常好的实现来支持ViewModel中的可视化状态 那么,我可以在控件(也在childwindow?)上定义视觉状态,然后使用DataStateSwitchBehavior切换它们吗?例如,一个状态可以是“SearchInProgress”。然后如何使用VSM禁用按钮,使其在控件处于“SearchInProgress”时不可单击?谢谢Graeme。我在一个样本项目中得到了这个结果,看起来这是一条可行的道路。然而,我似乎遇到了这里提到的相同问题:。VSM在子窗口中似乎不起作用。现在,我将把所有内容都放在UserControl中,并在子窗口中引用它。我正在使用您提到的DataStateSwitcher使其成为ViewModel驱动的。
private string visualState = XVisualStates.InitialState;
public string VisualState
{
get
{
return visualState;
}
set
{
visualState = value;
Messenger.Default.Send(new XStateChangedMessage(value));
}
}
public partial class XControl : UserControl
{
private string visualState = XVisualStates.InitialState;
public XControl()
{
InitializeComponent();
//go to state when view is loaded
Loaded += (s, e) => ChangeState(); //every time a view is loaded go to current state
//change visual state when a notification is received
Messenger.Default.Register<XStateChangedMessage>(this,
state =>
{
visualState = state.CurrentState; //save current state
ChangeState();
});
}
void ChangeState()
{
try
{
VisualStateManager.GoToState(this, visualState, true); //will throw an exception if current view is unloaded
}
catch
{
//NOTE: supress 'element' not found errors if user navigated to another view and state changes
}
}
}
public class XStateChangedMessage
{
public string CurrentState { get; private set; }
public XStateChangedMessage (string currentState)
{
CurrentState = currentState;
}
}