银光 MVVM - 按钮启用和可见性属性

6
所以我正在开发一个MVVM应用程序,并开始为功能添加一些闪光和磨光效果。
在我的页面左侧,我正在显示这些值:
DateActivated
DateCompleted
DateTrialClosed
DateAccountingClosed

如果在数据库中有日期,我会在文本块中显示它。如果没有,我会向用户显示一个按钮,上面写着“激活工作订单”、“完成工作订单”等等...
我将这8个控件(4个文本块和4个按钮)的可见性绑定到我的ViewModel中类型为Windows.Visibility的唯一属性。在我的SelectedWorkOrder的setter中,我评估SelectedWorkOrder.DateActivated属性的当前值(例如),并相应地设置可见性属性。对我来说,这有点啰嗦,但它按预期工作。
我的下一步是禁用第一个按钮后的任何可见按钮(逻辑很简单...在点击按钮1之前不能点击按钮2。在点击按钮1和2之前不能点击按钮3)。我不确定实现这一点的最佳方法是什么。顺便说一下,我已经在我的项目中有一个boolToVisibility值转换器...我只是不确定实现它是否与我现在所做的有所不同(请参见下面的VM代码)。
目前,我的XAML如下:
<TextBlock Text="Proposed:" />
<TextBlock Text="Activated:" />
<TextBlock Text="Eng Completed:" />
<TextBlock Text="Trial Close:" />
<TextBlock Text="Accounting Close:" />
<TextBlock Text="{Binding SelectedWorkOrder.EstimatedStartDate}" Visibility="{Binding ProposedVisibility}" />
<TextBlock Text="{Binding SelectedWorkOrder.DateActivated}" Visibility="{Binding ActivatedTextBlockVisibility}" />
<Button Content="Activate Work Order" Visibility="{Binding ActivatedButtonVisibility}" />
<TextBlock Text="{Binding SelectedWorkOrder.DateCompleted}" Visibility="{Binding EngineeringCompletedTextBlockVisibility}" />
<Button Content="Work Order Eng Complete" Visibility="{Binding EngineeringCompletedButtonVisibility}" />
<TextBlock Text="{Binding SelectedWorkOrder.DateClosed}" Visibility="{Binding TrialCloseTextBlockVisibility}" />
<Button Content="Close Work Order (Trial)" Visibility="{Binding TrialCloseButtonVisibility}" />
<TextBlock Text="{Binding SelectedWorkOrder.DateClosed}" Visibility="{Binding AccountingCloseTextBlockVisibility}" />
<Button Content="Close Work Order (Actual)" Visibility="{Binding AccountingCloseButtonVisibility}" />

虚拟机代码:

if (_SelectedWorkOrder.DateActivated.ToShortDateString() != "1/1/0001")
{
    ActivatedTextBlockVisibility = Visibility.Visible;
    ActivatedButtonVisibility = Visibility.Collapsed;
}
else
{
    ActivatedTextBlockVisibility = Visibility.Collapsed;
    ActivatedButtonVisibility = Visibility.Visible;
}

当我实例化一个新的DateTime时,如果Is DBNull.Value = true,我的数据库访问层中的日期将被设置为1/1/0001


2
我强烈建议使用DateTime.MinValue,而不是将DateActivated转换为字符串并将其与"1/1/0001"进行比较。 - Dan J
2个回答

2

今晚我遇到了类似的问题 :-)

我认为做这种事情的最好方法是将可见性绑定到ViewModel中的属性。

您可以为每个变量使用转换器(因此当预期时,您可以返回Visibility.Collapsed或Visibility.Visible)。

您可以为每个按钮使用“CanExecute”方法,以便在按下button1之前无法执行button2(例如使用布尔变量)。您必须使用命令来实现此功能,以便与每个按钮关联的代码将位于ModelView中。

如果需要示例,我可以从周一的工作中粘贴它们 :-)。

通过直接在此处编写代码的一个小例子(我这里没有安装silverlight)。

您的视图应该像这样:

<Button Content="Activate Work Order" Command="{Binding ActivateWorkOrderCommand}" />

