1

在 Windows 8 商店应用程序中,如何根据 ViewModel 的属性在 View 中的 UserControls 之间进行更改?

假设我的 ViewModel 有一个看起来像这样的属性:

    class MyViewModel
    {
        public string CurrentStatus
        {
            get { return (string)GetValue(CurrentStatusProperty); }
            set { SetValue(CurrentStatusProperty, value); }
        }

        public static readonly DependencyProperty CurrentStatusProperty =
            DependencyProperty.Register("CurrentStatus", typeof(string), typeof(MyViewModel), new PropertyMetadata("default", CurrentStatusChanged));


        ...
     }

如何根据CurrentStatus 来自 ViewModel 的值使我的 View 更改 UserControl?

对我来说,最直接的解决方案是CurrentStatus在 ViewModel 和 View 中的另一个字符串之间创建绑定,但显然数据绑定只能用于 a DependencyObject(字符串不是)。

编辑: xaml 文件仅包含一个StackPanel我想在其中放置的UserControl,基于 CurrentStatus。所以,如果CurrentStatus"one"我想要StackPanel包含 UserControlOne 等等......

对这个问题有什么想法或好的解决方案吗?

非常感谢!

4

3 回答 3

2

我通常使用 aContentControl并将其设置为ContentTemplate基于 aDataTrigger

我的博客文章Switching between Views/UserControls using MVVM中有一个示例,但这里有一个示例,说明使用您的场景可能会是什么样子:

<DataTemplate x:Key="DefaultTemplate">
     <local:DefaultUserControl />
</DataTemplate> 

<DataTemplate x:Key="ClosedTemplate">
     <local:ClosedUserControl />
 </DataTemplate>

<Style x:Key="MyContentControlStyle" TargetType="{x:Type ContentControl}">
    <Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding CurrentStatus}" Value="Closed">
            <Setter Property="ContentTemplate" Value="{StaticResource ClosedTemplate}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

...

<ContentControl Style="{StaticResource MyContentControlStyle}" />

编辑

显然,WinRT 不支持 DataTriggers,并且已被替换为VisualStateManager。我还没有机会使用它,但是从我读到的内容来看,他们对 WinRT 使用了与 Silverlight 相同的方法(DataTriggers直到 v5 才支持),我对 Silverlight 的解决方案是使用数据模板选择器

我希望这可以为您指明正确的方向:)

于 2013-02-28T15:39:16.747 回答
1

虽然我以前在这种情况下使用过DataTemplateSelectorand IValueConverter- 现在我最喜欢的方法是使用VisualStateManager. 我在这里创建了一个最基本的附加属性,它在 WinRT XAML 工具包中实现附加行为模式- 如下所示:

/// <summary>
/// Defines an attached property that controls the visual state of the element based on the value.
/// </summary>
public static class VisualStateExtensions
{
    #region State
    /// <summary>
    /// State Attached Dependency Property
    /// </summary>
    public static readonly DependencyProperty StateProperty =
        DependencyProperty.RegisterAttached(
            "State",
            typeof(string),
            typeof(VisualStateExtensions),
            new PropertyMetadata(null, OnStateChanged));

    /// <summary>
    /// Gets the State property. This dependency property 
    /// indicates the VisualState that the associated control should be set to.
    /// </summary>
    public static string GetState(DependencyObject d)
    {
        return (string)d.GetValue(StateProperty);
    }

    /// <summary>
    /// Sets the State property. This dependency property 
    /// indicates the VisualState that the associated control should be set to.
    /// </summary>
    public static void SetState(DependencyObject d, string value)
    {
        d.SetValue(StateProperty, value);
    }

    /// <summary>
    /// Handles changes to the State property.
    /// </summary>
    /// <param name="d">
    /// The <see cref="DependencyObject"/> on which
    /// the property has changed value.
    /// </param>
    /// <param name="e">
    /// Event data that is issued by any event that
    /// tracks changes to the effective value of this property.
    /// </param>
    private static void OnStateChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var stateName = (string)e.NewValue;
        var ctrl = (Control)d;
        VisualStateManager.GoToState(ctrl, stateName, true);
    }
    #endregion
}

您应该定义一个枚举样式的类VisualStates,如 Silverlight Toolkit 中列出所有视觉状态的类(因此您没有重复项),例如

internal static class VisualStates
{
    #region GroupCommon
    /// <summary>
    /// Common state group.
    /// </summary>
    public const string GroupCommon = "CommonStates";

    /// <summary>
    /// Normal state of the Common state group.
    /// </summary>
    public const string StateNormal = "Normal";

    /// <summary>
    /// Normal state of the Common state group.
    /// </summary>
    public const string StateReadOnly = "ReadOnly";

    /// <summary>
    /// MouseOver state of the Common state group.
    /// </summary>
    public const string StateMouseOver = "MouseOver";

    /// <summary>
    /// Pressed state of the Common state group.
    /// </summary>
    public const string StatePressed = "Pressed";

    /// <summary>
    /// Disabled state of the Common state group.
    /// </summary>
    public const string StateDisabled = "Disabled";
    #endregion GroupCommon

    #region GroupFocus
    /// <summary>
    /// Focus state group.
    /// </summary>
    public const string GroupFocus = "FocusStates";

    /// <summary>
    /// Unfocused state of the Focus state group.
    /// </summary>
    public const string StateUnfocused = "Unfocused";

    /// <summary>
    /// Focused state of the Focus state group.
    /// </summary>
    public const string StateFocused = "Focused";
    #endregion GroupFocus
}

一旦你有了这些 - 你可以在你的视图模型中拥有一个属性,比如

public string VisualState { get; set; /* Raise PropertyChange event your preferred way here */ }

在你看来说

<Page
    ...
    xmlns:extensions="using:WinRTXamlToolkit.Controls.Extensions"
    extensions:VisualStateExtensions.State="{Binding VisualState}">...

然后,您的视图模型可以轻松地驱动视觉状态的变化,您可以使用 Blend 来定义该状态的外观 - 例如,更改布局中各种元素的可见性或简单的可见性ContentContentTemplate我认为这种方法对设计器工具有最好的支持,因为您可以通过单击按钮在视图之间切换并在 Blend 中更新这些视图。

于 2013-02-28T18:35:07.170 回答
1

不确定我是否完全理解您要执行的操作。你可以发布xaml吗?

如果您想要根据状态以不同方式呈现控件,则使用转换器,您可以根据状态呈现不同的模板:

public class StatusToTemplateConverter : IValueConverter
{
    #region IValueConverter Members


    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch ((string) value)
        {
            case "Status1":
                return Application.Current.Resources["Status1Template"];
            case "Status2":
                return Application.Current.Resources["Status2Template"];

            default:
                return Application.Current.Resources["Status3Template"];
        }
    }


    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }

    #endregion
}

以上假设您在资源文件中定义了模板

如果您只想做一些更简单的事情,例如 Status1 的红色文本或 status2 的绿色文本,您可以拥有一个转换器,将状态转换为颜色并将 FontColor 绑定到状态并使用转换器。

但就像我说的那样,如果没有发布更多代码,我并不是 100% 清楚你想要实现的目标

于 2013-02-28T15:33:34.597 回答