如何使用combox和button实现多重绑定?

时间:2019-01-29 02:03:08

标签: c# wpf mvvm

我正在通过mvvm学习wpf。

我有一个组合框和一个按钮。该按钮最初在应用程序加载时被禁用。

我有两种情况:

  1. 在comboxbox中选择了项目后,应启用该按钮。
  2. 单击按钮后应禁用该按钮。

在这里,相对于第二种情况,我可以使用Converter实现第一种情况,我不知道如何使用按钮和组合框为单个组件实现多重绑定。

 <ComboBox IsEnabled="{Binding IsEnabled}" HorizontalAlignment="Left" Width="113" Height="19.277" Margin="10,1,-228.962,0" Name="cmbboxFinalstatus">
            <ComboBoxItem Content="Finding"></ComboBoxItem>
            <ComboBoxItem Content="No Finding"></ComboBoxItem>
            <ComboBoxItem Content="Skipped"></ComboBoxItem>
            <ComboBoxItem Content="Skipped Not reviewed"></ComboBoxItem>
        </ComboBox>
        <Button Command="{Binding stop}" Margin="90,1,-228.962,0" Width="62" Height="19.277" IsEnabled="{Binding ElementName=cmbboxFinalstatus,  Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}">End Timer</Button>

Converter.Cs:

 public class IndexToBoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if ((int)value >= 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

编辑:停止命令逻辑

ViewModel.cs

stop命令将调用以下逻辑

 public void stopbutton()
        {
            if (checkdata() == false)
            { MessageBox.Show("fill all fields"); }
            else
            {
                stopWatch.Stop();
                TimeSpan ts = stopWatch.Elapsed;
                string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}",
                        ts.Hours, ts.Minutes, ts.Seconds);
                EndTimerArgument = DateTime.Now.ToLongTimeString();
                TotalTimerArgument = elapsedTime;
                IsEnabledSubmit = true;
                IsEnabled = false;
            }
        }

3 个答案:

答案 0 :(得分:1)

祝贺您学习MVVM,这是一项很好的技能。不过,老实说,我在您的代码中发现了一些不良习惯,您可能想考虑早日掌握这些习惯。即使您现在不需要它们,也最好开始正确地做事,因为您会发现自己需要早点而不是迟点。

首先,我建议为您的选项创建一个枚举,并使用数据绑定填充ComboBox。它仅需一点点工作,但可以轻松扩展到其他控件(动态菜单,TabControl等),并在将来需要视图模型控制选择哪些项目时使您能够进行双向绑定。在这种情况下,您将创建以下内容:

[TypeConverter(typeof(EnumDescriptionTypeConverter))]
public enum MyEnum
{
    [Description("Finding")]
    Finding,

    [Description("No Finding")]
    NoFinding,

    [Description("Skipped")]
    Skipped,

    [Description("Skipped Not Reviewed")]
    SkippedNotReviewed
}

EnumDescriptionTypeConverter的源代码可以在here中找到,如果您想支持多种语言,则需要更强大的功能,但是现在就可以使用。

在主视图模型中,您将需要一个用于跟踪当前选定项的属性和一个在按下按钮时调用的命令处理程序;处理程序只需将属性设置为null:

public class MainViewModel : ViewModelBase
{
    private MyEnum? _CurrentItem;
    public MyEnum? CurrentItem
    {
        get { return this._CurrentItem; }
        set
        {
            if (this._CurrentItem != value)
            {
                this._CurrentItem = value;
                RaisePropertyChanged(() => this.CurrentItem);
            }
        }
    }

    private ICommand _StopCommand;
    public ICommand StopCommand => this._StopCommand ?? (this._StopCommand = new RelayCommand(OnStop));

    private void OnStop()
    {
        // do something with selection here
        this.CurrentItem = null;
    }

您的窗口需要自动创建一个所有Enum值的列表,以便您的ComboBox可以绑定到该列表,这样做意味着您以后可以在Enum中添加其他选项,并且GUI会自动更新:

    <ObjectDataProvider x:Key="MyEnums" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="vm:MyEnum" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>

现在最后是您的ComboBox和Button的XAML。 ComboBox只需要将ItemsSource绑定到上面的ObjectDataProvider,还需要绑定到视图模型中的CurrentItem属性。控制Button的IsEnabled状态的最简单方法是在视图模型中添加一个您自己维护的属性,并将IsEnabled绑定到该属性。那肯定是我自己的喜好,因为它可以进行单元测试等,但是您也可以使用转换器或简单地添加一个数据触发器,这就是我在这里为了展示一个示例所要做的事情:

    <ComboBox ItemsSource="{Binding Source={StaticResource MyEnums}}" SelectedItem="{Binding CurrentItem}" HorizontalAlignment="Left" VerticalAlignment="Top" />
    <Button Content="Press Me" Command="{Binding StopCommand}" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Button.Style>
            <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
                <Setter Property="IsEnabled" Value="True" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding CurrentItem}" Value="{x:Null}">
                        <Setter Property="IsEnabled" Value="False" />
                    </DataTrigger>
                </Style.Triggers>   
            </Style>
        </Button.Style>
    </Button>

请记住,应避免使用转换器,因为它们实际上是一种视图逻辑,即使它们没有专门引用视图逻辑代码也是如此。我并不是说不要使用它们……当我需要直接操纵GUI对象或在有助于XAML和/或视图模型更加简洁易读的地方使用它们时,我当然会自己使用它们。 。只是尝试抵制诱惑,使它们成为一切的首选解决方案,因为在大多数情况下,根本不需要它们。

答案 1 :(得分:0)

我认为您不需要multiBinding。单击按钮时,将ComboBox的SelectedIndex设置为-1,然后调用Command stop.RaiseCanExecuteEvent()。

答案 2 :(得分:0)

好吧,您想要的是单击按钮时将其禁用,而在选择组合框的某个元素时将其重新激活。

这很容易做到。您要做的第一件事是给按钮起一个名字,在这种情况下,我们将其命名为EndTimer,然后您使用按钮的Click事件,当您单击按钮时,按钮的{ {1}}属性从IsEnabled(默认值)更改为true

false具有Combobox事件,我们使用它将SelectionChanged按钮的IsEnabled属性再次更改为EndTimer

XML:

true

Cs:

<ComboBox HorizontalAlignment="Left" Width="113" Height="19.277" Margin="10,1,-228.962,0" Name="cmbboxFinalstatus" SelectedItem="cmbboxFinalstatus_SelectionChanged">
    <ComboBoxItem Content="Finding"></ComboBoxItem>
    <ComboBoxItem Content="No Finding"></ComboBoxItem>
    <ComboBoxItem Content="Skipped"></ComboBoxItem>
    <ComboBoxItem Content="Skipped Not reviewed"></ComboBoxItem>
</ComboBox>
<Button Name="EndTimer" Content="End Timer" Margin="90,1,-228.962,0" Width="62" Height="19.277" Click="EndTimer_Click"/>