您可以搜索MVVM中如何使用命令的示例,这里有一个简单的示例

对于转换器,如果您仍然喜欢隐藏和显示按钮,则应声明一个实现IValueConverter接口的新类:

public class UniversalConverter : IValueConverter {
      public object Convert(object value, Type targetType, 
                         object parameter, CultureInfo culture) {
if(_SelectedWorkOrder.DateActivated.ToShortDateString() != "1/1/0001")
{
          return Visibility.Collapsed;
      }
else { return Visibility.Visible;
}

所以你的视图也应该链接转换器:
<Button Content="Activate Work Order" Visibility="{Binding DateActivated, Converter={StaticResource DateConverter}}" />

希望这能帮到你;-)

好的,例子会很棒。我的ViewModelBase已经实现了iCommand和iNotify(记不清哪个接口有CanExecute),所以这应该不难。我只是不确定如何触发它,因为我从未使用过这个方法。谢谢伙计。 - Scott Silvi
我会搜索一些例子,我现在是放松时间 :-P - zapico
谢谢,我会看一下。我对使用命令很熟悉,而且我已经有一个转换器了。我只是不确定它是否比我现在的代码更简洁,尽管我可以将其抽象为自己的类,以便更好地重用代码。 - Scott Silvi

1

这里有一个小例子。

这是一个简单的示例,当您点击一个按钮时登录,当您点击另一个按钮时注销。

以下是命令:

        #region Login Command

        public ViewModelCommand LoginCommand { get; set; }

        public void Login(object parameter)
        {
            Code.Session.Session.Sesion.Logged = true;
        }

        public bool CanLogin(object parameter)
        {
            return !Code.Session.Session.Sesion.Logged;
        }
        #endregion



        #region Logout Command

        public ViewModelCommand LogoutCommand { get; set; }

        public void Logout(object parameter)
        {
            Code.Session.Session.Sesion.Logged = false;
        }

        public bool CanLogout(object parameter)
        {
            return Code.Session.Session.Sesion.Logged;
        }
        #endregion

为了绑定可见性和其他数据,请声明一个属性: public const string SesionPropertyName = "Sesion";
private Model.Sesion _Sesion = Code.Session.Session.Sesion;

public Model.Sesion Sesion
{
    get
    {
        return _Sesion;
    }

    set
    {
        if (_Sesion == value)
        {
            return;
        }

        var oldValue = _Sesion;
        _Sesion = value;

        // Update bindings, no broadcast
        RaisePropertyChanged(SesionPropertyName);
    }
}

在这个例子中,我们需要在用户登录时隐藏按钮,在用户未登录时显示它,因此我编写了这个转换器:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if ((bool)value)
            {
                return Visibility.Collapsed;
            }
            else
            {
                return Visibility.Visible;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if ((Visibility)value == Visibility.Visible)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

最后,我们需要将它绑定到视图上,注意转换器:
<Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="221*" />
                <ColumnDefinition Width="140*" />
            </Grid.ColumnDefinitions>
            <Button Content="Logout" Grid.Column="1" HorizontalAlignment="Stretch" Margin="2" Name="bLogout" VerticalAlignment="Stretch" Command="{Binding LogoutCommand}" />
            <TextBlock Height="Auto" HorizontalAlignment="Stretch" Margin="2" Name="txtBlockUser" Text="{Binding Sesion.UserName}" VerticalAlignment="Center" TextWrapping="NoWrap" TextAlignment="Center" />
            <Grid Grid.ColumnSpan="2" >
                    <Button Content="Login" Command="{Binding LoginCommand}" Visibility="{Binding Sesion.Logged, Converter={StaticResource InverseBooleanVisibilityConverter}}"></Button>
            </Grid>
        </Grid>

我已经做到了这一步 - 我不知道该如何处理禁用/启用属性。 - Scott Silvi
如果您有按钮,它们将会通过canexecute方法启用/禁用。当您认为它可以更改时(例如,在属性设置时),您必须调用OnCanExecuted方法:this.LoginCommand.OnCanExecuteChanged(); - zapico

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接