简体   繁体   English

C#/ MVVM:基于另一个控件的属性启用/禁用按钮

[英]C#/MVVM: Enable/Disable Buttons based on another control's property

Say i have a tab control that displays data of various types, eg EditorTabViewModel , PreviewTabViewModel both inheriting from TabViewModel . 说我有一个选项卡控件,该控件显示各种类型的数据,例如EditorTabViewModelPreviewTabViewModel都从TabViewModel继承。 The implementation is similar to the tutorial on MSDN 实现类似于MSDN上的教程

I want to enable buttons depending on the active tab, whether its an EditorTabViewModel or a PreviewTabViewModel . 我想根据活动选项卡启用按钮,无论其是EditorTabViewModel还是PreviewTabViewModel How can I achieve this? 我该如何实现?

UPDATE 更新

public ICommand EditorCommand
{
    get
    {
        if (_editorCommand == null) {
            _editorCommand = new RelayCommand(() =>
            {
                MessageBox.Show("Editor");
            }, () =>
            {
                var enabled = true;
                var viewSource = CollectionViewSource.GetDefaultView(Tabs);
                viewSource.CurrentChanged += (o, e) =>
                {
                    if (viewSource.CurrentItem is EditorTabViewModel)
                    {
                        enabled = false;
                    }
                };
                return enabled;
            });
        }
        return _editorCommand;
    }
}

UPDATE 2 更新2

public ICommand PreviewCommand
{
    get
    {
        if (_previewCommand == null) {
            _previewCommand = new RelayCommand(() =>
            {
                MessageBox.Show("Preview");
            }, () =>
            {
                var viewSource = CollectionViewSource.GetDefaultView(Tabs);
                var enabled = viewSource.CurrentItem is EditorTabViewModel;
                viewSource.CurrentChanged += (o, e) =>
                {
                    CommandManager.InvalidateRequerySuggested();
                };
                return enabled;
            });
        }
        return _previewCommand;
    }
}

I would suggest that you create an ICommand implementation that constructs on the ICollectionView that contains the 2 tab controls. 我建议您创建一个ICommand实现,该实现在包含2个选项卡控件的ICollectionView上构造。 The command can then react to the CurrentChanged event from the collection view to determine whether or not it should be enabled, and raise a CanExecuteChanged event to indicate a change. 然后,该命令可以从集合视图对CurrentChanged事件做出反应,以确定是否应启用它,并引发CanExecuteChanged事件以指示更改。

class MyCommand : ICommand
{
    private bool _isEnabled = true;

    public MyCommand(MyTopLevelViewModel viewModel)
    {
        var viewSource = CollectionViewSource.GetDefaultView(viewModel.Tabs);
        viewSource.CurrentChanged += (o,e) =>
            {
                _isEnabled = (viewSource.CurrentItem is EditorTabViewModel); //or however you want to decide

                if (this.CanExecuteChanged != null) 
                     this.CanExecuteChanged(this, EventArgs.Empty);

            };
    }

    public void Execute(object parameter) { /*...*/ }

    public bool CanExecute(object parameter) { return _isEnabled; }

    public event EventHandler CanExecuteChanged;
}

Note: you will need to set the IsSyncronizedWithCurrentItem property on the tab control: 注意:您将需要在选项卡控件上设置IsSyncronizedWithCurrentItem属性:

<TabControl IsSynchronizedWithCurrentItem="True" />

I would use a ValueConverter and pass the Active one as the value 我将使用ValueConverter并将Active 1作为值传递

You can convert from anything to anything. 您可以从任何事物转换为任何事物。 Passing in Active form can determine the type, and thus return true/false for binding to the buttons enabled property. 以Active形式传递可以确定类型,并因此返回true / false以绑定到buttons enabled属性。

It may be more in line with MVVM to do 2 Views (data templates). 进行2个视图(数据模板)可能更符合MVVM。 Just do them as generics in the control resources. 只需在控制资源中将它们作为泛型即可。

<TabControl>
<TabControl.Resources>
    <DataTemplate DataType="EditorTabViewModel">
         <Button Content="Enabled for Editor only" IsEnabled=True Command=SomeCommand />
         <Button Content="Enabled for Preview only" IsEnabled=False Command=SomeCommand />
    </DataTemplate/>
    <DataTemplate DataType="PreviewTabViewModel">
        <Button Content="Enabled for Editor only" IsEnabled=False Command=SomeCommand />
        <Button Content="Enabled for Preview only" IsEnabled=True Command=SomeCommand />
    </DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
    <DataTemplate DataType="TabViewModel">
        <TextBlock Text="{Binding SomeValueToShowAsHeader}" />
    </DataTemplate>
</TabControl.ItemTemplate>
</TabControl>

So what happens is all the tabs have the same tab header, because the itemtemplate is explicitly defined. 那么发生的是,所有选项卡都具有相同的选项卡标题,因为itemtemplate是显式定义的。 But because the ContentTemplates are not explicitly defined, when the control looks for a template for the content, it will give it the default template for the domain. 但是,由于未明确定义ContentTemplates,因此当控件为内容查找模板时,它将为该域提供默认模板。 Since we define 2 default templates, one for EditorTabViewModel and one for PreviewTabViewModel, when it comes across one of these, it will assign it to that data template. 因为我们定义了2个默认模板,一个用于EditorTabViewModel,一个用于PreviewTabViewModel,所以当遇到其中之一时,它将把它分配给该数据模板。 This should result in two different displays showing in the tab collection. 这将导致选项卡集合中显示两个不同的显示。 I havent tried it fully with tab viewmodel so let me know if it doesnt work as expected. 我还没有使用tab viewmodel完全尝试过它,所以让我知道它是否不能按预期工作。

Add a readonly property on your window view model that represents the visibility of the tabs: 在窗口视图模型上添加一个只读属性,该属性表示选项卡的可见性:

public bool EditorTabVisible{
    get{
        return GetActiveWorkspace() is EditorTabViewModel;
    }
}

You need to also have an event thet fires when you change the active tab and add this to the event handler: 您还需要在更改活动标签并将其添加到事件处理程序时触发事件thet:

OnPropertyChanged("EditorTabVisible");

Then you can bind the IsEnabled property of the button to this property. 然后,您可以将按钮的IsEnabled属性绑定到此属性。

I don't know if there's a better way to do it, but this works for me. 我不知道是否有更好的方法,但这对我有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM