使用Visual State Manager Silverlight& amp;显示/隐藏视图PRISM

时间:2012-09-02 05:58:23

标签: silverlight prism visualstatemanager

我有一个应用程序,使用radOutlookbar在屏幕上显示不同的数据集(用户,国籍等)。 我已经设法在每个项目中加载所需的视图以显示数据没有问题。

然后,我为每个数据集(用户,国籍等)构建了视图,以显示所显示数据集中每个所选项目(即:用户)的详细信息。

案例: 首先,当我点击它的项目时,我需要显示每个数据集的相应视图。 其次,显示的视图将有一个选项来编辑/添加显示的细节。

我想使用状态库导航来实现这种情况。

所以, 我在ItemsControl中有一个PRISM区域,其中有ItemsPanelTemplate网格来托管加载的视图,基本上我加载了每个数据集的视图。

问题, 如何使用VSM根据所选数据集显示/隐藏相应视图?

问题2: 我是否应该能够在加载的视图中定义另一个嵌套状态,以便为每个视图启用编辑/添加详细信息的方案?

如果有人有任何想法这样做,那么获得一个起始代码将会非常有帮助。 最好的问候

1 个答案:

答案 0 :(得分:0)

可能有其他方案可以访问VSM,但我更喜欢为它创建AttachedProperty。让我解释一下。

这是VisualState管理器

/// <summary>
/// Class will allow to change VisualSate on ViewModel via attached properties
/// </summary>
public static class VisualStateManagerEx
{
    private static PropertyChangedCallback callback = new PropertyChangedCallback(VisualStateChanged);

    /// <summary>
    /// Gets the state of the visual.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns></returns>
    public static string GetVisualState(DependencyObject obj)
    {
        return (string)obj.GetValue(VisualStateProperty);
    }

    /// <summary>
    /// Sets the state of the visual.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <param name="value">The value.</param>
    public static void SetVisualState(DependencyObject obj, string value)
    {
        obj.SetValue(VisualStateProperty, value);
    }

    /// <summary>
    /// DP for 'VisualState'
    /// </summary>
    public static readonly DependencyProperty VisualStateProperty =
        DependencyProperty.RegisterAttached(
            "VisualState",
            typeof(string),
            typeof(VisualStateManagerEx),
            new PropertyMetadata(null, VisualStateManagerEx.callback)
        );

    /// <summary>
    /// Visuals the state changed.
    /// </summary>
    /// <param name="d">The d.</param>
    /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
    public static void VisualStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        //Control changeStateControl = d as Control;
        FrameworkElement changeStateControl = d as FrameworkElement;
        if (changeStateControl == null)
            throw (new Exception("VisualState works only on Controls type"));

        if (Application.Current.Dispatcher.CheckAccess() == false)
        {
            // Wrong thread
            System.Diagnostics.Debug.WriteLine("[VisualStateManagerEx] 'VisualStateChanged' event received on wrong thread -> re-route via Dispatcher");
            Application.Current.Dispatcher.BeginInvoke(
                //() => { VisualStateChanged(d, e); }
                VisualStateManagerEx.callback
                , new object[] { d, e });    //recursive
        }
        else
        {
            if (string.IsNullOrEmpty(e.NewValue.ToString()) == false)
            {
                //VisualStateManager.GoToState(changeStateControl, e.NewValue.ToString(), true);
                VisualStateManager.GoToElementState(changeStateControl, e.NewValue.ToString(), true);
                System.Diagnostics.Debug.WriteLine("[VisualStateManagerEx] Visual state changed to " + e.NewValue.ToString());
            }
        }
    }
}

现在 - 在XAML中,您将它附加到ViewModel,如下所示:

<UserControl
     xmlns:VSManagerEx=clr-namespace:Namespace.namespace;assembly=Assembly01"
     VSManagerEx:VisualStateManagerEx.VisualState="{Binding Path=ViewModelVisualState, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
     ...
     ...

现在,您在XAML中的VSM绑定到ViewModelBase中的ViewModelVisualState属性(或者绑定到DataContext UserControl的任何属性。所以实际上在您使用的ViewModelBase中是这样的:

/// <summary>
/// Base class for all 'view-models'
/// </summary>
[Export(typeof(ViewModelBase))]
public abstract class ViewModelBase : INavigationAware, INotifyPropertyChanged
{
    private SynchronizationContext parentSyncContent;

    #region VisualState
    private string viewModelVisualState = string.Empty;
    /// <summary>
    /// Gets or sets the state of the view model visual.
    /// </summary>
    /// <value>
    /// The state of the view model visual.
    /// </value>
    public virtual string ViewModelVisualState
    {
        get { return viewModelVisualState; }
        set
        {
            viewModelVisualState = value;
            RaisePropertyChanged(this, "ViewModelVisualState");
        }
    }
    #endregion

    /// <summary>
    /// Raises the property changed.
    /// </summary>
    /// <param name="Sender">The sender.</param>
    /// <param name="PropertyName">Name of the property.</param>
    public void RaisePropertyChanged(object Sender, string PropertyName)
    {
        parentSyncContent.Post((state) =>
        {
            if (PropertyChanged != null)
                PropertyChanged(Sender, new PropertyChangedEventArgs(PropertyName));
        }, null);
    }


    ...
    ...

所以 - 在从ViewModelBase继承的任何ViewModel中,可以声明它自己的VMS状态并像这样管理它们:

    [Export(typeof(IViewModel1))
    public ViewModel1 : ViewModelBase, IViewModel1
    {

          private const string VM_STATE_WORKING = "WorkingState";

          internal void StartWorking()
          {
               this.ViewModelVisualState = VM_STATE_WORKING;
    ...
    ...

问题2:否 - 您不需要在任何内容中声明任何其他视图。阅读有关导航的PRISM文档。有很多关于如何创建支持各种表示逻辑的View / ViewModel的例子。

这对你有帮助吗?