C# 如何禁用绑定到当前项目的按钮';当没有当前项目时,s ICOMAND?
假设您有一个按钮,其C# 如何禁用绑定到当前项目的按钮';当没有当前项目时,s ICOMAND?,c#,.net,wpf,binding,mvvm,C#,.net,Wpf,Binding,Mvvm,假设您有一个按钮,其命令属性绑定到某个集合当前项的某个ICommand 当集合为null时,按钮保持启用状态,单击它似乎是不可操作的。我希望按钮保持禁用状态。我想出了以下方法,可以在集合为null时禁用按钮。然而,对于可能在更自然、更简单、更像MVVM的环境中完成的事情来说,这似乎有点太复杂了 因此,问题是:在理想情况下,如果不使用代码隐藏,是否有更简单的方法来保持该按钮处于禁用状态 .xaml: <Button Content="Do something" > <Bu
命令
属性绑定到某个集合当前项的某个ICommand
当集合为null
时,按钮保持启用状态,单击它似乎是不可操作的。我希望按钮保持禁用状态。我想出了以下方法,可以在集合为null时禁用按钮。然而,对于可能在更自然、更简单、更像MVVM的环境中完成的事情来说,这似乎有点太复杂了
因此,问题是:在理想情况下,如果不使用代码隐藏,是否有更简单的方法来保持该按钮处于禁用状态
.xaml:
<Button Content="Do something" >
<Button.Command>
<PriorityBinding>
<Binding Path="Items/DoSomethingCmd" />
<Binding Path="DisabledCmd" />
</PriorityBinding>
</Button.Command>
</Button>
public class ViewModel : NotificationObject
{
ObservableCollection<Foo> _items;
public DelegateCommand DisabledCmd { get; private set; }
public ObservableCollection<Foo> Items {
get { return _items; }
set { _items = value; RaisePropertyChanged("Items"); }
}
public ViewModel()
{
DisabledCmd = new DelegateCommand(DoNothing, CantDoAnything);
}
void DoNothing() { }
bool CantDoAnything()
{
return false;
}
}
.cs:
<Button Content="Do something" >
<Button.Command>
<PriorityBinding>
<Binding Path="Items/DoSomethingCmd" />
<Binding Path="DisabledCmd" />
</PriorityBinding>
</Button.Command>
</Button>
public class ViewModel : NotificationObject
{
ObservableCollection<Foo> _items;
public DelegateCommand DisabledCmd { get; private set; }
public ObservableCollection<Foo> Items {
get { return _items; }
set { _items = value; RaisePropertyChanged("Items"); }
}
public ViewModel()
{
DisabledCmd = new DelegateCommand(DoNothing, CantDoAnything);
}
void DoNothing() { }
bool CantDoAnything()
{
return false;
}
}
公共类视图模型:NotificationObject
{
可观察到的收集项目;
public DelegateCommand DisabledCmd{get;private set;}
公共可观察收集项目{
获取{return\u items;}
设置{u items=value;RaisePropertyChanged(“items”);}
}
公共视图模型()
{
DisabledCmd=新的DelegateCommand(DoNothing,CantDoAnything);
}
void DoNothing(){}
布尔·坎多纳
{
返回false;
}
}
编辑:
几点注意:
DoSomethingCmd.CanExecute
进行操作会有什么帮助,因为在没有当前项目的情况下,没有DoSomethingCmd
可访问禁用的DCMD
?我对提升DoSomethingCmd不感兴趣,因为它不是我想要的。否则我就不会问这个问题了<Button Content="Do something" >
<Button.Command>
<PriorityBinding>
<Binding Path="Items/DoSomethingCmd" />
<Binding Path="DisabledCmd" />
</PriorityBinding>
</Button.Command>
</Button>
public class ViewModel : NotificationObject
{
ObservableCollection<Foo> _items;
public DelegateCommand DisabledCmd { get; private set; }
public ObservableCollection<Foo> Items {
get { return _items; }
set { _items = value; RaisePropertyChanged("Items"); }
}
public ViewModel()
{
DisabledCmd = new DelegateCommand(DoNothing, CantDoAnything);
}
void DoNothing() { }
bool CantDoAnything()
{
return false;
}
}
所以我基本上采用了这个答案作为解决方案:
我相信这正是hbarck所建议的。如果你看一下委托命令,第二个参数是一个func,它可以让你做到这一点,我不太清楚,为什么你要把它弄得这么复杂。 如果您这样做,例如:
DoSomethingCommand = new DelegateCommand(() => SampleAction, () => Items != null);
仅将按钮的Command属性绑定到此命令时,按钮将被禁用,如下所示:
<Button Command={Binding DoSomethingCommand} />
当委托命令中的条件变为false时,该按钮将自动禁用。当条件的结果可能发生变化时,您还应该调用
DoSomethingCommand.RaiseCanceTechChanged()
,按钮的IsEnabled更新会反映当前状态。我使用了RelayCommand,它有一个构造函数,您可以在其中创建canExecute谓词,如果返回false,则绑定按钮将自动禁用
在delegate命令上,您应该重写CantDoAnything()方法来表示启用和禁用逻辑。您只需将绑定绑定到命令即可
查看PresentationFramework.dll中的代码,我看不到任何简单的方法(请参见
按钮库.updateCancecute
)。您可能有幸从按钮
派生出一个类,并重写CommandProperty
的元数据以自己处理更改。但是,您可以轻松避免在viewmodel中使用不执行任何操作的命令代码:创建一个特殊的转换器,将null
命令转换为共享的始终禁用的回退ICommand
。如果您有许多按钮需要这种行为,则可能需要附加属性和样式。您只需将按钮的IsEnabled属性绑定到当前项并使用转换器即可
下面是一个完整的演示:
<Page.Resources>
<Converters:NullToBoolConverter x:Key="NullToBoolConverter"
IsNullValue="False" IsNotNullValue="True" />
</Page.Resources>
<Page.DataContext>
<Samples:NoCurrentItemViewModel/>
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox
IsSynchronizedWithCurrentItem="True" Grid.Row="0"
ItemsSource="{Binding Items}"
DisplayMemberPath="Name"/>
<Button
Grid.Row="1"
Content="Do something"
IsEnabled="{Binding Items/, Converter={StaticResource NullToBoolConverter}}"
Command="{Binding Items/DoSomethingCommand}"/>
<Button Grid.Row="2" Content="Clear" Command="{Binding ClearCommand}"/>
</Grid>
您可以创建一个
触发器
来检查该项(按钮的数据上下文)是否为空,并将按钮的属性设置为false
,类似如下-
<DataTrigger
Binding="{Binding Path=Item}"
Value="{x:Null}">
<Setter Property="Control.IsEnabled" Value="False" />
</DataTrigger>
我现在还不能测试它,但我认为它应该可以工作。我会像akjoshi那样做,只是我会使用普通触发器而不是DataTrigger,我会检查Button.Command是否为null。由于禁用没有命令的按钮总是有意义的(特别是在MVVM中,没有click EventHandler),因此最好将此触发器包含到按钮的默认样式中,以便在整个应用程序的所有按钮上都有此行为。。。我看不出使用虚拟命令的理由。是的,我知道我可以将命令提升一级,但我必须在viewmodel中跟踪当前项。我认为在viewmodel中获得当前项是一个加号@pickles:是的,我使用IsSelected
间接跟踪当前项,但如果不需要,我不想将其作为特定属性,因为WPF UI已经在视图级别执行了。如果没有当前项,如何访问谓词?@Ludo谓词告诉命令是否可以执行,它基本上是第二种方法,例如当命令绑定到按钮时执行。如果集合发生更改,可以调用命令的raisecannexecutechange,或者我认为您也可以使用NotifyPropertyChanged。@Ludo如果您将命令的CanExecute部分编写为在没有项的情况下返回false,那么您的按钮将非常简单。+1年前,我刚刚想出了一种NullToFalseConverter
方法,如我的编辑中所示。这与我建议的有点不同:您是绑定的除了命令
之外,还启用了功能,但您可以编写转换器并使用此转换器绑定命令
。不过,您的方法更简单—直到您需要为其他内容启用IsEnabled
:)您的意思是定义静态资源吗