在我的应用程序中,我有很多网格,所以我正在创建一个用户控件,其中包含我们将用于网格的所有可能按钮(添加,删除,插入,上移,下移等) 。我使用依赖项属性来设置按钮的可见性和状态(启用或禁用),并为点击事件使用路由事件。
我在我的项目中使用Caliburn.Micro,因此我使用Message.Attach指定多个事件及其附加的操作。就他们自己而言,这些工作没有问题。
我遇到的问题是当动作具有Can *属性时。例如,我有Add和Remove方法以及CanAdd和CanRemove属性来设置它们的状态。如果CanAdd或CanRemove为false(另一个为true),则两个按钮都被禁用(可能是整个用户控件被禁用)。
我可以通过使用不符合Caliburn.Micro命名状态的属性(例如CanAddRecord和CanRemoveRecord而不是CanAdd和CanRemove)来解决此问题,因此它不会自动使用它们然后在每个依赖项属性中设置绑定。我宁愿不这样做,但如果它只是唯一的方式。
我创建了一个简单的示例项目来展示这一点。该项目是在VS 2015中编写的,使用的是.NET 4.5.2。我正在使用Caliburn.Micro v3.1.0。
应用程序有一个主窗口,顶部有用户控件。用户控件具有“添加”和“删除”按钮。在用户控件下是一个显示计数的标签。 “添加”按钮增加计数,“删除”按钮减少计数。始终启用“添加”按钮。仅当计数大于0时才会启用“删除”按钮(因此您无法将计数设置为负数)。计数从1开始,因此两个按钮都启动。如果单击“添加”,则两个按钮都保持启用状如果单击“删除”直到计数变为0,则两个按钮最终都会被禁用。
这是设计原因,因为消息附加到用户控件而不是特定按钮?有办法解决这个问题吗?
我最初尝试将Message.Attach语句放在用户控件中,但是当单击按钮时,它似乎想要绑定到用户控件内部的Add和Remove方法。
的App.xaml
<Application
x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:AppBootstrapper x:Key="Bootstrapper" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
AppBootStrapper.cs
using System.Windows;
using Caliburn.Micro;
namespace WpfApplication1
{
public class AppBootstrapper : BootstrapperBase
{
public AppBootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<MainViewModel>();
}
}
}
GridButtonBar.xaml
<UserControl
x:Class="WpfApplication1.GridButtonBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="40" d:DesignWidth="230">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
x:Name="AddButton"
Content="Add"
Grid.Column="0"
Margin="3"
IsEnabled="{Binding AddButtonIsEnabled}"
Click="Add_OnClick" />
<Button
x:Name="RemoveButton"
Content="Remove"
Grid.Column="1"
Margin="3"
IsEnabled="{Binding RemoveButtonIsEnabled}"
Click="Remove_OnClick" />
</Grid>
</UserControl>
GridButtonBar.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class GridButtonBar : UserControl
{
public static readonly DependencyProperty AddButtonIsEnabledProperty =
DependencyProperty.Register(nameof(AddButtonIsEnabled), typeof(bool), typeof(GridButtonBar),
new UIPropertyMetadata(true));
public static readonly DependencyProperty RemoveButtonIsEnabledProperty =
DependencyProperty.Register(nameof(RemoveButtonIsEnabled), typeof(bool), typeof(GridButtonBar),
new UIPropertyMetadata(true));
public static readonly RoutedEvent AddButtonClickedEvent = EventManager.RegisterRoutedEvent("AddButtonClicked",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(GridButtonBar));
public static readonly RoutedEvent RemoveButtonClickedEvent =
EventManager.RegisterRoutedEvent("RemoveButtonClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler),
typeof(GridButtonBar));
public GridButtonBar()
{
InitializeComponent();
}
public bool AddButtonIsEnabled
{
get { return (bool) GetValue(AddButtonIsEnabledProperty); }
set { SetValue(AddButtonIsEnabledProperty, value); }
}
public bool RemoveButtonIsEnabled
{
get { return (bool) GetValue(RemoveButtonIsEnabledProperty); }
set { SetValue(RemoveButtonIsEnabledProperty, value); }
}
public event RoutedEventHandler AddButtonClicked
{
add { AddHandler(AddButtonClickedEvent, value); }
remove { RemoveHandler(AddButtonClickedEvent, value); }
}
public event RoutedEventHandler RemoveButtonClicked
{
add { AddHandler(RemoveButtonClickedEvent, value); }
remove { RemoveHandler(RemoveButtonClickedEvent, value); }
}
private void Add_OnClick(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(AddButtonClickedEvent));
}
private void Remove_OnClick(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(RemoveButtonClickedEvent));
}
}
}
MainView.xaml
<Window
x:Class="WpfApplication1.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
Title="{Binding WindowTitle}"
WindowStyle="SingleBorderWindow"
ResizeMode="NoResize"
Height="140" Width="250">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<local:GridButtonBar
Grid.Row="0"
cal:Message.Attach="[Event AddButtonClicked] = [Action Add];[Event RemoveButtonClicked] = [Action Remove]" />
<Label
Grid.Row="1"
Margin="5"
BorderBrush="Black"
BorderThickness="1"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Content="{Binding Count}" />
</Grid>
</Window>
MainViewModel.cs
using Caliburn.Micro;
namespace WpfApplication1
{
public class MainViewModel : PropertyChangedBase
{
private const string WindowTitleDefault = "Caliburn Micro Test";
private int _count = 1;
private string _windowTitle = WindowTitleDefault;
public string WindowTitle
{
get { return _windowTitle; }
set
{
_windowTitle = value;
NotifyOfPropertyChange(() => WindowTitle);
}
}
public int Count
{
get { return _count; }
set
{
_count = value;
NotifyOfPropertyChange(() => Count);
}
}
public bool CanAdd => true;
public bool CanRemove => Count > 0;
public void Add()
{
Count++;
}
public void Remove()
{
Count--;
NotifyOfPropertyChange(() => CanRemove);
}
}
}